
事件驱动架构设计
事件驱动架构(EDA)的核心是解耦生产者和消费者,通过事件总线传递消息。对于积分奖励系统,用户行为(如登录、下单)作为事件触发,积分服务作为消费者处理事件。
关键组件包括:
- 事件生产者:用户服务、订单服务等业务模块
- 事件总线:消息队列(如Kafka/RabbitMQ)
- 事件消费者:积分计算服务
- 存储层:MySQL数据库
Java实现事件生产者
使用Spring Boot框架创建事件发布者:
// 用户行为事件定义
public class UserBehaviorEvent {
private Long userId;
private String behaviorType; // LOGIN, PURCHASE等
private LocalDateTime eventTime;
// getters/setters
}
// 事件发布服务
@Service
public class EventPublisher {
@Autowired
private ApplicationEventPublisher eventPublisher;
public void publishUserBehavior(Long userId, String behaviorType) {
UserBehaviorEvent event = new UserBehaviorEvent();
event.setUserId(userId);
event.setBehaviorType(behaviorType);
event.setEventTime(LocalDateTime.now());
eventPublisher.publishEvent(event);
}
}
消息队列集成
使用Spring Cloud Stream连接RabbitMQ:
# application.yml
spring:
cloud:
stream:
bindings:
userBehavior-out-0:
destination: user.behavior
content-type: application/json
rabbit:
bindings:
userBehavior-out-0:
producer:
routing-key-expression: "'user.behavior'"
@EnableBinding(Source.class)
public class MessageProducer {
@Autowired
private Source source;
public void sendEvent(UserBehaviorEvent event) {
source.output().send(MessageBuilder.withPayload(event).build());
}
}
积分服务实现
MySQL表结构设计:
CREATE TABLE user_points (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT NOT NULL,
points INT DEFAULT 0,
version INT DEFAULT 0, -- 乐观锁
UNIQUE KEY (user_id)
);
CREATE TABLE points_transaction (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT NOT NULL,
points_change INT NOT NULL,
behavior_type VARCHAR(50),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
积分计算逻辑:
@Service
public class PointsService {
@Autowired
private PointsRepository pointsRepository;
@Transactional
public void addPoints(Long userId, int points, String behaviorType) {
pointsRepository.findByUserId(userId).ifPresentOrElse(
userPoints -> {
userPoints.setPoints(userPoints.getPoints() + points);
pointsRepository.save(userPoints);
},
() -> {
UserPoints newPoints = new UserPoints();
newPoints.setUserId(userId);
newPoints.setPoints(points);
pointsRepository.save(newPoints);
}
);
// 记录积分变动历史
PointsTransaction transaction = new PointsTransaction();
transaction.setUserId(userId);
transaction.setPointsChange(points);
transaction.setBehaviorType(behaviorType);
transactionRepository.save(transaction);
}
}
事件消费者实现
使用@StreamListener处理事件:
@Service
@EnableBinding(Sink.class)
public class PointsCalculator {
@Autowired
private PointsService pointsService;
@StreamListener(Sink.INPUT)
public void handleUserBehavior(UserBehaviorEvent event) {
int points = switch(event.getBehaviorType()) {
case "LOGIN" -> 10;
case "PURCHASE" -> 100;
default -> 0;
};
if(points > 0) {
pointsService.addPoints(event.getUserId(), points, event.getBehaviorType());
}
}
}
事务一致性保证
采用最终一致性模式:
- 使用本地事务表记录事件状态
- 定时任务补偿未处理事件
- 幂等设计防止重复处理
补偿任务示例:
@Scheduled(fixedRate = 60000)
public void compensateFailedEvents() {
eventRepository.findByStatus("PENDING").forEach(event -> {
try {
pointsCalculator.handleUserBehavior(event);
event.setStatus("PROCESSED");
} catch (Exception e) {
event.setRetryCount(event.getRetryCount() + 1);
}
eventRepository.save(event);
});
}
性能优化建议
- 批量处理:对高频事件(如浏览)采用批量积分计算
- 缓存层:使用Redis缓存用户当前积分
- 读写分离:将积分查询路由到只读副本
- 分表策略:按用户ID哈希分片存储积分记录
完整实现需根据具体业务场景调整积分规则和事件类型,事件驱动架构能有效支持系统的水平扩展和模块解耦。
451

被折叠的 条评论
为什么被折叠?



