跳到主要内容

数据一致性策略

目录

  1. 引言
  2. 项目结构
  3. 核心组件
  4. 架构总览
  5. 详细组件分析
  6. 依赖关系分析
  7. 性能考量
  8. 故障排查指南
  9. 结论
  10. 附录

引言

本策略文档面向 yudao-cloud 在分布式环境下的数据一致性挑战,系统性阐述最终一致性的实现机制与工程化落地,覆盖消息队列异步处理、事件驱动架构、补偿与重试、分布式事务处理方案(Saga/TCC)、双写一致性与读写分离下的数据一致性保障,并给出一致性级别选择、性能权衡与故障恢复的技术决策。

项目结构

yudao-cloud 采用多模块微服务架构,围绕“基础设施层”“业务模块层”“消息中间件与总线”“一致性保障组件”四个维度组织。其中:

  • 基础设施层:提供 MQ 统一抽象、Redis 分布式锁、WebSocket 消息通道、定时任务等通用能力。
  • 业务模块层:如系统、规则、设备、流程等模块,负责具体业务逻辑与对外接口。
  • 消息中间件与总线:支持 Kafka/RocketMQ/RabbitMQ/Redis Streams 等多种传输介质;Spring Cloud Bus 提供广播能力。
  • 一致性保障组件:基于 Redis 分布式锁、本地队列兜底、Pending 消息重投、本地消息表等手段实现最终一致性。

Mermaid Diagram Code:

graph TB
subgraph "基础设施层"
MQ["消息队列抽象<br/>Redis/Kafka/RabbitMQ/RocketMQ"]
BUS["消息总线<br/>Spring Cloud Bus"]
REDIS["Redis 分布式锁"]
WS["WebSocket 消息通道"]
JOB["定时任务/重试作业"]
end
subgraph "业务模块层"
SYS["系统模块"]
RULE["规则模块"]
DEV["设备模块"]
BPM["流程模块"]
end
SYS --> MQ
RULE --> MQ
DEV --> MQ
BPM --> MQ
MQ --> SYS
MQ --> RULE
MQ --> DEV
MQ --> BPM
BUS --> RULE
WS --> MQ
JOB --> MQ
REDIS --> RULE

图示来源

章节来源

核心组件

  • 消息队列与总线
    • 支持 Kafka/RocketMQ/RabbitMQ/Redis Streams 多实现,统一抽象便于替换与扩展。
    • Spring Cloud Bus 提供广播能力,用于跨节点事件通知与回调。
  • 分布式锁
    • 基于 Redis 的 setIfAbsent + 过期时间 + 值校验的分布式锁工具,保障幂等与串行化。
  • 本地队列与重试
    • Kafka 消费侧在获取分布式锁失败时,将消息放入本地阻塞队列,后台线程兜底重试,避免丢失。
    • Redis Stream Pending 消息定期扫描与重投,提升崩溃后消息处理的可靠性。
  • 事件驱动与补偿
    • 业务模块通过 Kafka 发送事件,消费侧幂等处理;必要时采用本地消息表记录发送与处理状态,支持人工重试与追踪。
  • 双写与影子库
    • 设备模块通过影子库与 Nacos 动态切换,实现平滑的数据源迁移与双写验证,降低一致性风险。

章节来源

架构总览

yudao-cloud 的一致性策略以“事件驱动 + 最终一致 + 幂等 + 补偿”为核心,结合分布式锁与本地队列兜底,确保跨服务、跨数据源场景下的数据一致性。

Mermaid Diagram Code:

sequenceDiagram
participant Producer as "生产者模块"
participant MQ as "消息队列"
participant Consumer as "消费者模块"
participant Lock as "Redis 分布式锁"
participant DB as "业务数据库"
Producer->>MQ : "发送事件/消息"
MQ-->>Consumer : "投递事件"
Consumer->>Lock : "尝试获取分布式锁"
alt "获取成功"
Lock-->>Consumer : "加锁成功"
Consumer->>DB : "执行业务处理幂等"
Consumer-->>MQ : "确认消费/提交位点"
else "获取失败"
Lock-->>Consumer : "加锁失败"
Consumer->>Consumer : "本地队列入队兜底重试"
end

