一、分布式事务困境:ACID vs BASE
1.1 传统方案的局限性
1.2 轻量级方案核心思想
核心原则:
- 最终一致性:允许短暂不一致
- 事件驱动:通过消息解耦服务
- 幂等设计:支持重复消费
- 补偿机制:失败自动重试
二、Spring Boot实现方案:事务消息+本地事件表
2.1 架构设计
2.2 核心依赖
<dependencies>
<!-- Spring Boot Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- RocketMQ -->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.2.3</version>
</dependency>
<!-- MyBatis Plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
<!-- 分布式ID生成 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.16</version>
</dependency>
</dependencies>
三、核心实现源码
3.1 事件表设计
@Data
@TableName("distributed_event")
public class DistributedEvent {
@TableId(type = IdType.ASSIGN_ID)
private Long id;
private String eventType; // 事件类型:ORDER_CREATED, PAYMENT_SUCCESS
private String payload; // JSON格式事件数据
private String status; // 状态:NEW, PROCESSING, SUCCESS, FAILED
private Integer retryCount; // 重试次数
private LocalDateTime createTime;
private LocalDateTime updateTime;
}
// 事件状态枚举
public enum EventStatus {
NEW, PROCESSING, SUCCESS, FAILED
}
3.2 本地事务管理器
@Service
@Transactional
public class TransactionCoordinator {
private final DistributedEventMapper eventMapper;
private final RocketMQTemplate rocketMQTemplate;
public void executeInTransaction(Runnable businessLogic, String eventType, Object payload) {
// 1. 执行业务逻辑
businessLogic.run();
// 2. 保存事件到数据库
DistributedEvent event = new DistributedEvent();
event.setEventType(eventType);
event.setPayload(JSON.toJSONString(payload));
event.setStatus(EventStatus.NEW.name());
event.setRetryCount(0);
eventMapper.insert(event);
// 3. 发送事务消息
TransactionSendResult result = rocketMQTemplate.sendMessageInTransaction(
"tx-event-group",
"event-topic",
MessageBuilder.withPayload(event.getId()).build(),
event.getId()
);
if (!result.getLocalTransactionState().equals(LocalTransactionState.COMMIT_MESSAGE)) {
throw new TransactionException("消息发送失败");
}
}
}
3.3 RocketMQ事务监听器
@RocketMQTransactionListener(txProducerGroup = "tx-event-group")
public class EventTransactionListener implements RocketMQTransactionListener {
private final DistributedEventMapper eventMapper;
@Override
public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
Long eventId = (Long) arg;
DistributedEvent event = eventMapper.selectById(eventId);
if (event != null && EventStatus.NEW.name().equals(event.getStatus())) {
return LocalTransactionState.COMMIT_MESSAGE;
}
return LocalTransactionState.ROLLBACK_MESSAGE;
}
@Override
public LocalTransactionState checkLocalTransaction(Message msg) {
Long eventId = Long.parseLong(new String(msg.getBody()));
DistributedEvent event = eventMapper.selectById(eventId);
if (event == null) {
return LocalTransactionState.ROLLBACK_MESSAGE;
}
return EventStatus.NEW.name().equals(event.getStatus()) ?
LocalTransactionState.COMMIT_MESSAGE :
LocalTransactionState.ROLLBACK_MESSAGE;
}
}
3.4 事件消费者
@Service
@RocketMQMessageListener(
topic = "event-topic",
consumerGroup = "event-consumer-group"
)
public class EventConsumer implements RocketMQListener<String> {
private final EventDispatcher eventDispatcher;
private final DistributedEventMapper eventMapper;
@Override
@Transactional
public void onMessage(String message) {
Long eventId = Long.parseLong(message);
DistributedEvent event = eventMapper.selectById(eventId);
// 幂等性检查
if (event == null || !EventStatus.NEW.name().equals(event.getStatus())) {
return;
}
// 更新状态为处理中
event.setStatus(EventStatus.PROCESSING.name());
eventMapper.updateById(event);
try {
// 分发事件处理
eventDispatcher.dispatch(event);
// 处理成功
event.setStatus(EventStatus.SUCCESS.name());
} catch (Exception e) {
// 处理失败
event.setStatus(EventStatus.FAILED.name());
event.setRetryCount(event.getRetryCount() + 1);
}
eventMapper.updateById(event);
}
}
3.5 事件分发器
@Component
public class EventDispatcher {
private final Map<String, EventHandler> handlers = new ConcurrentHashMap<>();
// 注册处理器
public void registerHandler(String eventType, EventHandler handler) {
handlers.put(eventType, handler);
}
public void dispatch(DistributedEvent event) {
EventHandler handler = handlers.get(event.getEventType());
if (handler == null) {
throw new EventHandleException("未找到事件处理器: " + event.getEventType());
}
handler.handle(event);
}
}
// 订单创建事件处理器
@Component
public class OrderCreatedHandler implements EventHandler {
private final PaymentService paymentService;
@Override
public void handle(DistributedEvent event) {
OrderCreatedEvent payload = JSON.parseObject(event.getPayload(), OrderCreatedEvent.class);
paymentService.createPayment(payload.getOrderId(), payload.getAmount());
}
}
3.6 补偿任务(定时重试)
@Slf4j
@Component
public class EventCompensator {
private final EventDispatcher eventDispatcher;
private final DistributedEventMapper eventMapper;
private final RocketMQTemplate rocketMQTemplate;
@Scheduled(fixedDelay = 30000) // 每30秒执行一次
public void compensateFailedEvents() {
// 查询失败且重试次数小于5次的事件
List<DistributedEvent> failedEvents = eventMapper.selectList(
new QueryWrapper<DistributedEvent>()
.eq("status", EventStatus.FAILED.name())
.lt("retry_count", 5)
);
for (DistributedEvent event : failedEvents) {
try {
log.info("重试事件: {}", event.getId());
rocketMQTemplate.syncSend("event-topic", event.getId().toString());
} catch (Exception e) {
log.error("事件重试发送失败: {}", event.getId(), e);
}
}
}
}
四、应用场景实战
4.1 电商下单场景
代码实现:
// 订单服务
@Service
public class OrderService {
private final TransactionCoordinator coordinator;
public void createOrder(Order order) {
coordinator.executeInTransaction(() -> {
// 1. 保存订单
orderMapper.insert(order);
// 2. 生成事件数据
OrderCreatedEvent event = new OrderCreatedEvent();
event.setOrderId(order.getId());
event.setAmount(order.getAmount());
}, "ORDER_CREATED", event);
}
}
// 支付服务
@Component
public class PaymentHandler implements EventHandler {
@Override
public void handle(DistributedEvent event) {
OrderCreatedEvent payload = JSON.parseObject(event.getPayload(), OrderCreatedEvent.class);
paymentService.createPayment(payload.getOrderId(), payload.getAmount());
}
}
4.2 跨行转账场景
// 转账服务
public void transfer(TransferRequest request) {
coordinator.executeInTransaction(() -> {
// 1. 扣减转出账户
accountService.debit(request.getFromAccount(), request.getAmount());
// 2. 生成转账事件
TransferEvent event = new TransferEvent();
event.setFromAccount(request.getFromAccount());
event.setToAccount(request.getToAccount());
event.setAmount(request.getAmount());
}, "TRANSFER_INITIATED", event);
}
// 收款银行服务
@Component
public class TransferHandler implements EventHandler {
@Override
public void handle(DistributedEvent event) {
TransferEvent payload = JSON.parseObject(event.getPayload(), TransferEvent.class);
// 调用银行API
bankService.credit(payload.getToAccount(), payload.getAmount());
}
}
4.3 酒店预订场景
// 预订服务
public void bookHotel(BookingRequest request) {
coordinator.executeInTransaction(() -> {
// 1. 保存预订记录
bookingMapper.insert(booking);
// 2. 生成支付事件
PaymentEvent paymentEvent = new PaymentEvent();
paymentEvent.setBookingId(booking.getId());
paymentEvent.setAmount(booking.getAmount());
}, "BOOKING_CREATED", paymentEvent);
// 3. 生成积分事件
PointEvent pointEvent = new PointEvent();
pointEvent.setUserId(request.getUserId());
pointEvent.setPoints(booking.getAmount() / 10);
coordinator.executeInTransaction(() -> {}, "POINT_EVENT", pointEvent);
}
// 积分服务
@Component
public class PointHandler implements EventHandler {
@Override
public void handle(DistributedEvent event) {
PointEvent payload = JSON.parseObject(event.getPayload(), PointEvent.class);
pointService.addPoints(payload.getUserId(), payload.getPoints());
}
}
五、高级特性实现
5.1 幂等性设计
public class IdempotentHandler implements EventHandler {
private final DistributedEventMapper eventMapper;
@Override
public void handle(DistributedEvent event) {
// 检查是否已处理过
if (eventMapper.selectById(event.getId()) != null) {
log.warn("重复事件已忽略: {}", event.getId());
return;
}
// 处理逻辑...
}
}
5.2 死信队列处理
@Bean
public MessageChannel deadLetterChannel() {
return MessageChannels.queue().get();
}
@Bean
@ServiceActivator(inputChannel = "deadLetterChannel")
public MessageHandler deadLetterHandler() {
return message -> {
// 处理无法投递的消息
log.error("死信消息: {}", message);
DeadLetter deadLetter = new DeadLetter();
deadLetter.setPayload(message.getPayload().toString());
deadLetterRepository.save(deadLetter);
};
}
5.3 事件溯源
@Entity
public class EventSourcingRecord {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String aggregateId; // 聚合根ID
private String eventType;
private String payload;
private LocalDateTime timestamp;
}
public void saveEvent(String aggregateId, String eventType, Object payload) {
EventSourcingRecord record = new EventSourcingRecord();
record.setAggregateId(aggregateId);
record.setEventType(eventType);
record.setPayload(JSON.toJSONString(payload));
record.setTimestamp(LocalDateTime.now());
eventSourcingRepository.save(record);
}
六、性能优化策略
6.1 批量事件处理
@RocketMQMessageListener(
topic = "event-topic",
consumerGroup = "batch-consumer",
consumeMode = ConsumeMode.ORDERLY,
messageModel = MessageModel.CLUSTERING,
selectorExpression = "*",
consumeThreadMax = 20
)
public class BatchEventConsumer implements RocketMQListener<List<MessageExt>> {
@Override
public void onMessage(List<MessageExt> messages) {
List<Long> eventIds = messages.stream()
.map(msg -> Long.parseLong(new String(msg.getBody())))
.collect(Collectors.toList());
// 批量查询事件
List<DistributedEvent> events = eventMapper.selectBatchIds(eventIds);
// 批量处理
eventDispatcher.batchDispatch(events);
}
}
6.2 事件表分片设计
// 按月份分片
@TableName("distributed_event_#{T(java.time.LocalDate).now().getMonthValue()}")
public class DistributedEvent {
// ...
}
// 动态表名处理器
public class MonthShardingTableNameHandler implements ITableNameHandler {
@Override
public String dynamicTableName(String sql, String tableName) {
int month = LocalDate.now().getMonthValue();
return tableName + "_" + month;
}
}
6.3 异步事件处理
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(50);
executor.setQueueCapacity(1000);
executor.setThreadNamePrefix("EventExecutor-");
executor.initialize();
return executor;
}
}
// 异步处理事件
@Async
@Override
public void handle(DistributedEvent event) {
// 事件处理逻辑
}
七、生产环境最佳实践
7.1 监控指标配置
@Bean
public MeterRegistryCustomizer<MeterRegistry> metrics() {
return registry -> {
Gauge.builder("event.queue.size", eventMapper::selectPendingCount)
.description("待处理事件数量")
.register(registry);
Gauge.builder("event.process.duration", eventDispatcher::getAvgProcessTime)
.description("事件平均处理时间")
.register(registry);
};
}
7.2 部署架构
7.3 配置建议
rocketmq:
name-server: mq1:9876;mq2:9876;mq3:9876
producer:
group: tx-producer-group
send-message-timeout: 3000
consumer:
group: event-consumer-group
consume-thread-max: 32
event:
max-retry: 5
retry-interval: 30000 # 30秒
sharding-strategy: monthly # 分片策略
八、与传统方案对比
九、总结与展望
9.1 方案优势
- 高性能:单机支持万级TPS
- 低耦合:服务间通过消息解耦
- 高可用:无单点故障
- 可扩展:水平扩展能力强
- 简单易用:Spring Boot无缝集成
9.2 适用场景
- 电商订单系统
- 跨行转账业务
- 酒店机票预订
- 物联网设备联动
- 微服务间数据同步
9.3 未来演进
- 事件溯源增强:完整业务追溯能力
- AI驱动补偿:智能故障预测与修复
- 跨链事务:区块链集成
- 无服务架构:Serverless适配