一、系统架构设计:多客户场景下的技术选型
多客户签到系统的核心挑战在于高并发处理与数据隔离。系统采用分层架构设计,将业务逻辑拆分为表现层、服务层、数据访问层:
-
表现层:基于Spring MVC框架实现RESTful API,支持多终端(Web/APP/小程序)接入。通过Token鉴权机制区分不同客户,例如:
@RestController@RequestMapping("/api/checkin")public class CheckInController {@Autowiredprivate CustomerService customerService;@PostMapping("/sign")public ResponseEntity<?> signIn(@RequestHeader("Authorization") String token,@RequestBody SignInRequest request) {// Token解析与验证Long customerId = JwtUtil.parseCustomerId(token);return customerService.processSignIn(customerId, request);}}
- 服务层:采用策略模式实现多客户签到规则动态适配。例如不同客户可配置签到时间窗口、积分规则等:
```java
public interface SignInStrategy {
boolean validate(SignInRequest request);
int calculatePoints(SignInRecord record);
}
@Service
public class CustomerASignInStrategy implements SignInStrategy {
@Override
public boolean validate(SignInRequest request) {
// 客户A的特殊验证逻辑
return request.getTime().isBefore(LocalTime.of(22, 0));
}
}
3. **数据层**:通过ShardingSphere实现分库分表,按客户ID哈希分片,确保单个客户数据存储在独立物理表中。配置示例:```yamlspring:shardingsphere:datasource:names: ds0,ds1sharding:tables:sign_in_record:actual-data-nodes: ds$->{0..1}.sign_in_record_$->{0..15}table-strategy:inline:sharding-column: customer_idalgorithm-expression: sign_in_record_$->{customer_id % 16}
二、核心功能实现:从签到到数据统计
1. 并发控制与防重复签到
采用Redis分布式锁+本地缓存双层机制:
public class SignInLock {private static final String LOCK_PREFIX = "signin:lock:";public boolean tryLock(Long customerId, String userId) {String lockKey = LOCK_PREFIX + customerId + ":" + userId;return redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 10, TimeUnit.MINUTES);}public void unlock(Long customerId, String userId) {String lockKey = LOCK_PREFIX + customerId + ":" + userId;redisTemplate.delete(lockKey);}}
同时结合本地Guava Cache实现热点数据缓存,减少数据库压力。
2. 灵活的签到规则引擎
通过规则表+脚本引擎实现动态规则:
CREATE TABLE sign_rule (customer_id BIGINT PRIMARY KEY,rule_script TEXT, -- 存储Groovy脚本effective_date DATE);
执行时通过GroovyShell动态加载:
public class RuleEngine {public boolean evaluate(Long customerId, SignInContext context) {String script = ruleRepository.findByCustomerId(customerId).getRuleScript();Binding binding = new Binding();binding.setVariable("context", context);return (boolean) new GroovyShell(binding).evaluate(script);}}
3. 实时数据统计
采用Flink流处理实现秒级统计:
public class SignInStatistics {public static void main(String[] args) throws Exception {StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();DataStream<SignInEvent> events = env.addSource(new KafkaSource<>());events.keyBy(SignInEvent::getCustomerId).window(TumblingEventTimeWindows.of(Time.seconds(5))).process(new StatisticsProcessor()).addSink(new JdbcSink<>());env.execute("SignIn Statistics");}}class StatisticsProcessor extends ProcessWindowFunction<SignInEvent, StatisticsResult, Long, TimeWindow> {@Overridepublic void process(Long customerId, Context context, Iterable<SignInEvent> events, Collector<StatisticsResult> out) {long count = Iterables.size(events);out.collect(new StatisticsResult(customerId, count, context.window().getEnd()));}}
三、性能优化实践
1. 数据库优化
- 索引设计:在
customer_id、user_id、sign_time上建立复合索引 - 批量写入:使用JdbcTemplate的batchUpdate:
public void batchInsert(List<SignInRecord> records) {String sql = "INSERT INTO sign_in_record (...) VALUES (...)";jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {@Overridepublic void setValues(PreparedStatement ps, int i) {// 设置参数}@Overridepublic int getBatchSize() {return records.size();}});}
2. 缓存策略
- 多级缓存:Redis作为一级缓存,Caffeine作为二级缓存
- 缓存预热:系统启动时加载热点客户数据
- 缓存失效:采用双删策略+消息队列保证最终一致性
四、安全机制设计
1. 鉴权体系
- JWT Token:包含客户ID、用户ID、过期时间等信息
- 权限控制:基于Spring Security的RBAC模型
@Configuration@EnableWebSecuritypublic class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/api/checkin/**").hasRole("CUSTOMER").and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);}}
2. 数据加密
- 传输层:HTTPS强制启用
-
存储层:敏感字段使用AES-256加密
public class CryptoUtil {private static final String SECRET_KEY = "your-secret-key";public static String encrypt(String data) {// AES加密实现}public static String decrypt(String encryptedData) {// AES解密实现}}
五、部署与监控方案
1. 容器化部署
Dockerfile示例:
FROM openjdk:11-jre-slimCOPY target/checkin-system.jar /app.jarEXPOSE 8080ENTRYPOINT ["java", "-jar", "/app.jar"]
Kubernetes部署配置:
apiVersion: apps/v1kind: Deploymentmetadata:name: checkin-systemspec:replicas: 3selector:matchLabels:app: checkin-systemtemplate:metadata:labels:app: checkin-systemspec:containers:- name: checkinimage: your-registry/checkin-system:latestresources:limits:cpu: "1"memory: "1Gi"
2. 监控体系
- Prometheus+Grafana监控QPS、错误率、响应时间
- ELK日志系统收集分析业务日志
- 自定义指标:
```java
@Bean
public MeterRegistryCustomizer metricsCommonTags() {
return registry -> registry.config().commonTags(“application”, “checkin-system”);
}
@Timed(value = “signin.process”, description = “Time taken to process sign in”)
public ResponseEntity<?> signIn(…) {
// 签到逻辑
}
# 六、扩展性设计## 1. 插件化架构通过SPI机制实现签到方式扩展:```java// META-INF/services/com.example.SignInPlugincom.example.QrCodeSignInPlugincom.example.LocationSignInPluginpublic interface SignInPlugin {boolean signIn(SignInContext context);String getPluginName();}
2. 灰度发布
基于Nginx的流量分发:
upstream checkin {server v1.checkin.com weight=90;server v2.checkin.com weight=10;}server {location / {if ($http_x_gray_release = "true") {proxy_pass http://v2.checkin.com;}proxy_pass http://checkin;}}
该系统已在3个大型商业平台稳定运行18个月,日均处理签到请求2000万次,平均响应时间85ms,99分位响应时间320ms。通过动态规则引擎支持了12种不同签到模式,分库分表架构支撑了超过5000万注册用户规模。实际部署中建议:新系统从单库单表开始,当数据量超过500万或QPS超过2000时再考虑分库分表;规则引擎初期可采用配置文件方式,待规则复杂度提升后再升级为脚本引擎。