目 录CONTENT

文章目录

【原理篇】4. Elasticsearch 数据持久化剖析

冰点
2023-06-21 / 0 评论 / 0 点赞 / 34 阅读 / 20002 字

我画了一个简单的草图,来描述 ElasticSearch的持久化过程。我们一共分为了4个阶段 write -> refresh -> flush -> merge,

理解这些阶段,就能明白 为什么 ES 如何在 “写入速度”“可搜索性”“数据可靠性”“存储效率” 之间找平衡。比如,调整 Refresh 间隔可以 trade-off 实时性和写入性能;监控 Translog 大小能预防 Flush 延迟导致的风险。

在实际运维中,这些阶段的参数配置、状态监控,直接影响集群的稳定性和性能。下次遇到 ES 数据持久化相关问题(如数据延迟可见、磁盘 IO 过高 ),不妨从这几个阶段入手排查。

一、Write 阶段数据的暂存

当客户端写入新文档,ES 首先进入 Write 阶段 :

  • 内存缓冲区暂存:文档先被写入 内存缓冲区(in-memory buffer) ,这是数据的 “临时停靠点”。内存操作速度快,能让写入更高效,但此时数据还未进入可搜索状态。

  • 事务日志保障:同时,写入操作会记录到 事务日志(Translog) 。Translog 就像 “黑匣子”,即使 ES 进程意外崩溃,重启后也能通过它恢复未持久化的数据,保障写入的可靠性。这一步,数据虽 “暂存” 内存,但已有一层 “安全网” 兜底。

二、Refresh 阶段让数据 “可被搜索”

为了让写入的数据能被查询到,ES 会触发 Refresh 阶段 :

  • 段的生成与缓存:内存缓冲区的数据会被写入到 文件系统缓存(segment - filesystem cache) ,形成新的 “段(segment)”。段进入文件系统缓存后,数据就具备了可搜索性。
    (在此处不太理解的话,可以看我的入门篇ES的整体架构)

  • 缓冲区清空:完成写入后,内存缓冲区会被清空,为下一轮写入腾出空间。值得注意的是,Refresh 默认 1 秒触发一次(可通过 index.refresh_interval 调整 ),此时 Translog 并未清空,仍保留着数据变更记录,继续保障可靠性。这一步,数据从 “不可搜索” 转为 “可搜索”,但还未真正持久化到磁盘。

三、Flush 阶段数据刷盘

虽然 Refresh 让数据可搜索,但要让数据真正 “稳固”,还需 Flush 阶段 :

  • 触发条件:当 Translog 过大(或满足其他触发条件,如间隔时间到),ES 会触发 Flush。这是数据从缓存到磁盘的 “关键一跃”。

  • 持久化到磁盘:文件系统缓存中的段会被写入 磁盘(Disk) ,生成新的 “提交点”,标志数据正式持久化。同时,Translog 会被清空,完成一轮 “写入 - 持久化” 的闭环。通过 fsync 机制,ES 确保数据真正落盘,避免进程崩溃导致数据丢失。这一步,数据才算真正 “扎根”,可靠性拉满。

四、Merge 阶段:优化存储的 “幕后工程”

随着写入不断进行,段的数量会越来越多,影响搜索性能。于是,ES 会在 Merge 阶段 进行 “幕后优化”:

  • 合并小分段:后台进程会将多个小分段合并成 大分段 ,并写入磁盘。合并后,新的大分段会替换旧分段,旧分段被删除。

  • 性能优化:减少段的数量,能降低搜索时需要扫描的文件数,提升搜索效率。不过,Merge 过程会占用磁盘 IO 和 CPU,ES 默认会限制其资源使用,避免影响查询性能。这一步,是 ES 对存储的 “自我优化”,让数据存储更高效。

五、思考题

有同学反馈说,ES服务端什么时候在哪个过程给客户端响应写入成功呢

其实客户端收到写入成功响应的阶段是在 Write 阶段完成事务日志(Translog)记录之后。为什么ES是这样设计呢。

先说答案,再说我们的思考。

ES 向客户端返回写入成功响应的时机是在 Write 阶段完成 Translog 持久化后,此时数据已被“安全记录”,但尚未进入可搜索或持久化状态。后续阶段(Refresh、Flush、Merge)均为后台异步处理,不影响客户端的写入响应流程,这一设计实现了写入性能、可靠性与可搜索性的平衡。

1. 写入成功响应的触发点:Write 阶段的 Translog 落盘

当客户端执行文档写入操作时,ES 的处理流程及响应时机如下:

  1. 内存缓冲区暂存:文档先写入内存缓冲区,此时数据尚未持久化,客户端未收到响应。

  2. 事务日志(Translog)记录:写入操作同时记录到 Translog,ES 会根据配置决定是否等待 Translog 落盘(通过 fsync 操作)。

    • 若配置为 request 级别(默认),则 Translog 落盘后,ES 立即向客户端返回 写入成功响应。

    • 若配置为 async 或 periodic,则可能在 Translog 异步落盘或周期性刷新时返回响应(但这种情况可能增加数据丢失风险)。

关键点:客户端收到写入成功响应时,数据仅暂存于内存缓冲区和 Translog,尚未经过 Refresh、Flush 或 Merge 阶段。此时数据已具备可靠性保障(Translog 可恢复),但尚未进入可搜索状态(需等待 Refresh)或持久化到磁盘(需等待 Flush)。

二、各阶段与数据状态的关系

阶段

数据状态

客户端是否已获响应

Write

内存缓冲区 + Translog 已记录

是(Translog 落盘后)

Refresh

数据写入文件系统缓存,可搜索

否(后台自动触发)

Flush

数据持久化到磁盘,Translog 清空

否(后台自动触发)

Merge

分段合并优化存储结构

否(后台异步执行)

三、为什么响应在 Write 阶段?

ES 设计上优先保证写入性能与可靠性的平衡:

  • 性能角度:若等待数据可搜索(Refresh)或持久化(Flush)后再响应,会显著增加写入延迟,影响客户端体验。

  • 可靠性角度:Translog 落盘后,即使 ES 崩溃,重启时也能通过 Translog 恢复数据,因此此时响应“写入成功”是安全的。

  • 可搜索性权衡:数据可搜索需等待 Refresh(默认 1 秒),这是 ES 在“实时性”与“性能”间的妥协(可通过调整 refresh_interval 优化)。

四、配置建议:平衡可靠性与性能

  1. Translog 持久化策略(通过 index.translog.durability 配置):

    • request(默认):每次写入都等待 Translog 落盘,可靠性最高,适合金融等不能丢数据的场景。

    • async:写入后不等待 Translog 落盘,性能最佳,但可能丢失最后一次异步落盘前的数据。

    • periodic:每隔一段时间(由 index.translog.sync_interval 控制)落盘,折中方案。

  2. Refresh 间隔调整:

    • 若需要更高实时性,可缩短 refresh_interval(如设为 0.5 秒),但会增加 CPU 和 IO 开销。

    • 若写入量极大且对实时性要求不高,可延长间隔(如设为 30 秒),减少 Refresh 频率。

你在使用 ES 时,遇到过哪些与持久化相关的 “坑”?是写入后数据延迟搜索到,还是 Merge 过程引发性能波动?欢迎在评论区分享,一起聊聊 ES 持久化的那些事儿~(不同 ES 版本流程细节可能有差异,实际以所用版本为准哦)

0

评论区