四个坏掉的瞬间 —— 时间尺度 / 空间死结 / 冲突时机 / 规模效应,每个都回到真机日志与官方口径,逐字可对
dev/probe/ 与 dev/cloud-evidence/ 的原始输出里逐字找到,并由
dev/pathology-check.js 机器比对(找不到就报错)。本页为静态快照,零真机依赖,断网可看。
监控红线 20 秒就报警,业务方却问"怎么 9 分钟才恢复满配"。这两个数说的不是同一件事 —— 剖开看。
dev/probe/fr1-failover-replica.txt 的关键时刻表,可逐行对。
6 → 5 → 4 → 2 → 1 → 0 一批批搬走,
不是一次搬完。这段时间里写入探针 95/95 次全部成功 —— 时间尺度的"长",不等于服务的中断;
但迁移期间副本数在最低点是 2(欠一份),这段窗口里再坏一台就是数据风险 —— 这才是"8 分 44 秒"真正值得盯的原因。
同一场景的官方机制描述:心跳丢失 → Disconnect → 超过 max-store-down-time → Down → 在存活 store 上补足副本,本实验的 down-time 见病理 02 的账本行。
2026-09-20 的 r1 实验:想把 3 店集群缩容到 2 店,命令被 PD 直接拒绝;同一天另一条线上,停 1 台店后"补副本没有候选"。两条线撞的是同一堵墙。
store delete 4 发出去,PD 在入口就拒绝 —— 不是"进去以后卡住",是根本不让进。
拒绝原文(r1 实验 · 真机):
2026-09-19 的 r2 实验:两个事务改同一行,乐观模式下 UPDATE 双双返回成功,提交时第二个被 9007 拒绝。剖开这个"时机差"。
(2,) ——
说明 B 这次的加一没有写进去,也没有把 A 的覆盖掉;
随后 B 重试提交成功,重试后的值是 (3,) —— 两次加一最终都生效,一次都没丢。
两行收尾终值 ((1, 3), (2, 1)) 与逐步读数逐条吻合。
实验二里 B 的 3.006 秒只是一个标本:两个事务、抢一行。把标本放进"热点行 × 高并发"的培养皿,才是这个病理真正要防的东西。
waited=3.006s。
单点、单行、两个事务,3 秒不是病:这是悲观模式用顺序化换正确性的正常代价。
@@tidb_txn_mode = pessimistic、@@innodb_lock_wait_timeout = 50(真机读值)。
也就是说:default 配置下,取锁、排队、等待(上限 50 秒)是正常的常态机制,不是异常状态。
而等待是串行队列:同一行的写者一个接一个,先来先得 —— 队列里每个人的等待,都会被前一个人的持锁时长直接决定。
waited=3.006s 这一个点,其余是机制推演 —— 两者不允许混着读。
这一节原本列出四条「画了但没跑」的断言。09-25 云集群上,B1–B4 四条已逐个转成实测(下方绿色标记的兑现记录);B4(TSO 分配开销)兑现的是机制(批合并与时间戳对账),不是性能。所有条目继续保留「当时为什么没跑」的原记录 —— 边界被补掉的过程,也是证据的一部分。
prune 日志出现 RemoveTomestoneNodesInPD / Destroy success;② 重新上线后用 pd-ctl store delete 手动下线:12:44:43.766 采样器首次读到 "tombstones": [1058],终态 display 保留 10.206.16.14:20160 tikv 10.206.16.14 20160/20180 linux/x86_64 Tombstone 一行。SHOW TABLE REGIONS 解析)。正例:一个事务改两行,提交后 CROSS-A / CROSS-B 同时可见;反例:第二行撞锁拿 ERROR 1205 (HY000) at line 1: Lock wait timeout exceeded; try restarting transaction,第一步虽已执行,id=300000 仍回滚为原值 —— 无部分提交。data_lock_waits 里直接读出锁键 KEY: 7480000000000000725F7280000000000003E8 与 "handle_value":"1000"(锁的就是那一行),左邻 id=999 / 右邻 id=1001 的更新各 real 0m0.009s / real 0m0.008s 返回、不被阻塞;范围 BETWEEN 1000 AND 1005:范围内 id=1003 被挡(1205),范围外 id=2000 real 0m0.009s 通过。dev/cloud-evidence/)。已兑现的条目保留「当时为什么没跑」的原记录,不删 ——
边界被补掉的过程,也是证据的一部分:
知道什么没做,和知道什么做了一样重要。
三个等级分开标注:实测 来自真机原始输出;实验设置 是人为调过、用后回滚的参数;推导 未经实测;官方未列明 的写法本作品一个字都不写。
| 结论 | 等级 | 可对账处 |
|---|---|---|
| 停机后 15 秒检出 Disconnected(官方口径为"超过 20 秒",两口径并列见病理 01) | 实测 | fr1-failover-replica.txt · 10:40:28 行 |
| 判死 Down 距停机 117 秒(max-store-down-time 临时由 30m 调为 2m,实验后已回滚) | 实测 实验设置 | fr1-failover-replica.txt · 10:42:08 行 |
| 失效副本迁移 8 分 44 秒,分批搬离(6 → 5 → 4 → 2 → 1 → 0) | 实测 | fr1-failover-replica.txt · 关键时刻表 |
| 迁移与判死全程写入探针 95/95 次成功 | 实测 | fr1-writes.jsonl · 95 行 |
| 副本归位完成:存活店合计 21/21(store4 清零) | 实测 | fr1-failover-replica.txt · 10:50:56 行 |
| 恢复后 20 秒重新上线 · 14 秒收到第 1 个副本 | 实测 | fr1-failover-replica.txt · 10:51:23 / 10:51:37 行 |
| 迁移机制为整体搬移:mv peer: store [4] to [5](总数恒 21) | 实测 | fr1-failover-replica.txt · 机制发现 2 |
| 3 店缩容被拒:can not remove store 4 since the number of up stores would be 2 while need 3 | 实测 | r1-offline.txt · store delete 段 |
| 乐观冲突在 COMMIT 暴露:reason=Optimistic [try again later] | 实测 | r2-txn.txt · 实验一 |
| 悲观等锁时长 waited=3.006s | 实测 | r2-txn.txt · 实验二 |
| 被拒不丢更新:重试后 (3,)、两行终值 ((1, 3), (2, 1)) | 实测 | r2-txn.txt · 实验三 / 收尾 |
| 选举超时参数 = 10 tick × 1s = 10 秒(换算,非实测) | 推导 | spec.js · raft-base-tick-interval / raft-election-timeout-ticks |
| 故障到新 Leader 就绪的端到端时长 —— 官方未给出 | 官方未列明 | spec.js · leader-fail-e2e |
| 798 扩容:Up 后 4 分 34 秒承接 74 个 Region,其后 179 个采样点稳定在 74 | 实测 | cloud-evidence/samples.jsonl · 12:07:58–12:13:55 |
| TiUP 原生下线:Offline 后 20 秒搬空,prune 报 RemoveTomestoneNodesInPD / Destroy success(13 → 12 节点) | 实测 | cloud-evidence/samples.jsonl · _cloud_prune.txt |
| pd-ctl 手动下线:12 秒归零、25 秒后进入 Tombstone,终态 display 保留 Tombstone 行 | 实测 | cloud-evidence/samples.jsonl · final-state.txt |
| 跨 Region 两行事务被 1205 挡下后整体回滚(无部分提交);FOR UPDATE 点查只锁目标行(邻行 9ms / 8ms 通过) | 实测 | cloud-evidence/b2b3-txn.txt · B2-2 / B3-1 |
| TSO 批合并:并发窗平均批 1.092 vs 串行窗 1.010(batch≥2 的批次 +2525 vs +45);两次时间戳都经 PD 分配 | 实测 | cloud-evidence/tso-b4-20260925-144942.txt · 本底扣除法 |
| 锁等待的自我放大链条(队列 × 持锁时长 × 重试回流) | 推导 | 本页病理 04 · 未做压测 |
real 0m0.008s,再到 B4 的 batch≥2 直方图)由
dev/pathology-check.js 与 dev/probe/ / dev/cloud-evidence/ 原文逐字比对 —— 页面值必须在原始日志里逐字命中,否则构建不绿;
同一份脚本还反向检查本页不得出现任何未经标注的性能数字(本作品未做压测)。
dev/pathology-check.js 与 dev/probe/ / dev/cloud-evidence/ 原文逐字比对,找不到即报错。
三个等级分开标注:实测 实验设置 推导 —— 推导不是实测,不允许混着写。