图示来源

详细组件分析

组件A:规则模块的业务限流与幂等处理

规则模块通过 Kafka 消费事件,结合 Redis 分布式锁与本地队列,实现高并发下的幂等与可靠处理。

Mermaid Diagram Code:

flowchart TD
Start(["开始"]) --> Listen["监听 Kafka 事件"]
Listen --> TryLock["尝试获取分布式锁"]
TryLock --> LockOK{"加锁成功?"}
LockOK --> |是| Process["执行业务处理幂等"]
LockOK --> |否| Enqueue["放入本地队列"]
Enqueue --> LocalLoop["本地队列轮询"]
LocalLoop --> RetryLock["再次尝试加锁"]
RetryLock --> LockOK2{"加锁成功?"}
LockOK2 --> |是| Process
LockOK2 --> |否| DropOrBackoff["丢弃或退避重试"]
Process --> Done(["结束"])
DropOrBackoff --> Done

图示来源

章节来源

组件B:系统模块的短信发送事件处理

系统模块通过 Spring Event + @Async 实现异步短信发送,避免阻塞主流程,体现事件驱动与解耦。

Mermaid Diagram Code:

sequenceDiagram
participant Biz as "业务调用方"
participant Event as "Spring Event"
participant Consumer as "SmsSendConsumer"
participant Service as "SmsSendService"
Biz->>Event : "发布短信发送事件"
Event-->>Consumer : "@EventListener + @Async 异步触发"
Consumer->>Service : "doSendSms(message)"
Service-->>Consumer : "发送完成/异常上报"

图示来源

章节来源

组件C:规则编辑权限的事件驱动校验

规则模块通过 Kafka 与 Spring Cloud Bus 实现“规则 → 业务”的请求-回调模式,消费侧需幂等处理并返回结果。

Mermaid Diagram Code:

sequenceDiagram
participant Rule as "规则模块"
participant Kafka as "Kafka"
participant Bus as "Spring Cloud Bus"
participant Biz as "业务模块"
Rule->>Kafka : "发送检查是否可编辑事件"
Kafka-->>Biz : "消费组内仅一个节点处理"
Biz->>Bus : "广播回调结果所有节点可见"
Biz-->>Rule : "TimedCache 中获取回调结果"

图示来源

章节来源

组件D:WebSocket 消息的 Kafka 广播

WebSocket 消息通过 Kafka 广播,每个消费者组实例使用唯一 groupId 实现广播消费,确保消息到达所有节点。

Mermaid Diagram Code:

sequenceDiagram
participant Sender as "WebSocket 消息发送器"
participant Kafka as "Kafka"
participant Consumer as "KafkaWebSocketMessageConsumer"
Sender->>Kafka : "发送 WebSocket 广播消息"
Kafka-->>Consumer : "按不同 groupId 广播"
Consumer->>Consumer : "解析消息并发送给指定会话"

图示来源

章节来源

组件E:Redis Stream Pending 消息重投

Redis Stream 在消费者崩溃或处理超时后,通过定时任务扫描 Pending 队列并重投,保障消息不丢失。

Mermaid Diagram Code:

flowchart TD
T0["定时任务启动"] --> Scan["扫描 Pending 队列"]
Scan --> Timeout{"消息是否超时?"}
Timeout --> |是| Resend["重投消息"]
Timeout --> |否| Skip["跳过等待"]
Resend --> Ack["处理完成确认"]
Skip --> T1["下次调度"]
Ack --> T1

图示来源

章节来源

组件F:流程实例状态消息的重发与补偿

流程模块提供消息重发能力,当消息发送失败时,支持按消息键重发并记录重试次数,便于人工介入与追踪。

章节来源

组件G:设备模块的影子库与数据源切换

设备模块通过“影子库 + Nacos 动态切换 + 导出/导入/重置”的方式,实现平滑的数据源迁移与双写验证,降低一致性风险。

