短链、派单和票务都可以从单库开始,但十倍流量触发的修改不同。短链需要处理热读与撤销确认,派单需要拆开空间候选与司机归属,票务需要同时核算提交预算和外部扣款协议。复盘应留下旧方案在哪条约束下失效,以及新方案付出的代价。

这三场练习由 AI 执行者各在一个真实持续至少四十五分钟的窗口内完成。记录包含阶段稿、运行源码、正反例输出和约束注入时刻,原稿没有事后替换成最终答案。它们证明书面设计与代码核对过程;真人口述、实际支付渠道和生产吞吐尚未运行。

短链:热读不能绕开撤销

初始范围是创建、重定向、过期与撤销。创建响应丢失后,同一业务幂等键重试应返回同一个 code;同键换 target 要拒绝。撤销确认后开始的新读取不能再返回目标,已经在途的响应和复制出去的 URL 不在此保证内。

基准读取 2000 request/s、创建 20 request/s。按每条元数据 400 B、三十天保留、三份副本,正文为 20×86400×400×30×3=62.208 GB,索引和备份另算。读 p99 100 ms、创建 p99 300 ms 是教学目标,实验没有证明这些性能。

初稿采用单个 SQLite 权威库。创建与幂等映射同事务提交,code 从持久递增编号生成,避免删除后重新使用旧 code。接口是 POST /links、GET /{code}、DELETE /links/{code};重定向必须检查当前状态。单调 code 可枚举,不承担访问控制或不可猜测性。

第 25 分钟后的新增条件是 20000 read/s、90% 请求落在同一个 code,分区中的入口也必须遵守撤销确认,七天内备份恢复不能复活已撤销链接。权威库教学能力为 5000 次点读/s,旧路径超出四倍容量。仅缓存 target 仍需每次核对撤销状态,无法消除这个瓶颈。

修订方案为入口签发一秒读取租约。撤销先写独立持久撤销日志并停止续签,再等待已发租约的最晚失效点及两倍时钟误差界;等待期间返回 202,越过安全点后才确认 204。分区入口到期返回 503,不能拿旧缓存继续返回目标。确认延后换取撤销确认后的严格语义,撤销请求到达与撤销生效是两个时刻。

sequenceDiagram
    participant R as 撤销请求
    participant A as 权威库与撤销日志
    participant E as 持有旧租约的入口
    R->>A: 持久记录撤销并停止续签
    A-->>R: 202 等待旧租约失效
    E->>E: 到期或时钟不可信则拒绝读取
    A->>A: 越过最晚租约到期及误差界
    A-->>R: 204 撤销确认

备份恢复必须先重放撤销日志,再开放读取。超过七天的快照被拒绝,日志缺失不能自动创建一个空日志后继续服务。日志独立持久、完整且可取得是方案前提;本地实验没有实现跨地域共识或完整备份平台。

固定时钟下的 20000 个请求、20 个入口产生 2020 次租约申请。每次申请两次点读,算量约为 4040 次点读。这只是给定输入集的操作计数。若可信时钟误差界不能建立,就禁用租约、逐次查权威状态,超出给定 5000/s 的流量拒绝;此时无法同时承诺全部 20000/s 成功和原延迟目标。

实验核对了创建幂等、正文冲突、实际 HTTP 重定向、提交前后进程终止、分区到期、时钟边界和撤销日志恢复。三个错误租约方案以退出码 2 拒绝:提前确认撤销、忽略时钟误差,以及恢复旧快照时漏掉撤销日志。

派单:空间格子不能成为司机的多个所有者

初始要求是一个司机同时至多持有一个有效邀约,一个订单同时至多关联一个有效邀约。位置允许五秒陈旧,邀约有效期也是五秒;截止时刻等于当前时间即失效。位置索引产生候选,权威状态决定最终邀约和接受。

