Elasticsearch 索引生命周期与冷热架构:从无限膨胀到自动归档的存储治理

一、日志洪流下的存储困境:当 Elasticsearch 变成"数据黑洞"
在云原生可观测性体系中,Elasticsearch 承载着日志、指标、追踪三大支柱数据的存储与检索。然而,随着业务规模扩张,日志写入速率往往远超预期——一个中等规模的微服务集群,日均日志量轻松突破数百 GB。若不加治理,Elasticsearch 集群的存储空间会在数周内被吞噬殆尽。
更棘手的是,日志数据的价值随时间急剧衰减:最近 7 天的日志是故障排查的核心依据,30 天前的日志偶尔用于趋势分析,90 天前的日志几乎只在合规审计时才会被翻阅。但传统的"全量热存"策略,将所有数据都放在高性能 SSD 上,意味着为极少访问的冷数据支付了高昂的存储成本。
索引生命周期管理(Index Lifecycle Management,ILM)与冷热分层架构,正是为解决这一矛盾而生。它通过声明式策略自动管理索引从创建到删除的全生命周期,配合热-温-冷-冻结四级存储层级,实现"热数据高速检索、冷数据低成本归档"的精细化存储治理。
二、ILM 机制与冷热分层的底层原理
2.1 ILM 策略的执行引擎
ILM 策略由一组有序阶段(Phase)和动作(Action)构成。Elasticsearch 内部的 ilm-service 模块以轮询方式(默认 10 分钟间隔)检查所有索引的生命周期状态,评估是否满足阶段切换条件。
stateDiagram-v2
[*] –> Hot: 索引创建
Hot –> Warm: min_age 满足 / rollover 触发
Warm –> Cold: min_age 满足
Cold –> Frozen: min_age 满足
Frozen –> Delete: min_age 满足
state Hot {
[*] –> Rolling
Rolling –> Shrink: rollover 触发
Shrink –> ForceMerge: 可选
}
state Warm {
[*] –> Allocate_Warm
Allocate_Warm –> ReadOnly
}
state Cold {
[*] –> Allocate_Cold
Allocate_Cold –> Freeze_Optional
}
state Frozen {
[*] –> Frozen_Cache
}
关键阶段含义:
| Hot | NVMe SSD | 频繁读写 | Rollover、Force Merge |
| Warm | SATA SSD/HDD | 偶尔读 | Shrink、Read-only |
| Cold | HDD/对象存储 | 极少读 | Freeze、Searchable Snapshot |
| Frozen | 对象存储 | 合规审计 | Searchable Snapshot |
| Delete | — | — | 永久删除 |
2.2 Rollover 机制:索引滚动与分片管理
Rollover 是 ILM 在 Hot 阶段的核心动作。它根据预设条件(最大年龄、最大文档数、最大分片大小)自动创建新索引并将写入切换到新索引,避免单个索引无限膨胀。
sequenceDiagram
participant App as 日志采集端
participant ES as Elasticsearch
participant ILM as ILM Service
App->>ES: 写入 logs-app-000001
Note over ES: 别名 logs-app 指向 000001
ILM->>ES: 检查 rollover 条件
Note over ILM: 条件: max_size=50GB 或 max_age=1d
alt 条件未满足
ILM–>>ILM: 等待下次轮询
else 条件满足
ILM->>ES: 创建 logs-app-000002
ILM->>ES: 原子切换别名指向
Note over ES: 写入自动路由到 000002
end
2.3 冷热分层的节点角色与分片路由
冷热架构依赖节点级别的 node.attr 属性标记,ILM 的 allocate 动作根据这些属性将分片迁移到对应层级的节点。
# elasticsearch.yml 节点配置示例
# 热节点
node.attr.data_tier: hot
# 温节点
node.attr.data_tier: warm
# 冷节点
node.attr.data_tier: cold
分片迁移流程:当索引从 Hot 阶段进入 Warm 阶段时,ILM 发出 allocate 动作,Elasticsearch 的 Allocation Decider 重新计算分片分配方案,将分片从热节点迁移到温节点。迁移过程通过快照-恢复机制完成,保证数据一致性。
三、生产级 ILM 策略与冷热架构实现
3.1 ILM 策略定义
PUT _ilm/policy/logs-lifecycle-policy
{
"policy": {
"phases": {
"hot": {
"min_age": "0ms",
"actions": {
"rollover": {
"max_primary_shard_size": "50gb",
"max_age": "1d"
},
"set_priority": {
"priority": 100
}
}
},
"warm": {
"min_age": "7d",
"actions": {
"allocate": {
"number_of_replicas": 1,
"require": {
"data_tier": "warm"
}
},
"shrink": {
"number_of_shards": 1
},
"forcemerge": {
"max_num_segments": 1
},
"set_priority": {
"priority": 50
}
}
},
"cold": {
"min_age": "30d",
"actions": {
"allocate": {
"require": {
"data_tier": "cold"
}
},
"set_priority": {
"priority": 0
}
}
},
"frozen": {
"min_age": "90d",
"actions": {
"searchable_snapshot": {
"snapshot_repository": "logs-backup"
}
}
},
"delete": {
"min_age": "180d",
"actions": {
"delete": {}
}
}
}
}
}
策略设计要点:
- Hot 阶段:以 max_primary_shard_size: 50gb 触发 Rollover,避免单个分片过大影响恢复速度;同时设置 1 天的 max_age,保证索引粒度可控。
- Warm 阶段:执行 Shrink 将多分片合并为单分片,减少集群元数据开销;Force Merge 将段数压缩到 1,降低查询时的文件句柄消耗。
- Cold 阶段:仅迁移分片到冷节点,不执行 Freeze(避免搜索性能骤降),保留直接查询能力。
- Frozen 阶段:使用 Searchable Snapshot,数据仅存在于对象存储中,按需加载到缓存,存储成本降至最低。
- Delete 阶段:180 天后永久删除,满足大多数合规要求。
3.2 索引模板与别名绑定
PUT _index_template/logs-app-template
{
"index_patterns": ["logs-app-*"],
"template": {
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1,
"lifecycle.name": "logs-lifecycle-policy",
"lifecycle.rollover_alias": "logs-app",
"routing.allocation.require.data_tier": "hot"
},
"mappings": {
"properties": {
"@timestamp": { "type": "date" },
"level": { "type": "keyword" },
"service": { "type": "keyword" },
"message": { "type": "text" },
"trace_id": { "type": "keyword" }
}
}
}
}
初始化首个索引并绑定别名:
PUT logs-app-000001
{
"aliases": {
"logs-app": {
"is_write_index": true
}
}
}
3.3 Searchable Snapshot 配置
PUT _snapshot/logs-backup
{
"type": "gcs",
"settings": {
"bucket": "es-logs-archive",
"client": "gcs-client"
}
}
Searchable Snapshot 的工作原理:查询请求到达 Frozen 节点时,节点从对象存储按需下载所需的数据块到本地缓存(cache),后续相同数据的查询直接命中缓存。缓存采用 LRU 淘汰策略,大小由 searchable_snapshot.cache.size 控制。
3.4 监控 ILM 执行状态
# 查看索引的 ILM 状态
GET logs-app-*/_ilm/explain
# 查看 ILM 执行历史
GET _ilm/history
# 手步重试失败的 ILM 步骤
POST logs-app-000001/_ilm/retry
关键监控指标:
| ilm.status | 索引当前所在阶段 | 长期停留在 Hot |
| ilm.step | 当前执行步骤 | ERROR 状态 |
| ilm.phase_time | 阶段停留时长 | 超过预期 2 倍 |
| store.size | 索引存储大小 | 单分片 > 50GB |
| searchable_snapshot.cache_evictions | 缓存淘汰次数 | 持续高速增长 |
四、存储治理的架构权衡与边界分析
4.1 Rollover 粒度与恢复速度的矛盾
Rollover 的 max_primary_shard_size 直接影响索引粒度。较小的分片(如 25GB)恢复速度快,但索引数量激增,集群元数据膨胀;较大的分片(如 100GB)减少索引数,但故障恢复时间线性增长。生产实践中,50GB 是一个经过验证的平衡点,在大多数硬件配置下可在 10 分钟内完成分片恢复。
4.2 Shrink 操作的停机风险
Shrink 需要先将索引设为 Read-only,然后创建新索引并硬链接段文件。虽然硬链接本身很快,但在 Shrink 过程中索引不可写入。对于持续写入的日志场景,这通常不是问题(因为 Rollover 已将写入切换到新索引),但对于需要回填历史数据的场景,需确保 Shrink 在非写入窗口执行。
4.3 Searchable Snapshot 的查询延迟
Searchable Snapshot 的首次查询延迟取决于对象存储的响应速度和网络带宽。对于 GCS/S3,首次访问一个 50GB 索引的典型延迟在 5-30 秒之间(取决于查询命中的数据块数量)。如果业务要求冷数据的查询延迟在秒级以内,应将数据保留在 Cold 阶段而非进入 Frozen。
4.4 适用边界
ILM 与冷热架构适用于以下场景:
- 日志类时序数据,访问模式随时间明显衰减
- 存储成本敏感,需要将冷数据从 SSD 迁移到 HDD 或对象存储
- 合规要求保留数据 90 天以上,但访问频率极低
不适用场景:
- 频繁更新的业务数据(ILM 的 Rollover 和 Shrink 假设数据是追加写入的)
- 查询延迟要求严格一致的场景(冷热层查询性能差异显著)
- 小规模集群(节点数 < 3,无法有效分层)
五、总结
Elasticsearch ILM 与冷热分层架构,将日志存储从"全量热存"的粗放模式,升级为"按价值分层、按策略流转"的精细化治理模式。核心落地路线如下:
存储治理不是一次性工程,而是持续优化的过程。随着业务规模变化,需要定期审视 ILM 策略的阶段时长和 Rollover 条件,在存储成本与查询性能之间找到动态平衡点。

