NoSQL 一致性与事务设计:在 CAP、BASE 与业务正确性之间取舍
NoSQL 数据库经常被贴上“最终一致”的标签,但这并不意味着业务可以接受错误。工程设计的重点不是背诵 CAP,而是识别哪些业务必须强一致,哪些可以最终一致,哪些可以通过补偿修复。
分布式系统里,一致性、可用性和延迟之间永远存在取舍。NoSQL 的价值在于给你更多选择,同时也要求你承担更多设计责任。
CAP 的工程含义
CAP 讨论的是网络分区存在时,一致性和可用性之间的取舍。现实系统必须容忍网络分区,因此要明确故障时优先保证什么。
如果账户余额系统在网络分区时仍允许两个区域同时扣款,可能产生负余额,这是不可接受的。相反,文章浏览量在分区时短暂不一致,通常可以接受。
因此,不要问“这个数据库是否强一致”,而要问:
- 当前操作是否涉及资金、库存、权限或唯一约束?
- 用户是否能接受短暂旧数据?
- 冲突发生后能否自动合并?
- 补偿失败的影响是什么?
强一致路径
强一致适合核心正确性路径。例如支付、余额、库存、优惠券核销、权限变更。设计上可以选择:
- 使用支持事务的数据库作为主写模型。
- 使用单分区事务。
- 使用条件写入。
- 使用乐观锁版本号。
- 使用唯一约束服务。
一些 NoSQL 数据库支持条件更新。例如只有当版本号匹配时才更新:
UPDATE item
SET stock = stock - 1, version = version + 1
WHERE id = ? AND stock > 0 AND version = ?
具体语法因数据库不同而异,但思想一致:让并发冲突在写入点被检测。
最终一致路径
最终一致适合读模型、搜索索引、统计、推荐、缓存、消息通知等。它们可以短暂落后,但需要可恢复。
典型模式:
- 主数据写入成功。
- 产生事件。
- 异步消费者更新读模型。
- 失败进入重试或死信队列。
- 定期校验和补偿。
最终一致不是“丢给消息队列就完事”。必须设计幂等、重试、顺序和补偿。
幂等设计
分布式系统中,重试不可避免。没有幂等,重试就可能造成重复扣款、重复发货、重复通知。
幂等常用方式:
- 请求唯一 id。
- 业务唯一键。
- 状态机约束。
- 去重表或去重集合。
- 版本号或事件序号。
例如订单状态只能从 created 到 paid,不能从 shipped 回到 paid。状态机比简单布尔字段更容易维护正确性。
读己之写
最终一致系统中,用户刚提交修改后立即刷新页面,可能读到旧数据。这会造成体验问题。常见解决方式:
- 写后短时间读主库。
- 客户端保留本地提交状态。
- 使用 session consistency。
- 返回写入结果作为页面展示来源。
- 对关键接口使用强一致读取。
一致性不只是后台问题,也会直接影响用户感知。
冲突解决
多主写入或离线同步场景中,冲突不可避免。冲突解决策略包括:
- last write wins。
- 版本向量。
- CRDT。
- 业务规则合并。
- 人工审核。
last write wins 简单但危险,可能覆盖用户修改。适合低价值、可覆盖字段,不适合资金、库存和合同数据。
Saga 与补偿
跨多个系统的长事务通常不能依赖传统数据库事务。Saga 把长事务拆成多个本地事务,并为每一步设计补偿动作。
例如下单流程:
- 创建订单。
- 锁定库存。
- 发起支付。
- 支付成功后确认库存。
- 失败时释放库存并关闭订单。
Saga 的难点是异常路径。每一步都可能成功、失败、超时或结果未知。必须让状态机能表达中间状态,并支持人工介入。
总结
NoSQL 一致性设计不是理论装饰,而是业务正确性的底层工程。把数据路径分为强一致、最终一致和可补偿三类,分别选择数据库能力、消息机制、幂等策略和补偿流程。好的架构不是所有地方都强一致,而是在真正需要正确性的地方绝不含糊,在可以异步的地方用可观测、可修复的方式提升扩展性。
适用场景
适合正在处理 NOSQL、NoSQL, Consistency, Transactions, CAP 相关问题的团队,用于快速建立排查路径和交付标准。
问题背景
NoSQL 系统常在可用性、分区容忍和一致性之间取舍,工程上必须把业务正确性拆成强一致、最终一致和可补偿三类路径。
排查步骤
先确认影响范围和最近变更,再收集日志、配置、指标和链路数据,最后按风险从低到高执行修复。
命令示例
示例命令请替换为你的真实资源名,并使用环境变量保存账号、密码、token 等敏感信息。
风险说明
生产环境操作前需要确认备份、权限边界、变更窗口和回滚路径,避免扩大故障影响。
回滚方案
保留原配置和发布版本;如修复后指标异常,立即回退配置、镜像或数据库变更并复核日志。
交付清单
问题定位记录、关键命令、修复步骤、验证结果、后续优化建议。
遇到类似技术问题?
如果你的服务器、K8s、Docker、CI/CD、数据库或监控系统出现类似问题,可以提交日志和配置文件,我们帮你远程诊断。