二十万司机每五秒更新一次,入口为 40000 update/s。每条有效载荷 100 B,约 4 MB/s。只存最新位置的逻辑正文约 20 MB;保留一天两份轨迹则约 691.2 GB,索引和协议开销另计。历史轨迹不是“最新位置”顺手附带的免费能力。

基准为 100 次匹配/s,每个匹配器的教学能力为 300 次决策/s。创建邀约使用业务幂等键,数据库对 live offer 的 driver_id 和 order_id 分别设置唯一约束。接受条件包含邀约状态、司机 generation 和截止时间;时钟在取得写锁后采样,不能用排队前的旧时间判断仍有效。

新增条件把匹配提高到 1000/s,其中 80% 集中在车站格子。司机会在邀约有效期内跨格子移动,取消确认后新的接受必须拒绝。四个空间分区的示例负载为 67,800,66,67,热点仍以 500 次/s 增长积压,平均负载不能证明它安全。

修订把匹配工作按 order_id 分配,候选查询继续按空间索引,司机归属保持在同一权威提交路径。固定输入下五个工作节点的负载为 222,211,211,181,175;失去一个后为 234,263,239,264,均低于给定 300。若要求失去一个节点后利用率仍不超过 80%,算量需要六个节点。哈希分布和单节点能力均需生产压测另证。

跨格子只改变候选索引,不复制司机的写入权。反例让两个空间库各自判定同一司机空闲,确实生成两份 live offer;共享权威路径拒绝第二份。司机的新位置过期时也不能创建邀约,等待数据库锁的时间必须计入位置陈旧和邀约过期判断。

取消在权威事务里使邀约失效,确认后 accept 根据该状态拒绝。旧缓存盲写接受的反例会复活取消,测试保留这个失败结果。事件发送使用事务内 outbox;进程在提交前终止不留下半份邀约,提交后终止可以重发事件,不能凭一次网络发送结果决定资源归属。

flowchart LR
    O[按订单分配匹配计算] --> C[空间索引查询候选]
    C --> A[司机与订单权威提交]
    M[司机跨格子移动] --> C
    X[取消与接受] --> A
    A --> U[唯一约束与条件更新]
    A --> B[事务内 outbox]

这个修改扩大了匹配计算的并行度,尚未测出 SQLite 单写路径在真实 1000/s 下的能力。共享权威路径是本地不变量验证;实际部署还需要按稳定司机身份确定写入归属,并重新验证订单与司机之间的原子关系,不能直接把模型称为已经完成的分布式系统。

票务:先保证座位,再捕获款项

初始范围为余票、五分钟占座、付款与订单查询。每个座位最多销售一次,同一支付键不重复记账。基准占座 500 request/s、余票读取 5000 request/s,活动有五万席,单订单 1 KiB、三份正文约 153.6 MB。占座最多受五万席约束,不能把 500×300=150000 当成实际可用库存。

旧协议占座一次提交、支付入账一次提交。若 500 次占座/s 全部成交,已经需要 1000 次提交/s,超过给定的 800 次本地提交/s。此前把占座请求与提交能力直接比较,会错误地声称基线安全;请求速率、转换率和每单工作量必须分别列出。

新增条件为 5000 次占座/s、90% 集中在热门区域,并要求“实际扣款成功即保证座位”。占座过期并转给新用户之后,旧支付授权或回调仍可能到达。旧方案中的“先扣款,迟到后退款”能做补偿,却不满足新增保证。

新协议要求渠道支持授权与捕获分离、持久幂等键、按键查询以及终态撤销。任一能力缺失就拒绝承诺这个强语义,不能默认第三方渠道具有所需行为。本地 FakeChannel 用另一个 SQLite 库模拟这些能力,没有接入真实资金或网络。

授权意图先持久化,调用渠道授权后,再核对占座持有人、版本与期限。在同一库存事务中把座位置为 PINNED 并保存捕获意图,随后才允许发起捕获。占座已过期或已被其他人持有时只安排撤销授权,不得捕获。

