大数据-181 Elasticsearch 段合并与磁盘目录拆解
1. 背景:为什么需要段合并
Elasticsearch 的写入是「追加型」的,索引文档时不会直接更新已有文档,而是:
- 新文档写入内存 Buffer
- refresh 时,Buffer 内容写入新段(Segment)
- 段不可变更(Immutable)
refresh 频率默认 1 秒一次,意味着每秒都会产生新段。段越多,问题越多:
- 文件句柄占用(每个段需要打开多个文件)
- 内存开销(每个段有独立数据结构)
- CPU 消耗(查询时需要合并多个段的結果)
- 磁盘空间(已删除文档不释放,只做标记)
段合并(Merge)就是在后台把小段并入大段,清理已删除文档。
2. Merge Policy 配置
2.1 核心参数
| 参数 | 默认值 | 含义 |
|---|---|---|
index.merge.policy.floor_segment | 2MB | 小于此大小的段会被忽略,不参与合并 |
index.merge.policy.max_merge_at_once | 10 | 每次合并最多参与的段数 |
index.merge.policy.max_merged_segment | 5GB | 合并后最大段大小 |
index.merge.policy.segments_per_tier | 10 | 每层最少段数(与 max_merge_at_once 配合) |
2.2 配置示例
{
"settings": {
"index.merge.policy.max_merge_at_once": 20,
"index.merge.policy.max_merged_segment": "10gb"
}
}
3. Force Merge
强制合并用于只读/归档场景,手动把段合并成更少的段:
POST /my-index/_forcemerge?max_num_segments=1
注意:
- 会产生大量 I/O,建议在业务低峰期执行
- 完成后无法回退
- 只读索引建议用此操作归档
4. ES 数据目录结构
nodes/
└── 0/
└── indices/
└── {index-uuid}/
└── 0/
├── _state/
│ └── state-1.st
├── index/
│ ├── _0.cfe
│ ├── _0.cfs
│ └── _0.si
└── translog/
└── translog.ckp
4.1 核心文件类型
| 文件后缀 | 含义 |
|---|---|
.cfe | 复合文件入口 |
.cfs | 复合文件数据 |
.si | 段信息 |
.doc | DocValues |
.dim | BKD 树(地理坐标) |
.pos | 位置信息 |
.tip | Term Index |
5. 总结
- 段合并由后台线程自动执行
- 合理配置 Merge Policy 可平衡写入性能与查询效率
- Force Merge 只适用于只读索引
- 理解目录结构有助于排查问题