最终一致性的补偿窗口怎么设计?
简化版
补偿窗口是主流程成功后,各派生状态恢复一致的最长允许时间。 它由业务风险和用户承诺决定,再反推事件重试、扫描、对账与人工处理时限,不能只说“最终会一致”。 超过窗口后进入违约状态,触发升级、限制业务或人工修复。
详细版
搜索索引可能允许 5 分钟,积分允许 15 分钟,支付记账可能要求秒级并在超时后冻结后续动作。 端到端窗口包含发布、排队、消费重试、下游恢复、验证和人工响应。 设计 P50/P95/P99 收敛 SLO 与 hard deadline。 以不一致首次形成时间计算年龄,重试不能重置计时。
完整版教学
一、窗口是业务契约
最终一致不代表无限等待。 用户何时必须看到积分、财务何时完成记账,都需要时间上限。 窗口决定何时展示处理中、限制下一步和升级事故。
没有时间上限的最终一致,是无法验证的愿望。
二、按风险分层
| 数据 | 示例窗口 | 超时动作 |
|---|---|---|
| 搜索索引 | 5 分钟 | 降级查主库 |
| 推荐画像 | 30 分钟 | 使用旧画像 |
| 用户积分 | 15 分钟 | 展示处理中 |
| 资金记账 | 秒/分钟级 | 冻结并人工复核 |
表中数字只是示例,必须由业务确认。
三、端到端预算
total window
= publish + queue + retry
+ downstream recovery + verify + manual reserve
总窗口 10 分钟时,自动重试不能占满 10 分钟。 要给升级和人工处置留下余量。
四、重试节奏
窗口短时前几次快速重试,之后指数退避并加抖动。 下游限流时遵循 Retry-After。 永久业务错误立即转人工,不消耗整个窗口。 补偿吞吐按故障积压容量设计。
五、计时起点
用 inconsistencyStartedAt 记录首次形成时间。 每次重试更新 attemptAt,但不重置年龄。 事件晚到时分别观测业务发生时间和系统接收时间。 人工暂停也不能让 SLO 计时消失。
六、窗口内体验
明确展示 PROCESSING,不提前宣称成功。 返回查询 token,允许轮询或接收通知。 会话层可合并 pending 状态实现读己之写体验。 超时后给出追踪号和可行动提示。
七、容量和监控
监控年龄直方图、超窗数、oldest age、阶段耗时和恢复吞吐。 例如故障期间每分钟新增 10 万条不一致、补偿每分钟只能处理 2 万条时,队列每分钟净增 8 万条,仍会增长。 要让积压收敛,补偿处理能力必须高于新的不一致流入速率,并为在线流量保留余量。 演练依赖中断后能否在承诺时间清空积压。
八、常见误区与追问
- 误区:所有数据统一 24 小时。 风险和用户预期不同。
- 误区:每次重试重置计时。 会掩盖真实不一致年龄。
- 误区:窗口内不需告警。 趋势恶化要提前预警。
- 误区:自动重试占满窗口。 必须给人工留预算。
- 追问:窗口如何确定? 从业务损失和用户承诺反推。
- 追问:超窗怎么办? 升级、限制操作、人工修复并记录违约。
- 追问:如何验收? 故障注入并测 P99 收敛与清空时间。
九、加强记忆
- 窗口是业务 SLO。
- 按数据风险分别设置。
- 总预算拆给自动链路和人工。
- 从不一致形成时计时。
- 监控年龄与净恢复吞吐,超窗必须升级。