捕获结果未知时继续保留 PINNED,通过相同幂等键查询和恢复;不能按原五分钟占座期限释放它。查询确认捕获成功后,再原子记录 SOLD 与唯一支付账本。安全性会降低未知支付期间的库存可用性,恢复预算和人工核对不能从设计里省略。当前实现没有固定后主动放弃销售并释放 PINNED 的路径;若要增加,只能在渠道终态证明不可能再捕获后释放。

stateDiagram-v2
    [*] --> HELD: 占座提交
    HELD --> FREE: 到期且未固定
    HELD --> PINNED: 授权有效并原子保存捕获意图
    PINNED --> PINNED: 捕获结果未知时查询恢复
    PINNED --> SOLD: 捕获已确认且账本提交

修订后的成功销售路径实际包含四次库存提交:占座、授权意图、固定座位与捕获意图、最终入账。因此 500 次成功销售/s 需要 2000 commit/s,5000 次需要 20000 commit/s,分别为给定能力的 2.5 倍和 25 倍。展示余票的缓存无法减少这些提交。

准入预算暂定 160 次新占座/s;全成交按四次提交算为 640 commit/s,另留 160 给恢复。拒绝、重试和恢复也有成本,这个预算只是教学算量,尚未证明排队服务、公平性或库存库实际吞吐。热门区剩余请求排队或拒绝,不能绕过准入直达库存。

运行场景覆盖同座争抢、重复付款、旧授权到达新占座、截止时刻相等、捕获结果丢失、并发恢复与四个位置的真实进程终止。恢复过程曾出现旧状态误判,原始失败记录保留,修复后以确定性交错复验;不能只保留最终成功输出。

时间记录怎样支持复盘

题目 开始 UTC 45 分钟阶段 UTC 该阶段经过时间
短链 12:30:22.957 13:15:32.335 2709.361 s
派单 12:30:28.496 13:15:46.241 2717.745 s
票务 12:33:30.714 13:21:35.157 2884.425 s

阶段时间来自 UTC 与单调时钟;应用测试里的逻辑时间单独记录。0 分钟保存起始时钟,初稿及后续阶段按实际时间保存;派单初稿在第 57.377 秒落盘,票务初稿在第 175.014 秒落盘。检查点存在工具往返造成的偏差,收据保留计划时间与实际采样时间。派单首次 40 分钟快照提前 10.013 秒,原稿保留,另补达到四十分钟后的核验快照。

三类题目的已有参考稿对执行者可见,这不是盲测;父任务在初稿冻结后追加新的约束组合。部分阶段采样和约束持久记录晚于计划点,例如短链 40 分钟采样晚 64.486 秒,票务 45 分钟阶段晚 184.425 秒。票务最终封存为 48 分 31.505 秒,超过四十五分钟预算;这些偏差降低严格限时练习的可比性,不能删除它们后声称每场都在预算内完成。

三场都有实际设计、编程、失败调查与运行记录。四十五分钟窗口不能只由等待计时器成立,也不证明人的现场表达能力。原计划要求三题各做一次限时设计并记录约束改变;真人口述可按相同题目另做,当前状态仍为 NOT_RUN。

单独运行容量检查:python3 -B examples/system-design/labs/35/run.py。它只检查议程、工作单位和容量反例,明确 script_performs_actual_45min_sessions=false,不承担三场计时的证据。三场权威记录在 examples/system-design/evidence/35/session-shortlink/、session-dispatch/、session-ticket/,含实际命令、源码 SHA256、退出码和阶段快照。

实验附件与导航

本页容量附件使用 Python 3.14.4;三场本地事务实验使用 SQLite 3.51.3。历史环境输出保留其原版本,各类教学能力值没有改写成性能测量。完整时间记录与源码包包含失败反例和修复轨迹。

容量核算源码 · 容量原始结果 · 容量运行收据 · 三场源码与原始记录

系列导读;短链的创建与撤销。