Elasticsearch 的 Write-Ahead Log(Translog)学习笔记

非常好,这是一个高级系统设计问题。我们可以从《Designing Data-Intensive Applications(DDIA)》的视角,系统地解析 Elasticsearch 的 Write-Ahead Log(WAL)机制及其相关抽象组件


🧩 一、先复盘:DDIA 视角下的“存储抽象层次”

在 DDIA 的体系中,持久化与一致性的基础抽象一般分为:

层次 关键概念 典型组件
1️⃣ Commit Log / WAL 记录操作意图(append-only),保证crash后能恢复 Kafka、RocksDB WAL、Postgres WAL、Elasticsearch translog
2️⃣ In-memory Buffer / MemTable 暂存最近写入的索引/数据,用于快速查询与批量刷盘 Lucene Segment Writer, MemTable
3️⃣ Segment File / SSTable 不可变的排序文件,用于合并与压缩 Lucene Segment, SSTable
4️⃣ Compaction / Merge 周期性合并旧数据文件以清理过期项 Lucene Merge Policy, LSM Compaction
5️⃣ Index Metadata / Checkpoint 标记一致性边界,方便恢复 ES Commit Point, Checkpoint file

Elasticsearch 基本完全符合这套结构,只不过它在 Lucene 之上再包了一层分布式协调逻辑。


🧠 二、Elasticsearch 的 WAL 实现:Translog

在 ES 中,WAL 对应的组件叫 Translog(Transaction Log)

🔹 主要职责

  1. 持久化写入请求(WAL功能): 每当一个 document 被索引(index/update/delete)时,写操作先进入内存 buffer(in-memory index buffer),同时在 translog 记录一条日志。

  2. 崩溃恢复: 如果节点宕机,重启时会从 translog 读取并重放未持久化的操作。

  3. 异步落盘优化: 为了性能,ES 支持配置 index.translog.durability

    • "request"(默认)→ 每个请求 fsync 一次;
    • "async" → 定期批量 fsync;
    • "flush" → 定期 checkpoint 后清空旧 translog。

🔹 写入流程(结合 Lucene)

下面是 Elasticsearch 写入一条文档的完整路径:

Client Request
    ↓
Primary Shard
    ↓
Index Buffer (in-memory, Lucene RAM buffer)
    ↓
Translog (append-only WAL file)
    ↓
Lucene Segment (flush时写出新segment)
    ↓
Commit Point (记录索引一致性)

流程分解如下:

步骤 描述
1️⃣ 请求到达主分片(Primary Shard),被写入 Index Buffer(Lucene RAM buffer)。
2️⃣ 同时生成一条操作日志写入 Translog 文件(append-only)
3️⃣ 每隔一段时间或 buffer 满时执行 flush:将内存索引转换为新的 Lucene Segment 文件(不可变)。
4️⃣ flush 成功后,生成新的 commit point 并截断旧的 translog。
5️⃣ 数据同步到 replica shard,由 replica 重放同样的写操作。

⚙️ 三、Translog 的物理结构

每个分片都有自己的 translog 文件,例如:

/data/nodes/0/indices/<index_uuid>/<shard_id>/translog/
    ├── translog-123456.tlog
    ├── translog-123457.ckp
    └── translog-generation

组成部分:

文件 作用
.tlog 主体日志文件(append-only),包含操作记录
.ckp checkpoint 文件,标记已 fsync 的位置
translog-generation 记录当前 translog 序号

每条日志 entry 一般包含:

  • Operation type(index / delete / no-op)
  • seq_no(全局顺序号)
  • docID
  • source data(原始 JSON)
  • version

🔄 四、与 Lucene Segment 的配合:Flush 与 Commit

Lucene 的数据结构是 immutable segment,而 Elasticsearch 的实时性需求要求它支持近实时搜索(NRT)。 因此采用如下折中机制:

阶段 作用
refresh(默认 1s 一次) 将内存 buffer 的数据转入 Lucene 的新 segment(仅在内存/FS cache 层,不fsync)——提供近实时搜索。
flush 将所有 segment 落盘(fsync)+ 提交 commit point + 清理旧 translog——提供持久化。

这正对应 DDIA 中描述的两种 durability 层次:

  • log-first (WAL) 保障崩溃一致;
  • segment merge + commit 保障长期持久化。

🧬 五、分布式一致性:Primary-Replica 复制与 WAL 传播

在分布式层面,Elasticsearch 的写入机制延伸出类似于 DDIA 第9章的 Replication Log 概念:

  1. 写入主分片(Primary)

    • Primary 写入 translog;
    • 生成 seq_no 和 primary_term;
    • 将操作转发给所有 replica。
  2. Replica 重放日志(Replay)

    • Replica 节点写入自己的 translog;
    • 确认成功后返回 ack。
  3. Primary 等待所有 ack 后

    • 标记请求成功(可配置 quorum 写策略)。

这个过程类似于 DDIA 所述的 “主从复制日志(Replication Log)” 模式——本质上,translog 既是本地 WAL,又是分布式复制的源。


🧱 六、DDIA 对应章节映射

DDIA 章节 核心思想 在 Elasticsearch 中的体现
第3章:存储与索引结构 日志结构存储(Log-structured storage)+ SSTable Lucene segment + translog
第5章:复制 单主复制 + WAL 传播 Primary/Replica 写入流程
第6章:分区 分片(Shard)为独立数据子集 每个 shard 自带 WAL & Lucene
第7章:事务 基于操作序列号和 term 实现幂等与顺序一致性 seq_no + primary_term
第9章:一致性与复制 Leader-based replication with logs Translog 即 Leader log
第10章:批处理 segment merge = compaction Lucene MergePolicy

🔍 八、简短总结

Elasticsearch 的 translog 就是 DDIA 所说的“日志结构存储体系中的 Write-Ahead Log”。 它与 Lucene 的 immutable segment 形成“日志 + 快照”的双层模型:

  • 日志层(translog) → 负责可恢复性和复制;
  • 快照层(segment) → 负责可搜索性与压缩。

这种设计结合了高写入吞吐(append-only)、快速恢复(log replay)、高查询性能(segment-based index),是典型的 LSM + Log Replication 混合架构


🔍 九、总结与洞察

Elasticsearch 的 Translog = DDIA 所说的 “Commit Log / Write-Ahead Log”。

它与 Lucene Segment 构成了 “日志 + 快照” 的双层模型:

层次 职责
🧾 Translog (日志层) 提供崩溃可恢复性与复制保障
📚 Lucene Segment (快照层) 提供高效可搜索性与压缩能力

这种架构融合了:

  • 高写入吞吐(append-only)
  • 快速恢复(log replay)
  • 高查询性能(segment-based inverted index)

是典型的 LSM + Log Replication 混合体系, 完美印证了 DDIA 中的存储与复制设计原则。


📖 参考资料

-《Designing Data-Intensive Applications》,Martin Kleppmann

  • Elasticsearch 官方文档: Translog
  • Lucene 文档: Segments and Commits
  • DDIA 中文版:第3章、第5章、第9章、第10章
  • Blog: Deep Dive into Elasticsearch Translog and Commit Process

🧭 延伸阅读建议

探索:如何在分布式系统中实现 “WAL + Snapshot” 一致性(对比 Kafka log + checkpoint)

思考:为什么 Elasticsearch 不使用传统的 page-based 存储结构?

对比:RocksDB 的 WAL + MemTable + SSTable 三层架构与 ES 的异同