周五下午 5 点,客服反馈大量用户投诉:明明支付成功了,订单状态却显示"待支付";优惠券已经核销了,但订单里还显示"未使用"。你打开数据库一看,订单库和支付库的数据对不上——在一个微服务架构的系统中,数据不一致是最让人头疼的问题之一。它不像 OOM 或 CPU 飙升那样有明确的告警,而是悄无声息地累积,直到用户投诉才被发现。本文将系统性梳理数据不一致的排查和修复全流程。
一、数据不一致的 5 种典型场景
1.1 场景全景图
┌──────────────────────────────────────────────────────────────────┐
│ 微服务数据不一致的 5 种典型场景 │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 场景1: 跨服务操作部分成功 │ │
│ │ 订单服务 ──▶ 创建订单(✓) │ │
│ │ 库存服务 ──▶ 扣减库存(✗ 网络超时) │ │
│ │ 优惠券 ──▶ 核销券(✓) │ │
│ │ 结果: 订单创建了,券核销了,但库存没扣 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 场景2: 消息消费部分失败 │ │
│ │ Producer ──▶ 发送消息(✓) ──▶ 事务提交(✓) │ │
│ │ Consumer ──▶ 消费消息 ──▶ 更新DB(✗) ──▶ ACK(✓) │ │
│ │ 结果: 消息被确认消费了,但数据库更新失败 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 场景3: 并发更新顺序不一致 │ │
│ │ 线程A: 读旧值 ──▶ 计算 ──▶ 写入 │ │
│ │ 线程B: 读旧值 ──▶ 计算 ──▶ 写入 │ │
│ │ 结果: 后写的覆盖先写的,但逻辑上应该 A 在前 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 场景4: 缓存与数据库不一致 │ │
│ │ DB ──▶ 更新(✓) ──▶ 删除缓存(✗ 网络故障) │ │
│ │ 结果: 缓存还是旧值,读到脏数据 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 场景5: 补偿事务执行失败 │ │
│ │ TCC: Try(✓) ──▶ Confirm(✓) ──▶ Cancel(✗ 节点宕机) │ │
│ │ 结果: Try 成功但 Cancel 没执行,资源锁定 │ │
│ └─────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
2026/7/3大约 21 分钟