在经历了这个系列前四篇对生态定位、客户端流转与可靠性保障的深度推演后,我们终于触及了整个 Kafka 架构蓝图中最深邃、也最令底层研发者着迷的水域——性能底座。回顾之前的链路:核心原理、Producer、Consumer、可靠性与 EOS。现在,是时候拼上最后一块架构拼图了。
业界常常存在一种根深蒂固的疑惑:重度依赖普通物理磁盘的 Kafka,凭什么能在极其苛刻的高并发生产环境中跑出百万级甚至更高的吞吐,并且在诸多指标上直接碾压了部分基于内存的中间件?
要回答这个问题,我们无需去寻找什么深奥的黑魔法。其底层逻辑,实际上是建立在顺序追加写、页缓存、零拷贝以及日志分段这四个极其朴素却又被压榨到极致的架构取舍之上的。结合端到端的批量与压缩机制,Kafka 构筑了一条严丝合缝的数据高速公路。本篇,我们将卸下外围的封装,直击其 IO 流转的内核,带你彻底看透所谓“把日志顺序化、状态客户端化、并行分区化”背后的终极奥义。
TL;DR
- 顺序追加写:Kafka 主动剥离了局部数据的随机修改能力,坚守纯粹的 append-only 日志模型。这一架构上的退让,成功将高昂的磁盘随机寻址成本降维成了纯粹的顺序 IO 流,使普通机械磁盘的持续吞吐亦能逼近物理线速。
- 页缓存 (Page Cache):Kafka 极度克制地摒弃了复杂的应用层内存池管理,将数据缓冲的生命线全权托付给 OS 内核态的 Page Cache。此举不仅完美避开了 JVM 堆内存所带来的灾难性 GC 停顿与双重缓存损耗,更为应对进程崩溃提供了一道坚不可摧的内存兜底防线。
- 零拷贝 (Zero-copy /
sendfile):在应对下游的追尾消费时,系统通过调用底层的sendfile机制,让热数据直接在内核态中从 Page Cache 跃迁至网卡驱动。全程封杀任何无意义的用户态拷贝干预。正因如此,贸然在 Broker 端开启 SSL 加密往往是一场引发零拷贝机制阵亡、进而导致吞吐暴跌的性能灾难。 - 日志分段与稀疏索引:通过将巨型分区有条不紊地切割为多个分段文件,并辅助以基于
mmap的稀疏索引,系统在“基于 Offset 检索历史数据的随机性”与“极致的顺序读写”之间达成了完美的工程折中,同时将过期清理的物理代价降到了冰点。 - 批量与压缩机制:Producer 端的攒批动作极大地摊薄了网络 RTT 与系统调用的基础开销。而 Broker 坚持原样存取压缩批次的铁律,则彻底免除了核心集群冗余的压解压算力消耗,为零拷贝的顺畅执行铺平了道路。
Table of contents
Open Table of contents
1. 一个反直觉的事实:磁盘不一定慢
要勘破 Kafka 的性能底座,我们首先必须纠正一个在工程界流传甚广的技术偏见:磁盘天然就是慢的,而内存天然就是快的。基于这种直觉,许多系统在面对海量并发时,第一反应往往是将核心数据强行驻留于内存。然而 Kafka 却剑走偏锋,它不仅坚持全量数据持久化落盘,反而能在吞吐量上傲视群雄。
退一步讲,所谓磁盘的“慢”,其原罪根本不在于存储介质本身,而是在于传统随机访问模式下,磁头频繁的寻道与旋转延迟所带来的巨大时间开销。在严格的顺序读写场景下,即使是一块极其普通的 HDD 机械硬盘,其持续吞吐带宽也完全可以逼近甚至持平内存的写入速度,而成本却有着数量级的优势。正因如此,Kafka 整个底层架构设计的最高原则只有一个:想尽一切办法将所有底层数据访问降维成顺序 IO,同时疯狂榨干操作系统的每一寸系统级机制,将任何毫无意义的用户态干预彻底剔除。接下来,我们就来深度拆解这招招见血的“四板斧”。
2. 第一板斧:顺序追加写
正如我们在核心原理篇中所论述的,Kafka 的底层物理载体是一条极其纯粹的 append-only 日志。这不仅仅是数据模型上的理论优雅,更是它撕开高吞吐战场的第一道裂口。
如果我们审视传统关系型数据库或者早期的消息队列架构,会发现它们为了支持复杂的就地更新语义,或是单条消息的精确删除,不可避免地陷入了磁盘随机读写的泥潭。磁头在不同磁道间来回奔波,IO 耗时直接被物理寻址吃满。而 Kafka 则展现出了极大的架构克制,它主动舍弃了局部数据的随机修改能力。所有来自 Producer 的写请求,永远只会以顺流而下的姿态追加到当前活跃段文件(Active Segment)的最末端。这种看似呆板的写入模式,使得磁盘磁头几乎无需大幅移动,直接将落盘动作逼近了底层硬件的物理线速。
这也就解释了为什么在讨论 Kafka 的架构取舍时,我们反复强调“不支持随机修改”是一把双刃剑,但核心团队毫不犹豫地握住了它。在应对洪峰级别的并发时,这种数据模型上的自我约束,直接转化为降维打击般的性能红利,让整个系统的写入能力彻底摆脱了随机寻址的物理枷锁。
3. 第二板斧:页缓存(把内存交给 OS)
拿到了物理磁盘层的顺序追加写红利仅仅是个开始。Kafka 在架构演进上的第二个高明之处,在于它表现出了一种极其罕见的克制:坚决不在应用层去手搓一套庞杂的内存池或者缓存组件,而是将这部分生命线全权托付给了操作系统的 Page Cache。
从底层的数据流转来看,当 Producer 的微批次数据抵达 Broker 时,它们会被优先写入驻留在 OS 内核态的 Page Cache 中。在这之后,Kafka 的写链路便宣告闭环,至于数据何时真正落盘,则完全交由操作系统内核的异步刷盘策略去统筹调度。这意味着,对于上层应用而言,写入操作的延迟完全等同于内存级别的响应耗时。而在下游的消费侧,如果 Consumer 维持着极其健康的追尾消费模式,那么它所请求的热数据大概率还静静躺在 Page Cache 里,连唤醒底层物理磁盘的资格都没有。
放弃 JVM 堆内缓存而全面拥抱 Page Cache,绝不是一种工程上的偷懒,而是经过严密推演的系统级博弈。一方面,在动辄几十上百 GB 的庞大内存占用下,如果将核心数据硬塞进 JVM 堆区,垃圾回收器(GC)的停顿足矣将整个分布式节点拖入死局;而 Page Cache 处于堆外空间,天生免疫了 GC 的无端侵扰。另一方面,任何写往磁盘的数据底层本就要路过 Page Cache,强行在应用层再缓冲一份,纯属双重缓存的内存资源极度浪费。更为关键的是,即便 Kafka 进程遭遇意外崩溃,只要底层的操作系统依然坚挺,这份海量热点缓存就不会烟消云散。这也就为进程重启后的流量承接,提供了一道极其坚固的内存兜底防线。
4. 第三板斧:零拷贝 (Zero-copy / sendfile)
当数据安稳地躺在 Page Cache 中,紧接着面临的挑战便是如何将其极速输送给数以万计的 Consumer 节点。在传统的 UNIX I/O 模型里,这段旅程堪称颠簸:数据必须先从内核态拷贝至用户态缓冲区,经历应用层的业务逻辑处理后,再被打回内核态的 Socket 缓冲区,最终才送往物理网卡。这一来一回的四次拷贝与四次上下文切换,无疑是吞吐量最大的隐形杀手。
为了彻底打通这任督二脉,Kafka 深度借力了操作系统提供的 sendfile 系统调用(在 Java 世界里被优雅地封装为 FileChannel.transferTo)。既然 Kafka 的消费模型仅仅是严格按 Offset 顺序读取一段不可变的文件流,那么数据完全没有必要跃迁到用户态去折腾一圈。借助 sendfile,数据可以在内核态中从 Page Cache 直通网卡驱动,完成一次极其干脆利落的零拷贝(Zero-copy)。这硬生生地斩断了所有的 CPU 冗余搬运工作,将网络出口带宽的利用率推向了极致。
正因如此,我们必须在这个环节对一线生产环境提出严厉的防坑警告:贸然在 Broker 端开启 SSL/TLS 加密,无异于亲手摧毁这条零拷贝的高速公路。因为任何加密逻辑都不可避免地要求数据被强行拉回用户态进行加解密运算,零拷贝机制瞬间阵亡,随之而来的便是吞吐的断崖式暴跌与 CPU 负载的疯狂报警。安全红线与系统性能在这里,是真正的零和博弈。
5. 第四板斧:日志分段 (Log Segment) 与稀疏索引
在宏观层面探讨了 IO 流转之后,我们将视角切入微观的文件存储系统。面对单 Topic 下海量的持续追加写入,如果任由一个 Partition 膨胀为单一巨型文件,那么不管是数据检索还是过期清理,都将演变成一场灾难。Kafka 的解法同样利落:它将整个分区数据有条不紊地切割为一个个限定容量的日志分段(Log Segment)。
每个物理分段并不是一座孤岛,而是由核心数据文件 .log、稀疏索引 .index 以及时间戳索引 .timeindex 构成的三剑客。当我们需要根据特定的 Offset 定位一条历史消息时,底层的检索逻辑实质上是一场极其高效的两级二分定位与短途扫掠。系统首先利用目标 Offset 与所有分段的基础边界进行二分查找,迅速锁定目标所在的那个确切物理分段。随后,深入该分段的稀疏索引文件中进行第二轮二分探查,找出不超过目标 Offset 的最近一条索引映射记录,获取其物理绝对位移。最后,只需要顺着这个位移点,在对应的 .log 文件中执行极短距离的顺序扫描,便能精确捕获目标数据。
这也就解释了为什么 Kafka 坚持采用间隔采样的稀疏索引,而不是粒度更细的全量绝对定位。在极其充沛的 Page Cache 与 mmap (Memory Mapped Files) 内存映射技术的强力加持下,短距离的顺序扫描所付出的时间成本微乎其微,但这种架构上的让步却换取了成百上千倍的内存空间节约。这种看似不完美的折中,恰恰是在海量并发下保持 O(1) 级别定位速度的顶级工程智慧。不仅如此,正是基于这种粗粒度的分段机制,Kafka 在执行日志压缩(Compaction)或是淘汰过期数据时,可以直接以一整个固化的老分段作为物理清理边界,丝毫不干扰那个正在承接洪流写入的活跃分段,彻底保障了写入链路的绝对平顺。
6. 加成项:批量与压缩
如果说前面四板斧是在疯狂压榨单节点底层 IO 的物理极限,那么批量与压缩机制的引入,则是在宏观的分布式传输网络上打出的一记重拳。
在 Producer 篇 中我们曾深度推演过,攒批(Batching)的本质绝不仅仅是单纯的合并网络请求。通过 batch.size 与 linger.ms 的精密调配,系统实际上是在将昂贵的系统调用成本与网络 RTT 往返时延,极其均匀地摊薄到了每一次微观的消息投递上。在此基础上叠加端到端压缩(如 LZ4、ZSTD 等),整个链路的效能直接迎来了质的飞跃。最令底层极客拍案叫绝的一点在于:Broker 节点不仅坚决拒绝对接收到的 Batch 进行拆解重组,甚至连压缩包都不会去解压,而是原封不动地直接落盘。当 Consumer 发起拉取时,这些包裹依然以压缩形态通过零拷贝直送消费端。这也就意味着,整条数据总线仅在首尾两端消耗 CPU 进行压解压运算,将中间核心集群的计算负担彻底降到了冰点。这种架构级的高度协同,正是高吞吐神话背后不可或缺的拼图。
7. 把“快”串起来:一条消息的高速公路
行文至此,如果我们将上述所有精密咬合的齿轮逐一拼装,俯瞰一条消息在 Kafka 内部的生命周期,你会发现这是一条没有任何阻碍的高速公路。当 Producer 端通过攒批与压缩将海量流量汇聚成流后,网络层只需承受极低频的大块数据请求。数据一经 Broker 接收,立刻以顺序追加写的姿态沉降至操作系统的 Page Cache 中,整个写入动作瞬间闭环并向上游返回成功响应。与此同时,后台的 ISR 副本同步大军同样遵循着顺序拉取与顺序写入的铁律,默契地完成集群层面的高可用冗余。当下游 Consumer 启动追尾消费时,Broker 毫无保留地祭出 sendfile 零拷贝大杀器,将尚在内存温热期的压缩报文彻底绕过用户态,直接倾倒进下发网卡通道。
纵观全链,底层流转的逻辑线索极其清晰:全程杜绝任何形式的磁盘随机寻址,全程消灭无谓的用户态内存拷贝,全程封杀核心节点冗余的算力消耗。Kafka 能够跨越物理介质的鸿沟跑出极致性能,根本原因绝不在于某一项孤立的奇淫技巧,而是将极其克制的数据模型与操作系统最底层的基石特性,进行了一场严丝合缝的暴力级重构。
8. 什么时候 Kafka 会变慢
作为一名成熟的基础架构研发,理解一个系统为什么快,终极目的是为了洞察它在什么情况下会慢。那些发生在生产环境里惊心动魄的性能崩塌,几乎无一例外,都是因为上层的非理性业务操作直接击穿了 Kafka 底层极其脆弱的性能护城河。
| 性能降级场景 | 击穿了什么底层机制 | 资深架构的调优与兜底策略 |
|---|---|---|
| 海量 Consumer 触发历史回溯 (冷读) | Page Cache 热点被彻底冲刷,被迫退化为物理磁盘的随机冷读 | 必须在应用层实施错峰重放与严格限速;在架构侧可引入分层存储或搭建物理隔离集群。 |
| 物理机内存干涸 / JVM 堆被设置过大 | OS Page Cache 的物理生存空间惨遭挤占,连热数据都必须触发物理读盘 | 强制瘦身 JVM 堆内存(锁定 ~6GB 警戒线),将宝贵的物理内存全额让渡给操作系统。 |
| 强制开启 SSL/TLS 加密 | 零拷贝机制当场阵亡(数据被迫退回用户态执行繁重的加解密) | 深刻权衡安全红线与系统吞吐的零和博弈;若不可避免,必须果断扩容机器硬扛 CPU 损耗。 |
| 无节制地暴增分区/段文件数量 | 顺序写入的宏观连贯性被彻底打散,句柄耗尽,底层刷盘动作严重碎片化 | 必须严防死守业务方滥建 Topic。严格根据集群的吞吐基线反推合理的分区数上限,切忌无脑扩区。 |
高频强制刷盘(flush.ms 参数极小) | 彻底粉碎了“异步顺序刷盘”带来的 IO 红利,直接退化为高频碎片化随机落盘 | 坚信高可用与持久性应当由 ISR 副本同步队列来兜底保障,而非强行依赖单机侧的高频 fsync。 |
| 大报文狂暴轰炸 / 拒绝开启端侧压缩 | 直接将物理网卡与磁盘 IO 带宽彻底打满,导致全网链路引发致命拥塞 | 果断开启 lz4 或 zstd 压缩策略,并在源头层面对单条请求的物理载荷实施严酷管控。 |
我们需要时刻敬畏这条性能铁律:Kafka 狂暴的吞吐量,全部建立在“追尾消费 + Page Cache 极高命中 + 顺序 IO + 零拷贝直传”这一精巧却脆弱的平衡之上。任何试图让系统频繁交替读取冷热数据、剥夺 Page Cache 物理空间、或者试图用高频业务逻辑打断底层 IO 链路的愚蠢操作,都会在瞬间摧毁这套精密运转的齿轮,将其打回普通磁盘组件的原形。
9. 性能相关配置速查
在面对复杂的集群调优诉求时,以下的参数字典往往是资深架构师排查瓶颈的核心抓手:
| 核心参数配置 | 所属端侧 | 架构作用与调优逻辑 |
|---|---|---|
batch.size / linger.ms | Producer | 决定攒批操作的物理阈值与延迟容忍度。数值设定越高,吞吐量与压缩比的收益越显著,典型的“以延迟换吞吐”战略。 |
compression.type | Producer | 确立端到端的压缩算法,当前工业界以 lz4 与 zstd 为主流。其核心哲学是以客户端廉价的 CPU 算力换取极其昂贵的网络与磁盘带宽。 |
log.segment.bytes | Broker / Topic | 圈定单一日志段文件的物理极值。这直接决定了过期数据保留粒度的粗细,同时也显著影响着底层文件句柄的总数量。 |
log.index.interval.bytes | Broker / Topic | 决定稀疏索引的采样密度。调整它实质上是在“检索耗时”与“内存空间占用”之间寻找最佳的业务折中。 |
log.flush.interval.messages/ms | Broker / Topic | 强行触发内核态落盘的阈值。实战中强烈建议悬空不配,必须将业务持久性的重任全盘托付给高可用副本机制,而不是强求底层硬刷盘。 |
num.replica.fetchers | Broker | 决定 Follower 副本同步链路的并发线程规模,这一指标直接主导着集群内部数据复制管道的极限吞吐量。 |
JVM 堆大小(KAFKA_HEAP_OPTS) | Broker | 生产级标准通常红线控在 ~6GB。切忌迷信大内存,必须克制,将海量内存资源的调度权全额交给 Page Cache。 |
socket.request.max.bytes / fetch.max.bytes | Broker / Consumer | 严密把控单次网络请求或拉取动作的字节体积上限,这是防范 OOM 崩溃与大报文雪崩的最后一道物理闸门。 |
10. 落到 AdTech:为什么”Netty + Kafka”能扛住事件洪峰
回到我们熟稔的 AdTech 战场,在探讨支撑顶级并发广告大盘的经典架构时(参考核心原理篇 §13),Netty + Kafka + Redis + Flink 的组合总是不容置疑的定海神针。现在,结合其底层的流转逻辑,我们可以给出最严谨的架构释义。
广告领域的曝光、点击等归因事件,在晚高峰会化作无可阻挡的超高并发无 Key 洪流。Kafka 依托顺序追加写、Page Cache 缓冲与批量压缩组成的硬核连招,以前所未有的极速将这股洪流悉数吞没并异步落盘,使得冲锋在最前线的 Netty 接入网关永远不会被下游沉重的业务逻辑反向拖垮,从而根除了背压雪崩的隐患。另一方面,一份底层事件往往需要同时喂给实时计费、特征工程与反作弊等多条业务支流。得益于零拷贝机制的强力托底,Broker 能够以几近零 CPU 损耗的巨大优势,将缓冲区的全量热数据并行扇出分发给各个 Consumer 组群。正因如此,汹涌的流量洪峰在这里被彻底削平,复杂的下游集群得以根据自身真实的水位从容地执行 Pull 拉取。能够抗住这等强度的洗礼,绝非偶然。
11. 生产反模式与踩坑
在真实的研发一线,那些令人痛心疾首的生产惨案,往往源于对底层 IO 机制的无知与傲慢。以下是几条鲜血淋漓的教训总结:
盲目为 Broker 分配超大 JVM 堆内存,是新手极其容易触发的致命反模式。这不仅会导致 Page Cache 无生存空间可用,更会因为动辄几十 GB 的堆区引发极其漫长的 Full GC 死亡停顿。专业的对策是:克制贪欲,将堆内存严格束缚在 6GB 左右,把剩余的所有物理资源无条件上缴给操作系统。
追求极端安全却无脑强上 SSL 协议,同样是吞吐量的催命符。加解密算法的介入将直接撕裂零拷贝机制,迫使数据在内核态与用户态之间来回奔波。运维团队只能对着飙升的 CPU 曲线一筹莫展。正确的做法是:深刻认知安全加密与 IO 吞吐之间的零和博弈属性,仅在绝对必须的链路上开启,并提前做好集群计算算力的水平扩容准备。
任由部分非核心链路的 Consumer 开启暴力回溯冷读,更是极其危险的违规操作。这一举动会在瞬间冲刷掉宝贵的 Page Cache 热点防线,迫使底层磁盘陷入疯狂的随机读取泥潭,最终导致整个核心集群的吞吐被一条边缘业务线活活拖死。面对此类需求,架构组必须实施坚决的限流错峰,或者强行将冷读流量隔离至专用的分层存储集群。
12. 常见误解 ↔ 实战正解
| 业界流传的技术偏见 | 资深架构的底层洞见 |
|---|---|
| Kafka 吞吐极高,是因为它非常激进地把数据全部放进了内存里 | 极其荒谬。它的核心数据必须全量持久化落盘;其恐怖的性能根基源于顺序追加写 + Page Cache + 零拷贝组成的纯粹 IO 闭环,绝非粗暴的“全内存驻留”。 |
| 物理磁盘的读写速度注定被内存按在地上摩擦 | 慢的是随机物理访问;在严格的纯粹顺序 IO 管制下,普通的机械磁盘连续吞吐量完全可以逼近甚至碾压部分内存碎片的写入表现。 |
| 在进行 JVM 调优时,给 Broker 的堆内存越大,集群自然跑得越顺畅 | 恰恰相反。过大的 JVM 堆内存反而会无端挤占 Page Cache 空间,并必然引发灾难性的 GC 停顿;生产级别的标配通常锁定 ~6GB,大头必须全额让渡给 OS。 |
| Kafka 团队在内部手搓了一套极其庞杂且精妙的缓存管理框架 | 架构演进极其克制。它强硬地拒绝自建任何应用层缓存池,而是将整个缓冲体系全权委托给内核态的 Page Cache 来统一调度。 |
| 只要配置得当,开启 SSL 对 Broker 性能基本没有实质性影响 | 致命误判。任何用户态加解密计算都会彻底击毁零拷贝机制,导致吞吐断崖下跌、CPU 负荷飙升,这是不可调和的底层物理法则。 |
| 为了加快检索,索引文件必须逐条记录每一条消息的绝对硬盘位移 | 它实质上是基于 mmap 的稀疏索引 (Sparse Index),通过间隔抽样映射结合极其廉价的短途顺序扫,在极致的时间与空间中达成了最完美的检索折中。 |
| 开启消息压缩后,Broker 节点必然会先解压拆包再重新封装 | 严重的逻辑悖论。Broker 始终坚持原样存取整个压缩批次的底线;整条数据总线仅在 Producer 端进行唯一一次压包,在 Consumer 端进行唯一一次解包。 |
| 疯狂堆砌分区与分段数量,就能无限制地提高并发度与集群性能 | 灾难性的线性思维。盲目的海量分区必定会无情撕裂顺序 IO 的连贯性,导致集群元数据彻底爆炸,并将底层刷盘动作粉碎为万劫不复的随机 IO。 |
只有强行把 flush 频率拉高,频繁 fsync 才能确保核心数据绝对不丢 | 经典的 RDBMS 本末倒置。高可用架构下的持久性与安全性由多副本 ISR 机制与严密的位移提交来兜底;单机层面的频繁 fsync 只会彻底摧毁操作系统的异步顺序刷盘红利。 |
13. 结语
至此,我们的 Kafka 深度推演系列已经顺利构筑起了一套无懈可击的底层知识闭环:从最本源的数据结构(日志)出发,探讨了写入链路的极速聚合(Producer),梳理了下游分发与状态流转(Consumer),论证了容灾与精准一致性的兜底防线(可靠性 / EOS),并最终在本篇完成了对其极致性能引擎的终极破译。
把这五大核心模块的线索彻底串联交织——坚守纯粹的顺序日志模型、推动分区重平衡的并行架构、坚持极其克制的状态客户端化下沉、依托 ISR 副本机制兜底持久性、辅以页缓存与零拷贝打通 IO 命脉——你便真正握住了一份能够推演 Kafka 几乎所有底层行为逻辑与极限调优方向的资深架构师级完整地图。
延伸阅读
本系列内部串读:
- Kafka 核心原理精讲:从一条日志到分布式流平台:探寻日志内核、存储分段以及宏观设计哲学的底层地基。
- Kafka Producer 深挖:分区策略与 Sticky Partitioner:剖析批量机制与压缩策略在写入侧产生的巨大性能杠杆。
- Kafka Consumer 深挖:poll 循环、offset 提交与 rebalance:解析追尾消费逻辑、历史冷读与 Page Cache 命中率之间的深度羁绊。
- Kafka 可靠性与 Exactly-Once 深挖:探讨为什么工业级的持久性永远依靠 ISR 副本,而不是单机高频 fsync。
- 为什么 AdTech 偏爱 Kafka:广告事件中枢的五大典型场景与架构设计:揭秘顺序写、Page Cache 以及零拷贝,是如何在真实广告流量洪峰里化作削峰填谷定海神针的。
一手资料与优质权威教程:
- Apache Kafka. Documentation — Design: Persistence & Efficiency:官方原汁原味的设计精要,涵盖顺序 IO、Page Cache、零拷贝以及批量压缩的核心理念。
- Jay Kreps. The Log: What every software engineer should know about real-time data’s unifying abstraction:探寻日志抽象艺术与顺序化思想的最本源出处。
- Confluent. Kafka Performance:一套体系化讲解吞吐/延迟调优与性能内核的巅峰之作。
- Martin Kleppmann. Designing Data-Intensive Applications(第 3 章,日志结构存储):如果你想掌握顺序写与日志结构存储引擎更为普适的设计哲学,强烈建议阅读。