一、整体架构图

┌─────────────────────────────────────────────────────────────────────────────┐
│                             客户端 (用户/APP)                              │
└─────────────────────────────────┬───────────────────────────────────────────┘
                                  │
          ┌───────────────────────┼───────────────────────┐
          │ 路径1:域名直连        │                       │ 路径2:负载均衡入口
          │ (测试/特殊通道)       │                       │ (正式生产)
          ▼                       │                       ▼
┌─────────────────┐              │         ┌─────────────────────────────┐
│  反向代理服务器  │ ◄────────────┼─────────│   负载均衡器 (SLB/Nginx)    │
│   (Nginx)       │              │         │   ● IP白名单校验            │
│ ● 前端静态资源   │              │         │   ● 健康检查                │
└────────┬────────┘              │         └──────────────┬──────────────┘
         │                       │                        │
         └───────────────────────┼────────────────────────┘
                                 │
                                 ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│                         网关层 (Gateway)                                  │
│  ① 路由匹配:有服务则转发,无则返回503                                    │
│  ② 统一鉴权:Token/权限校验,非法请求直接拦截                              │
│  ③ 限流熔断:Sentinel 防护(待补充)                                     │
└─────────────────────────────────┬───────────────────────────────────────────┘
                                  │
                                  ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│                   服务注册与发现 (Nacos)                                  │
│            Gateway 根据路径从 Nacos 获取目标微服务列表                     │
└─────────────────────────────────┬───────────────────────────────────────────┘
                                  │
                                  ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│                        业务微服务层                                        │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │                         服务A (主业务服务)                         │   │
│  │  ┌─────────────────────┐          ┌────────────────────────────┐  │   │
│  │  │  查询/少量读操作     │          │  变更/写操作               │  │   │
│  │  │  (同步 OpenFeign)   │          │  (异步 MQ)                │  │   │
│  │  └──────────┬──────────┘          └─────────────┬──────────────┘  │   │
│  └─────────────┼────────────────────────────────────┼──────────────────┘   │
│                │                                    │                       │
│                ▼                                    ▼                       │
│  ┌─────────────────────────┐        ┌─────────────────────────────┐        │
│  │       服务B              │        │     消息队列 (RabbitMQ)     │        │
│  │  (人员信息查询服务)       │        │  ● 持久化消息              │        │
│  │  ● 高频读操作            │        │  ● Confirm机制             │        │
│  │  ● OpenFeign 同步响应    │        │  ● 死信队列 (DLX)          │        │
│  └─────────────────────────┘        └──────────────┬──────────────┘        │
│                                                    │                        │
│                                                    ▼                        │
│                              ┌─────────────────────────────┐               │
│                              │      服务C (消费者)          │               │
│                              │  ● 消费MQ消息               │               │
│                              │  ● 幂等检查(查DB状态)       │               │
│                              │  ● 执行变更业务             │               │
│                              └─────────────────────────────┘               │
└─────────────────────────────────┬───────────────────────────────────────────┘
                                  │
          ┌───────────────────────┼───────────────────────┐
          ▼                       ▼                       ▼
┌───────────────────┐ ┌─────────────────┐ ┌─────────────────────────────┐
│   缓存层 (Redis)  │ │  关系型数据库   │ │   对象存储 (MinIO)           │
│                   │ │  (MySQL)       │ │                             │
│ ● 分布式锁(防重复)│ │ ● 状态字段      │ │ ● 存放非关系型数据          │
│ ● 业务缓存(读)   │ │   (幂等标记)   │ │ ● 图片/文件/日志等          │
│ ● 读流程:       │ │ ● 读写分离     │ │                             │
│   先查缓存→DB→回写│ │ ● 唯一索引     │ │                             │
└───────────────────┘ └─────────────────┘ └─────────────────────────────┘

二、两种请求路径说明

路径方式 适用场景
路径 1:域名直连反向代理DNS → Nginx 本地调试、运维紧急通道、绕过 LB 白名单
路径 2:负载均衡入口DNS → LB (白名单) → Nginx 正式生产环境(推荐)

三、核心交互方式

场景 技术方案 原因
查询人员信息 / 少量数据 OpenFeign 同步调用 实时性强,链路简单,小数据量开销小
数据变更(增删改) RabbitMQ 异步消息 解耦、削峰填谷、下游故障隔离

