Elasticsearch 的索引生命周期管理(ILM)如何配置?
Elasticsearch ILM 是什么?
ILM(Index Lifecycle Management)是 Elasticsearch 提供的索引生命周期自动化管理机制,它根据索引的年龄、大小等条件,自动将索引在不同存储层级之间迁移,最终删除过期数据,从而降低存储成本和运维负担。
没有 ILM 时,常见的问题是:索引无限增长导致分片过大(恢复慢)、热节点磁盘告警、过期数据占满存储。ILM 通过定义策略(policy),让索引自动经历 hot → warm → cold → frozen → delete 五个阶段,每阶段执行特定操作(rollover、shrink、force_merge、delete 等)。
ILM 的五个阶段
| 阶段 | 触发条件 | 典型操作 | 节点角色 |
|---|---|---|---|
| hot | 索引活跃写入 | rollover(按大小/时间滚动) | data_hot |
| warm | 不再写入,仍常查询 | shrink(缩减分片)、force_merge(合并段) | data_warm |
| cold | 偶尔查询 | searchable_snapshot(可搜索快照) | data_cold |
| frozen | 极少查询 | freeze(7.x)/ searchable_snapshot(8.x) | data_frozen |
| delete | 超过保留期 | delete(永久删除) | — |
注意:frozen 阶段从 7.12 版本正式引入,8.x 中推荐用 searchable snapshot 替代 freeze 操作。
如何创建 ILM 策略?
通过 _ilm/policy API 创建策略,指定每个阶段的 min_age 和 actions:
jsonPUT _ilm/policy/log_retention_policy { "policy": { "phases": { "hot": { "min_age": "0ms", "actions": { "rollover": { "max_size": "50gb", "max_age": "7d", "max_docs": 100000000 }, "set_priority": { "priority": 100 } } }, "warm": { "min_age": "30d", "actions": { "shrink": { "number_of_shards": 1 }, "force_merge": { "max_num_segments": 1 }, "set_priority": { "priority": 50 } } }, "cold": { "min_age": "90d", "actions": { "searchable_snapshot": { "snapshot_repository": "my_backup" }, "set_priority": { "priority": 0 } } }, "delete": { "min_age": "180d", "actions": { "delete": {} } } } } }
关键参数说明:
min_age:索引进入该阶段需等待的最短时间,从索引进入上一阶段算起(不是从索引创建时间算)rollover:在 hot 阶段滚动创建新索引,三个条件满足任一即触发shrink:在 warm 阶段将分片数缩减,降低资源占用force_merge:合并段文件,减少文件句柄和查询开销searchable_snapshot:将索引转为快照挂载,大幅降低存储成本
如何将 ILM 策略绑定到索引?
有两种方式:索引模板(Index Template)和 Data Stream。
方式一:索引模板绑定
jsonPUT _index_template/log_template { "index_patterns": ["app-log-*"], "priority": 500, "template": { "settings": { "index.lifecycle.name": "log_retention_policy", "index.lifecycle.rollover_alias": "app-log", "number_of_shards": 3, "number_of_replicas": 1 } } }
创建初始索引时,需以 000001 结尾才能触发 rollover:
jsonPUT app-log-000001 { "aliases": { "app-log": { "is_write_index": true } } }
方式二:Data Stream 绑定(推荐 7.9+)
Data Stream 天然支持 ILM,创建时直接关联策略:
jsonPUT _data_stream/app-logs { "index_template": "log_template" }
写入 Data Stream 时,自动在背后创建 backing index,ILM 自动管理这些 backing index 的生命周期。Data Stream 的优势在于写入时无需关心底层索引名称,滚动完全自动化。
如何监控和排查 ILM?
查看所有索引的 ILM 状态:
jsonGET _ilm/explain?pretty
查看特定索引的 ILM 阶段和下一步操作:
jsonGET _ilm/explain/my-index-000001?pretty
常见排查思路:
- ILM 不生效:检查
indices.lifecycle.poll_interval(默认 10 分钟),策略变更后需等待轮询周期 - 索引卡在某个阶段:用
_ilm/explain查看step_info中的错误原因,常见原因是目标节点角色未配置 - rollover 未触发:确认索引名以数字结尾(如
000001)且设置了is_write_index: true - shrink 失败:目标分片数必须是原分片数的因子,且索引必须先设为只读
手动推进 ILM 步骤(排查用):
jsonPOST _ilm/retry/my-index-000001
ILM 配置有哪些常见坑?
-
min_age 的理解偏差:min_age 是从索引进入上一阶段开始计时,不是索引创建时间。比如 warm 阶段
min_age: 30d指的是进入 hot 阶段 30 天后(若 hot 阶段无 min_age 限制),而非索引创建 30 天后 -
allocate 语法变更:7.x 中用
allocate.include/require分配节点,8.x 已废弃,改用节点角色自动路由(配置data_hot/data_warm/data_cold角色,ILM 自动迁移) -
节点角色互斥:
data_hot/data_warm/data_cold不能与旧版data角色同时配置,需搭配data_content使用 -
shrink 前必须只读:执行 shrink 前索引必须设为
index.blocks.write: true,否则会失败 -
Data Stream 不可删除单条数据:Data Stream 是追加模型,不支持按文档 ID 删除,只能通过 ILM 删除整个 backing index
追问:frozen 阶段和 cold 阶段有什么区别?
cold 阶段的数据仍以完整分片存储在节点磁盘上,查询性能较好但存储成本高。frozen 阶段使用 searchable snapshot,数据存储在快照仓库中,查询时按需从快照加载缓存,存储成本极低但查询延迟较高。简单说:cold 是"低频但随时可查",frozen 是"几乎不查但保留可搜索"。