微服务架构设计文档
📅 2026-08-31
📂 架构
📖 15 分钟阅读
一、整体架构图
┌─────────────────────────────────────────────────────────────────────────────┐
│ 客户端 (用户/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 |
初始版本 |
- |