4. 索引生命周期管理(ILM)基础:Hot-Warm-Cold-Frozen架构设计,索引滚动策略与阶段迁移
在ELK日志检索场景中,日志数据具有明显的“热尾”特征:近几小时的数据被高频查询,几天前的数据查询频率骤降,而数月前的数据几乎不再被检索。如果对所有数据采用相同的存储策略,不仅浪费昂贵的SSD资源,还会拖慢集群性能。索引生命周期管理(ILM)正是解决这一问题的核心机制。
4.1 Hot-Warm-Cold-Frozen 四层架构
ILM将索引的生命周期划分为四个阶段,每个阶段对应不同的存储介质、副本数和计算资源,从而实现成本与性能的最佳平衡。
| 阶段 | 存储介质 | 典型保留时长 | 查询频率 | 写入/更新 | 成本等级 |
|---|---|---|---|---|---|
| Hot | SSD / 高性能NVMe | 最近 6~24 小时 | 极高(实时监控、告警) | 支持写入与更新 | 高 |
| Warm | HDD / 混合存储 | 最近 7~30 天 | 中等(日常分析、报表) | 只读,不写入 | 中 |
| Cold | HDD / 低成本云存储 | 最近 30~90 天 | 低(合规审计、回溯) | 只读,可手动合并 | 低 |
| Frozen | 对象存储(S3/GCS/MinIO) | 90 天以上 | 极低(年度归档、法律取证) | 不可写入,可搜索快照 | 极低 |
关键认知:Frozen 阶段并非传统意义上的“冷数据”,而是利用 Elasticsearch 的“可搜索快照(Searchable Snapshots)”功能,将数据存储在对象存储中,仅在查询时按需加载。这使得无限期保留日志成为可能,而存储成本仅为 SSD 的 1/10 甚至更低。
4.2 索引滚动策略(Rollover)
滚动策略决定了何时创建一个新的索引来替代当前写入的索引。合理的滚动策略可以避免单个索引过大,从而控制分片大小、缩短恢复时间,并让 ILM 阶段迁移更加平滑。
滚动触发条件通常基于以下三个维度(满足任一即触发):
- 最大文档数:例如 5000 万条文档。
- 最大索引大小:例如 50 GB。
- 最大时长:例如 24 小时。
以下是一个典型的滚动策略配置示例:
PUT _ilm/policy/logs_rolling_policy
{
"policy": {
"phases": {
"hot": {
"min_age": "0ms",
"actions": {
"rollover": {
"max_size": "50GB",
"max_age": "1d",
"max_docs": 50000000
},
"set_priority": {
"priority": 100
}
}
}
}
}
}
实战建议:对于日志检索场景,推荐将
max_size 控制在 30~50 GB 之间。过小的分片(<10 GB)会导致集群分片数量膨胀,增加管理开销;过大的分片(>100 GB)则会影响滚动和迁移效率。
4.3 阶段迁移与动作定义
每个阶段都可以定义一组“动作(Actions)”,当索引在该阶段停留的时间超过 min_age 后,ILM 会自动执行这些动作,并将索引迁移到下一阶段。
下表列出了各阶段的核心动作及其作用:
| 阶段 | 核心动作 | 作用说明 |
|---|---|---|
| Hot | rollover、set_priority |
控制索引滚动,设置高优先级确保写入节点优先处理 |
| Warm | allocate、force_merge、shrink |
将分片迁移到 Warm 节点,合并段文件,缩减分片数量 |
| Cold | allocate、freeze、searchable_snapshot |
迁移到 Cold 节点,冻结索引或创建可搜索快照 |
| Frozen | searchable_snapshot、delete |
将数据完全迁移到对象存储,可选删除本地副本 |
以下是一个完整的四阶段 ILM 策略示例:
PUT _ilm/policy/logs_four_tier_policy
{
"policy": {
"phases": {
"hot": {
"min_age": "0ms",
"actions": {
"rollover": {
"max_size": "50GB",
"max_age": "1d"
},
"set_priority": {
"priority": 100
}
}
},
"warm": {
"min_age": "1d",
"actions": {
"allocate": {
"require": {
"data_type": "warm"
}
},
"force_merge": {
"max_num_segments": 1
},
"shrink": {
"number_of_shards": 1
},
"set_priority": {
"priority": 50
}
}
},
"cold": {
"min_age": "30d",
"actions": {
"allocate": {
"require": {
"data_type": "cold"
}
},
"searchable_snapshot": {
"snapshot_repository": "my_s3_repo"
},
"set_priority": {
"priority": 0
}
}
},
"frozen": {
"min_age": "90d",
"actions": {
"searchable_snapshot": {
"snapshot_repository": "my_s3_repo",
"force_merge_index": true
},
"delete": {
"delete_searchable_snapshot": true
}
}
}
}
}
}
注意:Frozen 阶段的
delete 动作会删除本地索引以及可搜索快照的本地缓存副本,但不会删除对象存储中的底层快照数据。如果需要彻底删除归档数据,需要额外管理快照生命周期(SLM)。
4.4 架构流程总览
下图展示了从日志采集到 Frozen 归档的完整数据流与阶段迁移路径:
4.5 索引模板与ILM策略绑定
为了让 ILM 策略自动生效,需要将策略绑定到索引模板。这样,每次通过 Logstash、Filebeat 或 Fluentd 写入新索引时,都会自动应用该策略。
PUT _index_template/logs_template
{
"index_patterns": ["logs-*"],
"template": {
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1,
"index.lifecycle.name": "logs_four_tier_policy",
"index.lifecycle.rollover_alias": "logs-write"
}
}
}
最佳实践:始终使用
index.lifecycle.rollover_alias 指定写入别名。应用程序和采集端只向该别名写入数据,ILM 会自动管理底层索引的创建、滚动和迁移,实现“写入端无感知”的运维体验。
4.6 阶段迁移的触发条件与避坑
阶段迁移并非立即发生,ILM 会定期检查(默认每 10 分钟)索引是否满足迁移条件。以下是常见的迁移延迟原因及解决方案:
- min_age 计算起点:
min_age从索引滚动完成的时间开始计算,而非索引创建时间。如果滚动后立即进入 Warm 阶段,需要设置min_age: "0ms"。 - 节点标签不匹配:Warm/Cold 节点必须通过
node.attr.data_type: warm等自定义属性标记,否则allocate动作会一直等待。 - 分片数过多导致 shrink 失败:
shrink动作要求源索引的分片数必须是目标分片数的整数倍。建议在 Hot 阶段就控制好分片数(如 3 或 6),以便后续 shrink 到 1 或 2。 - 可搜索快照仓库未配置:Cold/Frozen 阶段使用
searchable_snapshot前,必须先创建快照仓库(如 S3 仓库)。
成本优化关键指标:通过 ILM 将 90 天前的日志迁移到 Frozen 阶段,存储成本可降低 80%~90%。以一个日增 500GB 日志的集群为例,仅 Hot 阶段保留 1 天数据(500GB SSD),Warm 保留 29 天(14.5TB HDD),Cold 保留 60 天(30TB HDD+快照),Frozen 保留 180 天(90TB 对象存储)。相比全 SSD 方案,年存储成本可从约 120 万元降至约 25 万元。