大数据 -180 Elasticsearch 近实时搜索:Segment、Refresh、Flush、Translog 全流程解析

TL;DR
场景:写入后立刻搜不到、节点重启怕丢数据,只知道“近实时”却搞不清 ES 底层是怎么保证性能和可靠性的。
结论:Segment 不可变、Refresh 负责“可搜”、Flush+Translog 负责“可恢复”,一套链路共同定义了 Elasticsearch 的性能上限和数据安全边界。
产出:梳理索引写入到 NRT 搜索的全链路流程,给出 refresh_interval、flush、translog.durability 等关键参数的调优思路和常见故障模式速查表。
版本矩阵
索引文档写入和近实时搜索原理
基本概念
Segments in Lucene
众所周知,Elasticsearch 存储的基本单元是 Shard,ES 中的一个 Index 可能分为多个 Shard,事实上每个 Shard 都是一个 Lucence 的 Index,并且每个 LucenceIndex 由多个 Segment 组成,每个 Segment 事实上是一些倒排索引的集合,每次创建一个新的 Document,都会归属于一个新的 Segment,而不会去修改原来的 Segment。且每次的文档删除操作,会仅仅标记 Segment 中该文档为删除状态,而不会真正的立马物理删除,所以说 ES 的 index 可以理解为一个抽象的概念。就像下图所示:
Translog-Hbase WAL(Write Ahead Log)
Write Ahead Log 预写入日志新文档被索引意味着文档会被首先写入内存 buffer 和 translog 文件,每个 shard 都对应一个 translog 文件
Refresh In Elasticsearch
在 Elasticsearch 中,_refresh 操作默认每秒执行一次,意味着将内存 buffer 的数据写入到一个新的 Segment 中,这个时候索引变成了可检索的,写入新 Segment 后会清空内存 buffer。
Flush In Elasticsearch
Flush 操作意味着将内存 buffer 的数据全部写入到新的 Segment 中,并将内存中所有 Segments 全部刷盘,并且清空 translog 日志的过程。
近实时搜索
基本流程
Elasticsearch 写入流程,当一个写请求到达 Elasticsearch 后,ES 将数据写入 MemoryBuffer 中,并添加事务日志(translog)。如果每次一条数据写入内存后立即写到硬盘上,由于写入的数据肯定是离散的,因此写入磁盘的操作也就是随机写入了。硬盘随机写入的效率相当低,会严重降低 ES 的性能。因此 ES 在设计时在 MemoryBuffer 和硬盘之间加入了高速缓存(FileSystemCache)来提高 ES 的写效率。当写请求发送到 ES 后,ES 将数据写入 MemoryBuffer 中,此时写入的数据还不能查询到。默认设置下,ES 每 1 秒钟将 MemoryBuffer 中的数据 Refresh 到 Linux 的 FileSystemCache,并清空 MemoryBuffer,此时写入的数据就可以被查询到了。
Refresh API
在 Elasticsearch 中,写入和打开一个新段的轻量的过程叫做 Refresh,默认情况下每个分片会每秒自动刷新一次。这就是为什么我们说 Elasticsearch 是“近”实时搜索:文档的变化并不是立即对搜索可见,但会在一秒之内变成可见。这些行为可能会对新用户操作困惑,他们索引了一个文档然后尝试搜索它,但却没有搜索到。这个问题的解决方法是用 Refresh API 执行一次手动刷新:
刷新(Refresh)所有的索引
只刷新(Refresh)blogs 索引
只刷新文档
并不是所有的情况都需要每秒刷新,可能你正在使用 Elasticsearch 索引大量的文件,你可能想优化索引速度而不是近实时搜索,可以通过设置 refrsh_interval,降低每个索引的刷新频率。
refresh_interval 可以在既存索引上动态更新,在生产环境中,当你正在建立一个大的索引时,可以先关比自动刷新,待开始使用该索引时,再把他们调回来。
持久化变更
基本流程
持久化变更 flush 即使通过每秒刷新(Refresh)实现了近实时搜索,仍然要经常进行完整提交来确保从失败中恢复。但在两次提交之间发生变化的文档怎么办?我们也不希望丢掉这些数据。Elasticsearch 增加了一个 Translog,叫做事务日志,在每一次对 Elasticsearch 操作时都会进行日志记录,通过 translog,整个流程是下面这个样子:
第一步:一个文档被索引之后,就会被添加到内存缓冲区中,并且追加到了 translog,如下图描述一样:新的文档被添加到内存缓冲区并且追加到了事务日志:
第二步:刷新(refresh)使分片处于下图描述的状态,分片每秒刷新(refresh)一次:
这些内存缓冲区的文档被写入到一个新的段中,且没有进行 fsync 操作
这个段被打开,使其可被搜索。
内存缓存区被清空
刷新(refresh)完成后,缓存被清空但是事务日志不会。
第三步:这个进程继续工作,更多的文档被添加到内存缓冲区和追加到事务日志,事务日志不断积累文档:
每隔一段时间:列如 translog 变得越来越大,索引被刷新(flush),一个新的 translog 被创建,并且一个全量提交被执行。
所有在内存缓冲区的文档都被写入一个新的段(Segment)
缓冲区被清空
一个提交点被写入硬盘
文件系统缓存通过 fsync 被刷新(flush)
老的 translog 被删除
translog 提供所有还没有被刷到磁盘的操作的一个持久化记录,当 Elasticsearch 启动的时候,它会从磁盘中使用最后一个提交点去恢复已经得段,并且会重放 translog 中所有在最后一次提交后发生的变更操作。translog 也被用来提供实时 CRUD,当你试着通过 ID 查询、解析、删除一个文档,它会在尝试从相应的段中检索之前,首先检查 translog 任何最近的变更。这意味着它总是能够实时的获取到文档的最新版本。在刷新(flush)之后,段被全量提交,并且事务日志被清空。
flush API
这个执行一个提交并且截断 translog 的行为在 Elasticsearch 被称作一次 flush,分片每 30 分钟被自动刷新(flush),或者在 translog 太大(512M)的时候也会刷新。flush API 可以被用来执行一个手工的刷新(flush):
刷新(flush)blogs 索引
刷新(flush)所有的索引并且等待所有刷新在返回前完成,我们很少需要自己手动执行一个 flush 操作,通常情况下,自动刷新就够了。
这就是说,在重启节点或者关闭之前执行 flush 有益于你的索引,当 Elasticsearch 尝试恢复或重新打开一个索引的时候,它需要重放 translog 中所有的操作,所以如果日志越短,恢复的会越快。
Translog 安全问题
Translog 有多安全?Translog 的目的是保证操作不会丢失,但是却引出了对应的问题:在文件被 fsync 到磁盘前,被写入的文件在重启之后就会丢失。这个过程在主分片和复制分片都会发生。最终,基本上,这意味着在整个请求被 fsync 到主分片和复制分片的 translog 之前,你的客户端不会得到一个 200 的 OK 响应,在每次写请求后执行一个 fsync 会带来性能上的损失,尽管实践表明这个损失并不大(特别是 bluk 导入,在一次请求时平摊了大量的文档开销)但是对于一些大容量的偶尔丢失几秒数据问题并不眼中的集群,使用异步的 fsync 还是比较有益的。比如,写入的数据被缓存到内存中,再每 5 秒执行一次 fsync。这个行为可以通过设置 durability 参数为 async 来启动。
这个选项可以针对索引单独设置,并且可以动态修改,如果你决定使用异步 translog 的话,你需要保证在发生 crash 时,丢失掉 sync_interval 时间段的数据也无所谓。请在决定前知晓这个特性。如果你不确定这个行为的后果,最好使用默认参数:"index.translog.durability": "request" 来避免数据丢失。
错误速查
其他系列
🚀 AI 篇持续更新中(长期更新)
AI 炼丹日志-29 - 字节跳动 DeerFlow 深度研究框斜体样式架 私有部署 测试上手 架构研究,持续打造实用 AI 工具指南!AI 研究-132 Java 生态前沿 2025:Spring、Quarkus、GraalVM、CRaC 与云原生落地🔗 AI模块直达链接
💻 Java 篇持续更新中(长期更新)
Java-180 Java 接入 FastDFS:自编译客户端与 Maven/Spring Boot 实战 MyBatis 已完结,Spring 已完结,Nginx 已完结,Tomcat 已完结,分布式服务已完结,Dubbo 已完结,MySQL 已完结,MongoDB 已完结,Neo4j 已完结,FastDFS 已完结,OSS 正在更新... 深入浅出助你打牢基础!🔗 Java模块直达链接
📊 大数据板块已完成多项干货更新(300 篇):
包括 Hadoop、Hive、Kafka、Flink、ClickHouse、Elasticsearch 等二十余项核心组件,覆盖离线+实时数仓全栈!大数据-278 Spark MLib - 基础介绍 机器学习算法 梯度提升树 GBDT 案例 详解🔗 大数据模块直达链接
版权声明: 本文为 InfoQ 作者【武子康】的原创文章。
原文链接:【http://xie.infoq.cn/article/2f2cd00b6bccf2f7d6b068de7】。文章转载请联系作者。







评论