unified - map
13. 大一统:十二个思想在四大件和技术栈里的复现总图
0. 本章先解决什么问题
前十二章每章追一个思想。本章做收拢:把十二个思想钉进一张总图,把它们之间的咬合线画出来,再用三个没讲过的新技术做落格练习,验证这张图真的能把”学一个新中间件”的成本从全量压到增量。
这张图怎么读
十二个格子分三行:存储侧、计算侧、分布式侧。每格写着思想名和两三个代表实例。所有格子共同的地基是三条硬件事实:延迟阶梯、顺序快于随机、传输按块。
1. 三条硬件事实:所有思想的共同地基
十二个思想没有一个是凭空聪明,全部是对三条物理现实的应对。成本模型 建立过这套语言,压缩成三行:
- 延迟阶梯: L1 约 1 ns,内存约 100 ns,SSD 约 100 us,
跨机房毫秒级。相邻层差两三个数量级 - 顺序快于随机: 机械盘差数百倍,SSD 和内存(预取、缓存行)同样受益
- 按块传输且有固定成本: 磁盘按扇区,内存按缓存行,网络按报文,
摊薄固定成本只能靠一次多带
对应关系一眼可辨:缓存和池化对付第 1 条,日志和不可变文件对付第 2 条,定长块和批处理对付第 3 条;分布式侧的四个思想对付的是第四条更狠的现实,跨机器之后消息会丢、会迟、会乱序,而机器本身会死。
2. 总表:十二章各自的一句话
| # | 思想 | 一句话内核 | 本书章节 | 代表实例 |
|---|---|---|---|---|
| 1 | 事件驱动 | 等待集中给内核,就绪才分发 | 01 | epoll、Redis ae、Netty |
| 2 | 定长块 | 按固定大小块分配搬运缓存 | 02 | 16 KB 页、4 KB 页、Kafka 段 |
| 3 | 缓存分层 | 小快存储挡大部分访问 | 03 | buffer pool、Redis、CDN |
| 4 | 日志先行 | 随机改写成顺序追加 | 04 | redo、AOF、Kafka |
| 5 | 副本复制 | 送日志到别处重放 | 05 | binlog 复制、PSYNC、ISR |
| 6 | 多数派 | 过半集合必有交集 | 06 | Sentinel、Raft、MGR |
| 7 | 分片 | route(key) 决定数据去哪 | 07 | 16384 槽、分库分表、partition |
| 8 | 间接层 | 名字和位置解耦 | 08 | 页表、DNS、代理、AOP |
| 9 | 池化复用 | 贵的东西造好了别扔 | 09 | 线程池、HikariCP、内存池 |
| 10 | 写时复制与多版本 | 共享读,写时才付钱 | 10 | fork、MVCC、COW List |
| 11 | 批处理 | 攒一批摊固定成本 | 11 | 组提交、pipeline、攒批 |
| 12 | 惰性与摊销 | 大代价拆碎或推迟 | 12 | 渐进 rehash、过期删除 |
3. 思想不是并列的,是嵌套咬合的
总表容易给人”十二个独立工具”的错觉,实际它们咬得很紧。四条咬合线,每条都在前面的章节里出现过,这里连成网:
- 日志线:日志(4)是复制(5)的载体,复制进度决定选主(6)里谁上位,
选主的多数派同时保护复制的提交点(Raft 里两者共用一个过半),
纪元编号再把旧主的日志封印 - 块与缓存线:块(2)是缓存(3)的搬运单位,buffer pool 的脏页靠日志(4)兜底,
刷脏是批处理(11),页的非原子写靠 doublewrite 补丁,
删除的空间靠惰性(12)的 purge 慢慢收 - 间接与分片线:分片(7)的槽位表是一层间接(8),
间接层的翻译表本身是缓存(3),MOVED 就是缓存失效通知,
smart client 的本地槽表又是池化(9)之外另一种”客户端持有资源” - 快照线:BGSAVE 的快照靠写时复制(10),fork 出来给复制(5)做全量,
rehash(12)在快照期间提高扩容阈值以忌惮 COW 的内存账,
AOF 重写(4)又用同一个 fork
所以拿到新系统时最有信息量的问题往往是跨格子的:它的日志同时用来做恢复和复制吗?它的间接层缓存在哪、怎么失效?它的摊销把尖刺转移给谁了?它的快照撞上写高峰会发生什么?
4. 第十三条线索:幂等与重试
有一条线索贯穿全书但没有自己的章节,在收尾处必须点破。第 5 章的复制可能重放、第 6 章的切换窗口可能重发、第 11 章的整批重试可能重复投递,它们把同一个问题推给了使用者:
消息可能重复到达,操作必须经得起重做。
TCP 用序号去重(协议层内置幂等)
MQ 的”至少一次”投递 + 消费端幂等(业务唯一键、去重表、
MQ高级 里的方案全在做这件事)
HTTP 的幂等方法约定(GET/PUT 幂等,POST 不幂等所以要防重提交)
支付系统的幂等号、上一章 JDBC 批量重试的插入冲突处理
第 6 章的 fencing token 也是它: 拒绝旧时代的重放
规律:分布式世界里”恰好一次”几乎总是”至少一次 + 幂等”拼出来的。看到任何重试逻辑,下一个问题永远是”重复了怎么办”。
5. 落格练习:三个没学过的系统
拿三个前面没展开的东西验证总图的可用性。
5.1 Elasticsearch
translog -> 日志先行(4)
倒排索引段不可变 + 段合并 -> 不可变文件(10) + 摊销(12)
refresh 攒一秒才可见 -> 批处理(11)
hash(_routing) % 主分片数 -> 分片(7)
primary/replica -> 复制(5)
master 节点选举 -> 多数派(6)
filesystem cache 依赖 -> 缓存(3)
真正要新学的增量: 倒排索引结构本身、打分、DSL
5.2 RocksDB / LevelDB
WAL + memtable -> 日志先行(4) + 批量刷盘(11)
SSTable 不可变 + compaction -> 不可变(10) + 摊销(12)
block cache + 定长 block -> 缓存(3) + 定长块(2)
布隆过滤器挡无效读 -> 第 3 章穿透方案的同款零件
真正要新学的增量: 层级 compaction 策略、读写空间放大的调参
5.3 etcd
Raft 日志 -> 日志(4) + 复制(5) + 多数派(6) 三合一
watch 机制 -> 事件驱动(1)
租约 lease 心跳 -> 第 6 章的判死机制
boltdb 的 B+ 树与页 -> 定长块(2)
MVCC 多版本键 -> 多版本(10)
真正要新学的增量: Raft 的工程细节(日志压缩、成员变更)
三个都没学过的系统,落完格七成机制是旧知识,剩下三成才要真花力气。这就是总图的用途:把新技术拆成”落在哪几格”加”真正新增的部分”,学习成本从全量变增量。
6. 怎么背这张图
不用背十二个名词,记三层结构就够:
底层: 三条硬件事实(延迟阶梯、顺序优先、按块有固定成本)
中层: 每条事实对应两三个应对套路
顶层: 每个套路在自己章节里有一个”参考实现”
(epoll、16 KB 页、buffer pool、redo、binlog 复制、
Sentinel、16384 槽、页表、ThreadPoolExecutor、
fork、组提交、渐进式 rehash)
从参考实现出发横向类比,比从定义出发背名词牢固得多
7. 学完本章你能解决什么问题
- 三条硬件事实分别催生了哪几个思想?
- 四条咬合线各自串起哪几章,为什么说思想是嵌套的?
- “恰好一次”在分布式里通常怎么拼出来?
- 拿到新中间件,落格的顺序和跨格问题清单是什么?
- ES 的 refresh、RocksDB 的 compaction、etcd 的 lease 各落在哪格?
核心一句话:硬件只有三条事实(外加分布式的”消息不可靠、机器会死”),应对只有十二个套路,产品是套路的排列组合;学新技术先落格,落不进去的部分才是真正的增量,而跨格的咬合处往往藏着系统最深的设计。