Mermaid Diagram Code:

flowchart TD
A["创建影子库"] --> B["切换数据源到影子库"]
B --> C["新写入走影子库"]
C --> D["导出旧主库数据"]
D --> E["重置旧主库结构"]
E --> F["切换回旧主库可选回滚"]

图示来源

章节来源

依赖关系分析

  • 模块间耦合
    • 业务模块通过 MQ 与总线与外部交互,降低直接 RPC 调用带来的强耦合。
    • 规则模块与业务模块通过事件驱动解耦,消费侧需幂等处理。
  • 外部依赖
    • Kafka/RocketMQ/RabbitMQ/Redis Streams 提供高吞吐、低延迟的消息传递。
    • Spring Cloud Bus 提供广播与配置刷新能力。
  • 循环依赖
    • 通过事件与消息解耦,避免模块间的直接循环调用。

Mermaid Diagram Code:

graph LR
SYS["系统模块"] -- "Kafka/RabbitMQ" --> MQ["消息中间件"]
RULE["规则模块"] -- "Kafka/RabbitMQ" --> MQ
DEV["设备模块"] -- "Kafka/RabbitMQ" --> MQ
BPM["流程模块"] -- "Kafka/RabbitMQ" --> MQ
MQ -- "Spring Cloud Bus" --> RULE
MQ -- "Redis 分布式锁" --> RULE

图示来源

章节来源

性能考量

  • 异步与解耦
    • 通过事件驱动与消息队列异步处理,显著降低请求链路延迟,提升吞吐。
  • 幂等与重试
    • 消费侧幂等设计与本地队列兜底,减少重复计算与资源浪费。
  • 分布式锁粒度
    • 以“业务类型+业务ID”为维度的细粒度锁,避免全局阻塞,提高并发。
  • Redis Stream Pending 重投
    • 通过定时扫描 Pending,平衡消息可靠性与系统负载。
  • 双写与影子库
    • 影子库双写验证与 Nacos 动态切换,降低迁移期间的一致性风险与停机时间。

故障排查指南

  • 消息堆积与积压
    • 检查消费者线程池与分区数量,评估是否需要扩容或优化消费逻辑。
    • 关注本地队列容量与重试策略,避免队列溢出导致丢弃。
  • 消费失败与重试
    • 查看 Redis 分布式锁是否正确释放,避免死锁导致的持续重试。
    • 对 Redis Stream 场景,确认 Pending 消息重投任务是否正常运行。
  • 业务补偿
    • 对于流程模块的消息重发失败,根据消息键定位并重发,记录重试次数。
  • 本地消息表
    • 规则模块需求中提到本地消息表方案,建议在 MQ 多次失败后,采用私信队列记录并提供人工重试界面。

章节来源

结论

yudao-cloud 在分布式环境下以“事件驱动 + 最终一致 + 幂等 + 补偿”为核心策略,结合 Redis 分布式锁、本地队列兜底、Pending 消息重投与影子库双写验证,有效平衡了性能与一致性。对于强一致需求,建议优先采用本地消息表与补偿机制,辅以 Saga/TCC 的长事务编排,确保跨服务的数据一致性与可恢复性。

附录

  • 一致性级别选择
    • 金融级强一致:采用本地消息表 + 补偿(Saga/TCC)。
    • 业务级强一致:采用 Redis 分布式锁 + 幂等 + 本地队列兜底。
    • 最终一致:采用 Kafka/RabbitMQ + 幂等 + Pending 重投。
  • 性能权衡
    • 异步解耦提升吞吐,但需关注幂等与补偿成本。
    • 分布式锁粒度与超时设置影响并发与稳定性。
  • 故障恢复
    • 本地消息表与私信队列记录失败消息,提供人工重试与可视化追踪。
    • Redis Stream Pending 重投与 Kafka/RabbitMQ 的重试策略协同,提升可靠性。
用户文档
AI 助手
Agent 列表
请选择一个 Agent 开始对话
AI 问答