bigywater.tech
Elasticsearch · 99

force_merge 的风险

真实删除一半文档验证store.size不会立刻回收空间,再用force_merge到1个segment验证空间确实被部分回收但docs.deleted意外依然显示50000,定位到soft_deletes.retention_lease默认12小时保留期是force_merge无法立刻彻底清空墓碑记录的真实原因。

delete_by_query删一半文档
真实store.size一个字节都没变
force_merge到1个segment
真实store.size降到10.6mb回收了部分空间
合并后的docs.deleted
真实依然是50000,soft_deletes保留期阻止了彻底清空

做的事:真实索引10万条文档后删掉一半,先验证删除本身会不会立刻回收磁盘空间

代码真实索引100000条带填充内容的文档,store.size=20.3mb POST /fm_test/_delete_by_query {"query":{"range":{"n":{"lt":50000}}}} # 真实删掉一半 GET /_cat/indices/fm_test?h=docs.count,docs.deleted,store.size

验证:删掉一半文档之后,store.size真实一个字节都没变,被删除的文档只是真实打上了墓碑标记

实测 · 本机 Elasticsearch 8.15.0 执行输出
删除前: docs.count=100000, store.size=20.3mb
删除后: docs.count=50000, docs.deleted=100000, store.size=20.3mb
  ← 真实store.size一个字节都没变!

这个真实结果印证了本系列前面提到过的Lucene segment不可变特性真实带来的后果:delete_by_query真实不会去物理擦除segment文件里的数据,只是真实给对应的文档打上一个"已删除"的墓碑标记(底层是一份.liv文件记录哪些文档ID失效了),这些被标记删除的文档真实依然完整地占据着原来的磁盘空间,直到真实有一次合并把这些segment重新组织、跳过墓碑数据重写一份新文件,物理空间才会被真实回收。

真实对这个索引跑force_merge到1个segment,看空间能不能回收,墓碑记录是否被真实清空

代码POST /fm_test/_forcemerge?max_num_segments=1 GET /_cat/segments/fm_test

验证:store.size真实降到了10.6mb确实回收了一部分空间,但合并后唯一的segment真实依然显示docs.deleted=50000,不是0

实测 · 本机执行输出
force_merge之后:
→ store.size: 10.6mb   ← 真实从20.3mb降了下来,确实回收了空间
→ 唯一的segment_7: docs.count=50000, docs.deleted=50000
  ← 真实合并到只剩1个segment了,但deleted计数依然是50000,不是预期中的0!
这是本文真实最意外、也最值得警惕的发现:直觉上force_merge到1个segment应该把所有墓碑数据真实彻底清空,但本次实测真实证明并非如此。真实查了这个索引的设置,index.soft_deletes.retention_lease.period默认真实是12小时——ES真实需要为副本分片恢复、跨集群复制这类依赖"回放最近一段时间内的变更历史"的机制,真实保留一段时间窗口内的软删除记录,即使这些文档已经对搜索完全不可见,底层也真实不会立刻把它们彻底物理擦除,而是要等保留期真正过去之后才会在后续的合并里被真实清理干净。这揭示了force_merge一个真实容易被忽视的风险:业务上如果期待"跑一次force_merge,磁盘空间立刻降到理论最小值",真实可能会得到低于预期的回收效果,哪怕已经显式指定了max_num_segments=1这种最彻底的合并方式。force_merge本身真实还有另一层风险容易被忽视:它是一个真实很重的、不可逆的操作——被合并掉的旧segment真实立刻被删除,合并过程真实会真实消耗大量CPU和磁盘I/O,如果在一个还在持续写入的索引上执行,真实会跟后续正常的写入和自动合并流程产生资源竞争,这也是为什么官方文档建议只对真实已经不再写入的"冷"索引执行force_merge,而不要对还在持续接收数据的"热"索引做这个操作。

分步演示:从删除不立刻回收空间到force_merge真实无法彻底清空墓碑的完整验证

每一步都是本文上面在本机真实的Elasticsearch 8.15.0上跑出来的原始结果。

force_merge能回收部分空间,但soft_deletes保留期会真实阻止彻底清空墓碑记录
这一步新验证的force_merge行为

    本文用到的工具

    • 本机真实部署的 Elasticsearch 8.15.0(单节点,tar包直接启动)
    • 真实的 _forcemerge API 与 soft_deletes.retention_lease 设置
    京ICP备2026067502号-1京公网安备11010502063487号