为卖家账单建立镜像表时,如何保证买家表和卖家表双写一致?
未标记
考查重点:可靠投影与双表收敛。权威事务写 outbox,可靠投影卖家表,按版本幂等更新并对账
本题目录
参考答案
本答案基于相关资料,由 AI 辅助编写,供学习与面试准备参考。如有疏漏,欢迎反馈指正。
核心回答
若卖家账单表是订单权威数据的查询投影,我会用“本地事务记录订单与待发送事件,可靠投递后幂等更新投影,再持续对账”的方案实现最终一致。只在业务代码里先写买家表、再写卖家表,两次独立提交之间总有一边成功、另一边失败的窗口。
若两表确实在同一数据库事务内,可直接用本地事务原子提交;跨库且要求立即强一致,则需要评估分布式事务及其延迟、可用性成本。不能把异步投影说成两表任何时刻都完全相同。
Outbox 怎样补上可靠交接
- 在买家订单所在数据库的同一个本地事务中,更新订单并写入
outbox,保存事件标识、订单标识、业务版本与变更内容。 - 投递进程或
CDC从已提交事件中发送消息,投递失败可重试;发送后标记也可能丢失,因此按至少一次交付设计消费者。 - 卖家库在同一事务中完成去重记录和账单更新。使用事件唯一约束防重复,按订单业务版本阻止旧事件覆盖新状态,提交后再确认消息。
- 监控投影延迟、失败与死信,并按订单版本或校验摘要对账修复。
flowchart TD
subgraph T["买家订单库:同一本地事务"]
B["更新权威订单"] --- O["写入 outbox 事件"]
end
O -->|"仅投递已提交事件"| R["投递进程或 CDC"]
R -->|"可重试,可能重复"| M["消息队列"]
M --> C["卖家库事务:事件去重、版本检查、更新账单"]
C -->|"事务提交后"| A["确认消息"]图中的两个本地事务各自原子提交;消息传递期间允许投影暂时落后,失败后通过重试和对账收敛。
事件只包含增量时,不能随意跳过中间版本,否则可能漏算。若采用“只接受更高版本”的覆盖策略,事件应包含足以重建该行的完整状态,或检测版本缺口并回查权威数据。
订单查询还要考虑哪些边界
镜像表保留卖家查询需要的字段和索引,明确一次订单是否包含多个卖家、拆单后使用哪个业务标识。删除和撤销也要携带版本或保留墓碑,避免旧消息将已撤销记录重新创建。
首次构建需要一致的全量基线与增量衔接,再切换查询流量。投影落后时可以展示更新时间、稍后重试,或对少量关键记录回查权威订单;读取哪种结果是产品契约的一部分。
MQ、CDC 和重试都不能单独保证业务一致性。权威事务、可靠事件、投影幂等、乱序处理和对账共同形成完整链路。
参考资料
- 国内:JavaGuide:分布式事务:采用本地消息表、可靠交接与最终一致的职责划分。
- 国内:阿里巴巴:Canal工作原理:核对通过数据库变更日志取得已提交变化的
CDC链路;CDC不代替投影幂等和对账。 - 国内:阿里云:消息幂等:采用业务唯一标识处理重复发送与重复投递,区分消息标识和业务动作。
- 国内:Leo(编程导航):接口幂等性:参考唯一索引识别重复写入的做法,说明投影消费者需要去重约束,并将去重记录与账单更新一起提交。
- 国外:AWS:Transactional outbox pattern:采用权威数据与事件同事务提交,消除双写窗口,并考虑重复消息与顺序。
- 国外:MySQL 8.4:事务提交与回滚:核对单库事务的原子提交边界,说明跨库两次独立写入不在同一本地事务内。
相关面经
1 篇阿里巴巴
AI 全栈开发工程师一面
深分页与卖家账单查询深分页和卖家账单查询的场景,你觉得有哪些要优化的?给订单系统做商家纬度账单查询,order 表分库分表,用卖家来查,近三个月或近六个月,很多条件。首先有深分页问题,深分页怎么优化?第二是这种卖家纬度的查询怎么去支持?(追问·深分页·游标)游标跳页的查询也支持吗?从第一页跳到第五页。(追问·深分页·跳页)账单查询并不像刷抖音一样,有一到十可以选择中间任何一页,你觉得这个方法能用吗?(追问·深分页)跳页怎么办呢?(追问·卖家表)你说卖家表,下单时把买家表落了以后,单独搞一个卖家表落买卖家 id 和买家表业务单号,查的时候查那个卖家表?(追问·卖家表)分页时每页查 200 条,卖家表查 200 个 id,再散到买家库查 n 个库,查 200 次,再聚合?(追问·卖家表)买家的所有字段你都落吗?相当于镜像表一模一样的字段,分表键换了一个?(追问·卖家表)两张表是双写吗?下达时都写上是吧?(追问·卖家表)写入开销小的话,怎么保证事务?A 成功 B 失败怎么办?(分布式事务)
