news 2026/4/27 17:39:49

6.2 Elasticsearch-写入链路:Index → Refresh → Flush → Merge 源码走读

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
6.2 Elasticsearch-写入链路:Index → Refresh → Flush → Merge 源码走读

6.2 Elasticsearch-写入链路:Index → Refresh → Flush → Merge 源码走读

Elasticsearch 的写入链路是一条“先写内存、再写事务日志、后刷盘、最终合并”的四级流水线。
整条链路由Index → Refresh → Flush → Merge四个阶段组成,对应内核代码里的四个关键服务:
IndexServiceRefreshServiceFlushServiceMergeScheduler
下面以 8.11 分支源码为基准,按时间顺序把一次文档写入的完整旅程跑一遍,并给出可直接打断点的位置与核心字段含义。


1. Index:文档进门的第一站

入口TransportBulkAction#doExecuteBulkRequestHandler#executeBulk
关键类InternalEngine#index
关键字段versionMaplocalCheckpointmaxSeqNo

  1. 路由计算
    TransportBulkAction把 bulk 拆成 shard 级别的BulkShardRequest,通过IndexRouting#resolve得到目标主分片。
  2. 主分片写内存
    PrimaryShardOperation#doRunInternalEngine#index拿到Index操作对象,先加writeLock
  3. 版本号与序列号
    Index#resolveVersionversionMap做乐观锁冲突检测;SequenceNumbers#nextSeqNo原子递增生成seqNo
  4. 写 Lucene 的 DWPT
    IndexWriter#addDocument只是把文档追加到DocumentsWriterPerThreadpendingDocs队列,此时数据不可见
  5. 写 translog
    Translog#addIndex操作序列化后追加到translog.ckp文件,返回locationlocation被塞进Engine.Index结果里,用于回放。
  6. 主分片返回
    ReplicationOperationlocationReplicationRequest发到副本,副本走同一条InternalEngine#index路径,保证主副一致。

断点
org.elasticsearch.index.engine.InternalEngine:index第 952 行,assert seqNo > localCheckpoint.get();
可观察seqNoversionprimaryTerm三值是否连续。


2. Refresh:把内存数据变为可查

入口IndexService#refreshRefreshService#refresh
关键类ElasticsearchDirectoryReaderReadersAndUpdates
关键字段lastRefreshedCheckpointrefreshedSeqNo

  1. 触发条件
    • 定时:默认 1s (index.refresh_interval)。
    • 强制:调用_refreshAPI 或bulkrefresh=true
  2. 打开新 reader
    InternalEngine#refreshIndexWriter#getReader(true)拿到StandardDirectoryReader,内部是SegmentCoreReaders列表。
  3. 更新 checkpoint
    lastRefreshedCheckpoint被原子更新为当前已写完的最大seqNo只有 ≤ checkpoint 的文档才对 Searcher 可见
  4. 发布新的 Searcher
    IndexShard#storeNewSearcherDirectoryReader包装成ElasticsearchDirectoryReader,注册到ShardSearchRegistry;旧 reader 引用计数归零后自动关闭。

断点
org.elasticsearch.index.engine.InternalEngine:refresh第 1273 行,lastRefreshedCheckpoint = localCheckpointTracker.getProcessedCheckpoint();
可验证可见延迟 =localCheckpoint - lastRefreshedCheckpoint


3. Flush:把 translog 刷盘并提交 commit