四、防重复机制(核心设计)

4.1 生产者端(服务 A)—— Redis 永久锁

用户发起变更请求
    │
    ▼
尝试获取 Redis 锁(Key: "lock:业务类型:业务ID")
    │
    ├─ 获取失败 → 返回 "操作中,请勿重复提交"(永久拦截)
    │
    └─ 获取成功 → 发送 MQ 消息 → 返回 "提交成功"

特点:

4.2 消费者端(服务 C)—— 数据库状态字段

消费者收到消息
    │
    ▼
查询数据库状态字段(如 status)
    │
    ├─ 已是 "已完成" → 直接丢弃消息(ACK确认)
    │
    └─ 是 "待处理" → 执行业务 → 更新状态为 "已完成" → ACK

特点:

4.3 双锁配合流程图

┌─────────────────────────────────────────────────────────────────┐
│                        生产者端(服务A)                        │
│  ① 业务请求 → ② Redis锁(永久拦截重复入队)→ ③ 发送MQ消息    │
└─────────────────────────────────────────────────────────────────┘
                                  │
                                  ▼
┌─────────────────────────────────────────────────────────────────┐
│                        RabbitMQ                                │
│  ● 消息持久化                    ● Confirm机制                 │
│  ● 死信队列 (消费失败N次后进入)                                 │
└─────────────────────────────────────────────────────────────────┘
                                  │
                                  ▼
┌─────────────────────────────────────────────────────────────────┐
│                        消费者端(服务C)                        │
│  ① 拉取消息 → ② 查DB状态 → ③ 已变更则丢弃,未变更则执行     │
└─────────────────────────────────────────────────────────────────┘

五、Redis 锁与 DB 状态的职责划分

组件 作用范围 是否设过期时间 防什么
Redis 永久锁 生产者端 ❌ 不设(业务完成后主动删) 防止同一数据重复入队
数据库状态字段 消费者端 ❌ 不需要 防止消息重复消费(幂等)
读缓存(Redis) 读操作 ✅ 设过期(防雪崩) 加速查询,减少 DB 压力

六、数据流向

6.1 读操作流程

请求 → 查 Redis 缓存 → 命中 → 直接返回
                    ↓
                 未命中
                查 MySQL → 回写 Redis → 返回

6.2 写操作流程(变更)

变更请求 → Redis锁(防重复入队) → 发MQ消息 → 返回"提交成功"
                                          ↓
                               消费者拉取消息 → 查DB状态
                                            ↓
                                  已变更? ──是──→ 丢弃
                                            ↓ 否
                                      执行业务 → 更新DB状态 → ACK
                                          ↓
                                    删除Redis锁(允许下次变更)

七、高可用与容错设计

问题 解决方案 状态
网关超时 / 服务慢 Sentinel 限流熔断 🔲 待补充
跨服务事务一致性 Seata (TCC) 🔲 按需引入
链路追踪 SkyWalking 🔲 待补充
监控告警 Prometheus + Grafana 🔲 待补充
缓存穿透 / 击穿 / 雪崩 布隆过滤器 + 互斥锁 + 随机过期时间 🔲 建议补充
MQ 消息丢失 生产者 Confirm + 持久化 + 消费者手动 ACK ✅ 已具备
MQ 消费失败重试 重试 N 次后进死信队列 ✅ 已具备
重复消费 生产者 Redis 锁 + 消费者 DB 状态 ✅ 已具备

八、Redis 锁正确用法总结

场景 是否设过期 原因
生产者端防重复入队 ❌ 不设(业务完成后主动删) 永久拦截,防止并发提交
分布式锁(通用) ✅ 必须设 防进程级故障导致死锁
业务缓存 ✅ 设过期 保证数据最终一致性

九、待补充项清单(按优先级)

优先级 项目 说明
🔴 高 Sentinel 熔断限流 网关层和服务层防护
🔴 高 SkyWalking 链路追踪 全链路监控
🟡 中 缓存三大坑防护 布隆过滤器 + 互斥锁 + 随机过期
🟡 中 Prometheus 监控告警 JVM / 内存 / GC / 业务指标
🟢 低 K8s + Docker 容器化部署与灰度发布
🟢 低 Seata 分布式事务 强一致性场景按需引入

十、订单支付场景适配说明

