ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

system-design-notes第27章:设计数字钱包(Digital Wallet)完整指南

system-design-notes第27章:设计数字钱包(Digital Wallet)完整指南 system-design-notes第27章设计数字钱包Digital Wallet完整指南【免费下载链接】system-design-notesNotes of the book System Desgin Interview - An Insiders Guide项目地址: https://gitcode.com/GitHub_Trending/sy/system-design-notes这是开源笔记system-design-notes《System Design Interview》一书的中英对照笔记第 27 章的完整解读设计数字钱包Digital Wallet。本章围绕支撑 100 万 TPS 的钱包转账系统这一高难度系统设计方案带你彻底搞懂分布式事务、事件溯源Event Sourcing、Raft 复制与 CQRS 等核心概念是准备系统设计面试的一份完整指南。数字钱包是支付平台的核心组件用户把资金存入应用内可随时提现、消费或转账。相比传统支付通道钱包间转账更快、成本更低。本章的面试场景目标是✅ 支持两个账户之间的余额转账✅ 支撑100 万 TPS的吞吐量✅ 99.99% 可用性 事务性保证✅ 支持重放历史、可审计而不只是事后对账一、容量估算为什么单靠关系型数据库不行云上一个传统关系型数据库大约能支撑1000 TPS。而每笔转账涉及两个账户两条腿实际上需要200 万 TPS。设计目标就变成提升单节点吞吐从而减少节点数量 单节点 TPS所需节点数10020,0001,0002,00010,000200二、数字钱包高层设计内存分片 分布式事务钱包服务的核心数据结构是一个mapuser_id, balance。用内存 KV 存储如 Redis 集群承载余额按accountID.hashCode() % 分片数做分片Zookeeper 保存分片数与节点地址无状态钱包服务水平扩展![数字钱包系统高层设计内存分片与无状态钱包服务](https://raw.gitcode.com/GitHub_Trending/sy/system-design-notes/raw/9d8388721e7231442763ad37398b8d82224aa68f/27. Digital Wallet/images/wallet-service.png?utm_sourcegitcode_repo_files)但方案有个致命伤无法原子地执行跨账户转账A 扣款成功、C 加款失败怎么办。这就引出了本章的重头戏——分布式事务。完整推导过程见 27. Digital Wallet/README.md。2PC 两阶段提交经典方案及其短板协调者钱包服务向所有数据库发起prepare全部返回 yes 后统一 commit否则统一回滚![数字钱包分布式事务中的2PC两阶段提交协议](https://raw.gitcode.com/GitHub_Trending/sy/system-design-notes/raw/9d8388721e7231442763ad37398b8d82224aa68f/27. Digital Wallet/images/2pc-protocol.png?utm_sourcegitcode_repo_files)缺点很明确锁竞争导致性能差、协调者是单点故障。TC/CTry-Confirm/Cancel 补偿式两阶段TC/C 是 2PC 的变体核心区别在于每个阶段都是独立的可提交事务失败时用补偿事务反向冲正Try 阶段A 的数据库扣 $1C 的数据库执行 NOP什么都不做Confirm 阶段两边都 yesA 执行 NOPC 加 $1Cancel 阶段任一失败A 回补 $1C 执行 NOP![数字钱包TC/C协议的Try阶段A扣款、C执行NOP](https://raw.gitcode.com/GitHub_Trending/sy/system-design-notes/raw/9d8388721e7231442763ad37398b8d82224aa68f/27. Digital Wallet/images/try-phase.png?utm_sourcegitcode_repo_files) 两个关键细节恢复中间状态协调者宕机后可通过原子更新的 phase status table记录事务 ID、各阶段状态、乱序标记恢复短暂不一致转账在途时账户总额会短暂失衡但只要永远先扣后加、且中间状态不可被消费就能保证安全![数字钱包转账过程中的短暂失衡状态示意](https://raw.gitcode.com/GitHub_Trending/sy/system-design-notes/raw/9d8388721e7231442763ad37398b8d82224aa68f/27. Digital Wallet/images/unbalanced-state.png?utm_sourcegitcode_repo_files)TC/C 与 2PC 的本质差异第一阶段第二阶段成功第二阶段失败2PC事务未完成全部提交/回滚全部回滚TC/C事务已落定执行新的补偿/确认事务反向冲正已提交的事务Saga微服务架构的标准答案Saga 把转账拆成线性执行的独立本地事务序列任一步失败则用补偿操作逐步回滚![数字钱包Saga分布式事务顺序执行与补偿回滚](https://raw.gitcode.com/GitHub_Trending/sy/system-design-notes/raw/9d8388721e7231442763ad37398b8d82224aa68f/27. Digital Wallet/images/saga.png?utm_sourcegitcode_repo_files)协调方式有**编排Orchestration和编舞Choreography**两种钱包系统通常选编排模式。TC/C 支持并行、Saga 只能线性——延迟要求低就选 TC/C这是二选一的决策依据。推导细节可对照 README.md 分布式事务章节。三、事件溯源让数字钱包可审计、可重放审计场景下要回答三个问题任意时刻的余额是多少历史余额如何验证正确代码改动后如何证明逻辑没坏事件溯源Event Sourcing一次解决![数字钱包事件溯源模型命令、事件、状态与状态机](https://raw.gitcode.com/GitHub_Trending/sy/system-design-notes/raw/9d8388721e7231442763ad37398b8d82224aa68f/28. Stock Exchange/images/event-sourcing.png?utm_sourcegitcode_repo_files)四个核心概念概念说明Command 命令真实世界的意图动作如A 转 $1 给 C进入 FIFO 队列如 Kafka可以失败Event 事件系统中已发生的事实同样有序入队不可变State 状态事件作用后的结果即账户余额 KV 表State Machine 状态机校验命令、把事件应用到状态上必须确定性执行钱包服务的完整事件溯源流水线![数字钱包服务事件溯源状态机命令队列到余额更新](https://raw.gitcode.com/GitHub_Trending/sy/system-design-notes/raw/9d8388721e7231442763ad37398b8d82224aa68f/27. Digital Wallet/images/wallet-service-state-macghine.png?utm_sourcegitcode_repo_files)可重放性是事件溯源的最大红利事件列表不可变 状态机确定 ⇒ 从任意起点重放都能精确复现余额审计问题迎刃而解![数字钱包历史状态重放从事件列表重建任意时刻余额](https://raw.gitcode.com/GitHub_Trending/sy/system-design-notes/raw/9d8388721e7231442763ad37398b8d82224aa68f/27. Digital Wallet/images/historical-states.png?utm_sourcegitcode_repo_files)用户查询余额则交给CQRS多个只读状态机基于同一份不可变事件列表提供查询读写彻底分离![数字钱包CQRS架构写状态机与只读状态机分离](https://raw.gitcode.com/GitHub_Trending/sy/system-design-notes/raw/9d8388721e7231442763ad37398b8d82224aa68f/27. Digital Wallet/images/cqrs-architecture.png?utm_sourcegitcode_repo_files)四、性能深挖mmap RocksDB 快照要冲 100 万 TPS外部队列和数据库的网络开销太大优化三板斧mmap命令与事件写入本地磁盘append-only 天然快并由 OS 页缓存驻留内存一举省掉网络延迟和手动缓存![数字钱包mmap优化本地磁盘写入与内存缓存](https://raw.gitcode.com/GitHub_Trending/sy/system-design-notes/raw/9d8388721e7231442763ad37398b8d82224aa68f/27. Digital Wallet/images/mmap-optimization.png?utm_sourcegitcode_repo_files)RocksDB 存状态LSM 树结构对写操作优化极佳读靠缓存加速定期快照把状态快照存到 HDFS 等分布式存储重放时从最近的快照开始而非从头再来。五、可靠性与扩展Raft 复制 分片 Raft 组本地化优化让服务变成了有状态必须引入复制。关键洞察只有事件列表需要高可靠——状态和快照都能从事件重放生成而命令是非确定的、不可用来再生事件。用Raft复制事件列表leader 负责写入followers 被动同步多数节点存活即系统可用![数字钱包事件列表的Raft复制leader与follower同步](https://raw.gitcode.com/GitHub_Trending/sy/system-design-notes/raw/9d8388721e7231442763ad37398b8d82224aa68f/27. Digital Wallet/images/raft-replication.png?utm_sourcegitcode_repo_files)单 Raft 组容量有限最终方案是分片为多个 Raft 组组间用 TC/C 或 Saga 编排分布式事务Saga 协调器在 phase status table 中全程跟踪事务状态![数字钱包分片Raft组最终架构多Raft组加Saga协调器](https://raw.gitcode.com/GitHub_Trending/sy/system-design-notes/raw/9d8388721e7231442763ad37398b8d82224aa68f/27. Digital Wallet/images/sharded-raft-groups.png?utm_sourcegitcode_repo_files)一笔转账的完整生命周期协调器创建追踪记录 → 路由到对应分片 → 该分片 Raft leader 校验命令并生成事件、组内复制 → 只读状态机同步后推送结果回协调器 → 处理下一腿 → 通知客户端 ✅六、实时体验反向代理 主动推送CQRS 的请求/响应流有个体验问题客户端得不断轮询查询服务既不实时又加重负载。分两步解决引入反向代理代替用户批量轮询一次请求可捎带多个用户的查询结果只读状态机在结果就绪后主动 push回反向代理用户获得实时更新的体感。![数字钱包反向代理与只读状态机推送响应](https://raw.gitcode.com/GitHub_Trending/sy/system-design-notes/raw/9d8388721e7231442763ad37398b8d82224aa68f/27. Digital Wallet/images/reverse-proxy.png?utm_sourcegitcode_repo_files)七、总结设计演化路线图 阶段方案解决的问题遗留问题1内存 Redis 分片高吞吐数据不持久、转账不原子2关系库 2PC/TC/C/Saga原子转账2PC 慢、难审计3引入事件溯源可审计、可重放外部存储性能瓶颈4mmap RocksDB 快照单节点高性能有状态后缺持久性5Raft 复制数据不丢、无单点单组容量上限6CQRS 反向代理推送实时查询体验—7分片 Raft 组 TC/C/Saga100 万 TPS 最终达成—本章核心记忆点数字钱包设计的灵魂是先扣后加 补偿事务 事件溯源重放——前者保一致后者保可信。八、延伸阅读本章完整笔记27. Digital Wallet/README.md事件溯源与 CQRS 详解README.md#L244-L309分布式事务三种方案对比README.md#L92-L242性能与可靠性深挖mmap/RocksDB/RaftREADME.md#L313-L365配套架构图目录27. Digital Wallet/images/【免费下载链接】system-design-notesNotes of the book System Desgin Interview - An Insiders Guide项目地址: https://gitcode.com/GitHub_Trending/sy/system-design-notes创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表