Elasticsearch 的 translog、flush 和 segment merge 有什么关系?
简化版
ES 写入先进入内存 buffer 和 translog,refresh 会把 buffer 生成可搜索 segment,但不等于持久化提交;flush 会执行 Lucene commit 并开启新的 translog;segment merge 会把多个小 segment 合并成大 segment,减少查询开销和删除标记。refresh 管可搜索,flush 管提交点和 translog 清理,merge 管段整理。
详细版
写入链路可以简化为:
index request -> indexing buffer + translog -> refresh -> new segment searchable
-> flush -> Lucene commit + new translog
-> merge -> small segments become larger segments
面试要区分几个动作:refresh 让数据近实时可搜;translog 用于故障恢复;flush 建立持久提交点并裁剪 translog;merge 是后台整理 Lucene segment,清理删除标记、减少小段数量,但会消耗 I/O。不要把 refresh、flush、fsync、merge 混成一件事。
完整版教学
一、ES 写入不是立刻变成最终大文件
Elasticsearch 底层基于 Lucene。文档写入后,不是每条都马上落成一个稳定的大索引文件。为了吞吐,它会先进入内存结构,同时写 translog 保障恢复。
简化链路:
client index
-> primary shard
-> indexing buffer
-> translog
-> replica
这样既能提高写入速度,又能在节点异常后通过 translog 恢复未提交的数据。
记忆钩子:refresh 管看见,flush 管提交,merge 管整理。
二、refresh 让文档近实时可搜索
refresh 会把内存 buffer 中的数据打开成新的 segment,使其可以被搜索。默认情况下 ES 是 near real-time,而不是每次写入立即可搜。
T0 write doc
T0.2 search maybe not found
T1 refresh
T1.1 search found
这解释了为什么写入成功后马上搜索可能查不到。可以用 refresh=wait_for 等待下一次 refresh,但高频使用会影响写入吞吐。
refresh 不是完整持久化提交,它主要解决“可搜索性”。
三、translog 用于故障恢复
translog 是事务日志。写入请求在进入内存 buffer 的同时也写入 translog。如果节点在 Lucene commit 前崩溃,重启时可以从 translog 重放操作。
可以类比数据库 redo log,但不要完全等同。ES 的 translog 与 Lucene segment、flush 策略配合工作。
last commit point
+ translog operations after commit
= recoverable latest shard state
如果没有 translog,最近写入但尚未提交的内容可能在崩溃后丢失。
四、flush 建立 Lucene commit 并裁剪 translog
flush 会触发 Lucene commit,把当前 segment 状态形成提交点,并开启新的 translog。旧 translog 中已被 commit 覆盖的操作就可以被清理。
before flush:
commit A + translog[op1, op2, op3]
after flush:
commit B includes op1..op3 + new empty translog
flush 太频繁会增加 I/O;太久不 flush,translog 过大,恢复时间可能变长。ES 会根据阈值自动管理,通常不需要业务频繁手动 flush。
五、segment merge 解决小段过多和删除标记
Lucene segment 写入后基本不可变。更新和删除并不是原地修改,而是写新版本或打删除标记。随着 refresh 增多,小 segment 会越来越多。
merge 会在后台把多个小 segment 合并成更大的 segment,同时清理被删除的文档。
seg1 + seg2 + seg3
-> merge
seg_big
merge 能改善查询效率、减少文件数量,但会消耗 CPU、磁盘 I/O 和临时磁盘空间。写入高峰时 merge 压力可能导致整体变慢。
六、refresh、flush、merge 的区别要能一表说清
| 动作 | 主要目的 | 影响 |
|---|---|---|
| refresh | 让新数据可搜索 | 产生新 segment,影响近实时 |
| flush | 创建 commit,清理 translog | 影响恢复边界和 I/O |
| merge | 合并 segment,清理删除标记 | 影响查询效率和磁盘 I/O |
如果面试官问“为什么写入后搜不到”,答案通常是 refresh;问“崩溃后怎么恢复”,答案涉及 translog;问“删除后磁盘为什么没立刻降”,答案涉及 segment merge。
七、常见误区与追问
- 误区:refresh 就是把数据安全落盘。 refresh 主要让数据可搜索,持久提交边界要看 flush 和 translog。
- 误区:flush 会让数据立刻可搜索。 可搜索性主要由 refresh 决定,flush 关注 commit 和 translog。
- 误区:删除文档后磁盘马上释放。 删除通常先打标记,segment merge 后才真正清理空间。
- 追问:为什么 refresh 太频繁会影响写入? 它会产生更多小 segment,增加后续 merge 压力。
- 追问:translog 太大有什么问题? 节点恢复时需要重放更多操作,恢复时间可能变长。
- 追问:force merge 能不能随便跑? 它很耗 I/O,通常只适合只读或低峰索引,不适合热写索引频繁执行。
八、加强记忆
ES 写入链路记成“三个动作分三件事”:refresh 让新文档可搜索,所以解释近实时;translog 记录未提交写入,所以解释崩溃恢复;flush 建 commit 并清理 translog;merge 合并小 segment 并清理删除标记,所以解释磁盘和查询性能。把这几件事分开,很多 ES 写入、可见性和磁盘问题就能讲清楚。