10.1 适合异步 MQ 处理的(✅ 可以直接用)

操作 说明
增加用户积分 非核心,可重试,幂等
发送支付成功通知 非核心,可重试
更新统计报表 非核心,最终一致即可
记录操作日志 非核心

10.2 不适合异步 MQ 处理的(❌ 必须改为同步)

操作 原因 正确做法
扣减余额 强一致性,用户实时感知 同步本地事务(@Transactional)
扣减库存 强一致性,防止超卖 同步本地事务(@Transactional)
创建订单 用户立即要看 同步创建,状态 = 待支付

10.3 支付场景混合架构流程

用户发起支付请求
    │
    ▼
① Redis锁(防重复提交): lock:order:123456
    │
    ├─ 获取失败 → 返回 "支付处理中,请勿重复提交"
    │
    └─ 获取成功 → ② 开启数据库事务
                   │
                   ├─ 扣减余额(SELECT ... FOR UPDATE 或 乐观锁)
                   ├─ 扣减库存(同上)
                   ├─ 创建订单(状态=已支付)
                   └─ 提交事务
                      │
                      ▼
                  ③ 删除Redis锁
                      │
                      ▼
                  ④ 发送MQ消息(订单支付成功事件)
                      │
                      ▼
                  ⑤ 返回 "支付成功" 给用户
                      │
          ┌──────────┴──────────┐
          ▼                     ▼
    消费者A(积分)        消费者B(通知)
    查DB幂等 → 加积分      查DB幂等 → 发短信/推送

十一、核心结论

业务类型 是否适合当前架构
非核心变更(发通知、加积分、写日志) ✅ 非常适合,直接用 MQ 异步
核心支付扣款(扣余额、扣库存) ❌ 不适合,必须改为同步事务
订单状态更新(待支付→已支付) ⚠️ 有条件,必须等扣款事务成功后发 MQ
防重复支付 ✅ 完美,Redis 永久锁正合适

十二、生产者消费者核心代码示例

12.1 生产者端(发送消息)

@Service
public class OrderService {

   @Autowired
   private RedisTemplate<String, String> redisTemplate;

   @Autowired
   private RabbitTemplate rabbitTemplate;

   public Result createOrder(OrderDTO dto) {
       String lockKey = "lock:order:" + dto.getOrderId();

       // 1. 获取Redis永久锁(防重复入队)
       Boolean locked = redisTemplate.opsForValue()
               .setIfAbsent(lockKey, "1");
       if (!locked) {
           return Result.fail("操作处理中,请勿重复提交");
       }

       try {
           // 2. 发送MQ消息
           rabbitTemplate.convertAndSend(
                   "order.exchange",
                   "order.create",
                   dto
           );
           return Result.success("提交成功");
       } catch (Exception e) {
           // 发送失败,释放锁
           redisTemplate.delete(lockKey);
           throw e;
       }
   }
}

12.2 消费者端(消费消息)

@Component
@RabbitListener(queues = "order.queue")
public class OrderConsumer {

   @Autowired
   private OrderService orderService;

   @Autowired
   private RedisTemplate<String, String> redisTemplate;

   @RabbitHandler
   public void handle(OrderDTO dto, Channel channel,
                      @Header(AmqpHeaders.DELIVERY_TAG) long tag) {
       try {
           // 1. 幂等检查:查DB状态
           Order order = orderService.getById(dto.getOrderId());
           if (order.getStatus() == OrderStatus.COMPLETED) {
               // 已处理,直接ACK
               channel.basicAck(tag, false);
               return;
           }

           // 2. 执行业务
           orderService.processOrder(dto);

           // 3. 更新DB状态为已完成
           orderService.updateStatus(dto.getOrderId(), OrderStatus.COMPLETED);

           // 4. ACK确认
           channel.basicAck(tag, false);

           // 5. 删除Redis锁(允许下次变更)
           redisTemplate.delete("lock:order:" + dto.getOrderId());

       } catch (Exception e) {
           log.error("消费失败", e);
           // 重试或进入死信队列
           try {
               channel.basicNack(tag, false, false);
           } catch (IOException ex) {
               log.error("NACK失败", ex);
           }
       }
   }
}

十三、文档版本

版本 日期 修改内容 作者
v1.0 2026-08-31 初始版本 -