入口FlushService#flushInternalEngine#flush
关键类TranslogWriterIndexWriter
关键字段flushSeqNocommittedTranslogGeneration

  1. 触发条件
    • translog 大小超过 512 MB (index.translog.flush_threshold_size)。
    • 定时 5 min 一次。
    • 重启前必须 flush(IndicesClusterStateService#applyClusterState)。
  2. 写 Lucene commit
    IndexWriter#commit()生成新的segments_N文件,把内存中所有已 refresh的段 fsync 到磁盘。
  3. 截断 translog
    Translog#current被关闭并重命名为<generation>.ckp,新 translog 从空文件开始;committedTranslogGeneration指针推进。
  4. 更新 shard state
    IndexShard#persistMetadatacommitSeqNocommitPrimaryTerm写进shard-state.st文件,供节点重启后恢复。

断点
org.elasticsearch.index.translog.Translog:closeIntoReader第 568 行,
logger.debug("flushing translog generation {}", generation);
可确认 flush 后旧 translog 文件是否被清理。


4. Merge:后台段合并与物理删除

入口MergeScheduler#mergeTieredMergePolicy#findMerges
关键类ElasticsearchMergePolicyMergeTask
关键字段maxMergedSegmentBytesdeletesPctAllowed

  1. 策略选择
    TieredMergePolicy把段按大小分层,优先合并大小相近且删除率高的段;maxMergedSegmentGB默认 5 GB,防止写出过大段。
  2. 合并流程
    IndexWriter#merge创建MergeSpecification,每个OneMerge包含待合并的SegmentCommitInfo列表;Lucene 把多个段读出 → 去删除 → 重新写成一个新段。
  3. 更新版本映射
    ElasticsearchMergePolicy#keepFullyDeletedSegment返回 false,保证完全删除的段在合并后直接物理丢弃;versionMap中对应uidversion被清理,防止版本泄露
  4. 并发控制
    合并线程与写入线程共享IndexWriterwriteLock,但merge本身使用flushLock的读锁,因此refresh 不会被 block,搜索仍可进行。

断点
org.apache.lucene.index.TieredMergePolicy:findMerges第 214 行,
if (segBytes > maxMergedSegmentBytes) continue;
可观察哪些段被选入合并列表。


5. 端到端时序图(简化)
Client ──► TransportBulkAction │ ├─► Index (DWPT + Translog) │ ├─► Refresh (1s 默认) ──► Searcher 可见 │ ├─► Flush (512 MB / 5 min) ──► Commit + Translog 清理 │ └─► Merge (后台) ──► 物理删除 + 段数量收敛

6. 调优提示与源码黑魔法
  1. refresh_interval = -1
    把 refresh 关掉后,lastRefreshedCheckpoint不再推进,搜索 0 结果,但写入吞吐可提升 30 %+;适合离线灌数据场景。
  2. translog durability = async
    异步刷盘每 5 s 一次,减少 fsync 次数,但宕机可能丢 5 s 数据;源码位置:TranslogWriter#syncBeforeReturn第 417 行。
  3. merge scheduler 限流
    MAX_MERGE_COUNT默认 3,MAX_THREAD_COUNT默认 1,机械盘可调到 2×2;源码位置:ElasticsearchMergeScheduler构造器。
  4. sequence number 回滚
    主分片失败时,新主通过Store#readLastCommittedSegmentsInfo读取commitSeqNo,把localCheckpoint回退到 commit 点,保证主副切换不丢数

7. 小结

Index 阶段只保证durability(translog),不保证visibility
Refresh 阶段把内存段暴露给 Searcher,是 ES 近实时搜索的精髓;
Flush 阶段把内存 + translog一起固化,是重启恢复的基石;
Merge 阶段把碎片段 + 删除文档持续整理,决定长期查询性能。

四段代码环环相扣,却通过lock-free checkpoint引用计数 reader做到几乎互不阻塞,值得反复走读。```
推荐阅读:
PyCharm 2018–2024使用指南

更多技术文章见公众号: 大城市小农民

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/25 6:42:04

Qwen3-VL智能家居:视觉控制界面开发教程

Qwen3-VL智能家居&#xff1a;视觉控制界面开发教程 1. 引言&#xff1a;Qwen3-VL-WEBUI与智能家居的融合前景 随着AI大模型在多模态理解能力上的持续突破&#xff0c;视觉语言模型&#xff08;VLM&#xff09; 正逐步从“看懂图像”迈向“操作现实”。阿里云最新发布的 Qwen…

作者头像 李华
网站建设 2026/4/25 6:41:17

导师不会告诉你的9个AI论文写作隐藏技巧,效率飙升告别熬夜!

开头&#xff1a;90%的学生不知道的论文“黑科技”&#xff0c;正在悄悄改变学术圈 你是否经历过这样的场景&#xff1f; 导师轻描淡写地说“下周交初稿”&#xff0c;你却对着空白文档熬到凌晨三点&#xff1b; 文献综述看了几十篇&#xff0c;依然理不清逻辑框架&#xff1b…

作者头像 李华
网站建设 2026/4/27 14:05:12

Qwen3-VL-WEBUI模型热更新:不停机升级部署教程

Qwen3-VL-WEBUI模型热更新&#xff1a;不停机升级部署教程 1. 引言 1.1 业务场景描述 在AI大模型快速迭代的背景下&#xff0c;Qwen系列持续推出性能更强、功能更丰富的视觉语言模型。当前&#xff0c;Qwen3-VL-WEBUI 已成为开发者和企业部署多模态应用的重要工具平台。该系…

作者头像 李华
网站建设 2026/4/27 10:39:33

Obsidian字体优化终极指南:打造舒适阅读体验的完整方案

Obsidian字体优化终极指南&#xff1a;打造舒适阅读体验的完整方案 【免费下载链接】awesome-obsidian &#x1f576;️ Awesome stuff for Obsidian 项目地址: https://gitcode.com/gh_mirrors/aw/awesome-obsidian 在Obsidian中进行知识管理时&#xff0c;字体优化是提…

作者头像 李华
网站建设 2026/4/17 23:20:28

GalTransl革命性突破:智能AI驱动的视觉小说翻译新纪元

GalTransl革命性突破&#xff1a;智能AI驱动的视觉小说翻译新纪元 【免费下载链接】GalTransl Automated translation solution for visual novels supporting GPT-3.5/GPT-4/Newbing/Sakura. 支持GPT-3.5/GPT-4/Newbing/Sakura等大语言模型的Galgame自动化翻译解决方案 项目…

作者头像 李华
网站建设 2026/4/17 23:57:04

Qwen3-VL vs Llama3-Vision实战对比:视觉理解与GPU利用率评测

Qwen3-VL vs Llama3-Vision实战对比&#xff1a;视觉理解与GPU利用率评测 1. 引言&#xff1a;为何需要多模态模型的深度对比&#xff1f; 随着AI应用从纯文本向多模态交互演进&#xff0c;视觉语言模型&#xff08;VLM&#xff09;已成为智能助手、自动化代理和内容理解系统…

作者头像 李华