你是不是也遇到了这样的烦恼:系统运行时间越长,产生的日志、指标等时序数据就越多,像滚雪球一样,把你的存储空间吃得一干二净?更头疼的是,这些海量数据不仅存储成本蹭蹭上涨,时间久了,查询分析也变得越来越慢,甚至卡顿,严重影响了问题排查和系统监控的效率。
别担心,如果你正在使用 Elasticsearch (ES) 来存储和分析这些时序数据,那么它内置的索引生命周期管理 (Index Lifecycle Management, ILM) 功能就是你的得力助手!它就像一个智能管家,能帮你自动、高效地管理这些数据的“生老病死”,在保证数据可用性的前提下,大幅优化存储成本和查询性能。
什么是 ILM?它凭啥能管理时序数据?
想象一下数据的生命周期,就像人的生命一样,有“年轻力壮”的活跃期,也有“退休养老”的归档期,最后可能还需要“寿终正寝”。对于时序数据(比如日志、监控指标)来说,这个特点尤其明显:
- 近期数据(Hot):刚产生的数据,访问最频繁,需要快速写入和查询,通常存储在性能最好的硬件上(比如SSD)。
- 中期数据(Warm):数据变旧了一些,访问频率降低,但偶尔还需要查询,可以接受稍慢的查询速度,可以考虑迁移到成本稍低的存储上(比如大容量HDD)。
- 长期数据(Cold/Frozen):数据非常陈旧,几乎不再访问,但可能因为合规性要求或其他原因需要长期保留。查询需求极低,甚至可以接受非常慢的查询或只读访问,目标是最低的存储成本(比如对象存储)。
- 过期数据(Delete):数据完全失去价值,可以直接删除以释放空间。
ILM 就是 Elasticsearch 提供的一套自动化管理机制,让你能够根据数据的“年龄”和“状态”,预先定义好一套规则(称为策略 Policy),然后将这个策略应用到你的索引上。ES 就会像个不知疲倦的管理员,定期检查索引,并根据策略自动执行相应的操作,推动索引在不同的生命周期阶段 (Phase) 之间流转。
一个典型的 ILM 策略包含以下几个核心部分:
- 策略 (Policy):定义了一整套管理规则,包含多个阶段。
- 阶段 (Phase):代表数据生命周期的不同时期,常见的有
hot
、warm
、cold
、frozen
和delete
。 - 动作 (Action):在每个阶段可以执行的具体操作,比如
rollover
(滚动索引)、shrink
(收缩分片)、forcemerge
(强制合并段)、allocate
(分配到不同节点)、searchable_snapshot
(创建可搜索快照)、delete
(删除索引)等。
ILM 如何为你的日志数据“续命”和“瘦身”?
让我们通过一个典型的日志管理场景,看看 ILM 是如何大显身手的。
假设你的应用日志索引模式是 applogs-%{+yyyy.MM.dd}-000001
,并且你希望实现以下管理目标:
- Hot 阶段:日志 активно 写入,需要高性能查询。当索引达到 50GB 或 7 天时,自动创建一个新索引继续写入(Rollover)。
- Warm 阶段:7 天后的数据进入 Warm 阶段。访问频率降低,为了节省资源和提高查询效率(针对旧数据),将索引分片数减少到 1,并强制合并段。同时,将数据迁移到成本较低的“暖节点”上。
- Cold 阶段:90 天后的数据进入 Cold 阶段。访问极少,但需要保留。将其迁移到更便宜的“冷节点”存储上,并设置为只读。
- Delete 阶段:365 天后的数据不再需要,自动删除。
下面我们来分解一下 ILM 在这个过程中扮演的角色:
阶段一:Hot - 性能优先,写入高峰
这是数据的“黄金时期”。新日志源源不断地写入,你也需要能够快速地搜索最近的日志来排查线上问题。
- 关键动作:
rollover
- 为什么需要 Rollover? 如果你一直往一个索引里写数据,这个索引会变得越来越大。巨大的索引不仅写入性能会下降,查询性能也会变差,而且一旦出问题恢复起来也更困难。想象一下,一个房间无限堆积货物,找东西和放东西都会越来越难。
- ILM 怎么做? 你可以设置
rollover
条件,比如max_size: 50gb
或max_age: 7d
或max_docs: 100000000
。当索引满足任一条件时,ILM 会自动:- 创建一个新的索引(例如,
applogs-2023.10.27-000002
)。 - 将索引别名(比如
applogs-write
)指向这个新索引。 - 后续的写入请求就会自动路由到新索引。
- 创建一个新的索引(例如,
- 效果: 保持写入索引的大小可控,确保了写入和查询的性能。这就像是仓库满了自动开一个新仓库,并告诉所有人新货往新仓库放。
阶段二:Warm - 优化资源,降低成本
数据不再频繁写入,访问频率也下降了。这时候的主要目标是优化资源占用和存储成本,同时保持数据可查询。
- 关键动作:
allocate
、shrink
、forcemerge
allocate
: 你可以配置 ILM 将索引迁移到具有不同硬件配置的节点上。比如,将 Warm 阶段的索引分配到使用大容量 HDD 而不是 SSD 的“暖节点” (Warm Nodes) 上。ES 通过节点属性 (Node Attributes) 来实现这一点(例如,node.attr.data: warm
)。这就像把不常用的东西从市中心的昂贵仓库搬到郊区的廉价仓库。shrink
: Hot 阶段为了写入吞吐量,你可能设置了较多的主分片。进入 Warm 阶段后,写入停止,可以将主分片数量收缩到一个较小的值(通常是 1)。比如从 5 个分片收缩到 1 个。这会减少集群的元数据开销和资源消耗。注意:收缩前索引必须是只读,并且每个节点上必须有索引所有主分片的副本。forcemerge
: Lucene(ES 底层搜索引擎)会将数据写入称为“段 (Segment)”的小文件。随着数据写入和更新,段的数量会增多。太多的段会消耗更多的内存和文件句柄,并可能拖慢查询速度。forcemerge
操作会将这些小段合并成更少、更大的段,并可以永久删除已标记为删除的文档。这能释放磁盘空间,并显著提高查询性能(特别是对于不再写入的索引)。这个过程比较消耗 I/O 和 CPU,适合在 Warm 或 Cold 阶段执行。- 效果: 通过迁移到更便宜的存储、减少分片开销、优化段文件,有效降低了资源占用和成本,同时还可能提升了对旧数据的查询速度。
阶段三:Cold - 长期归档,最低成本
数据已经很老了,几乎没人会查,但可能因为法规或特殊需求需要保留很长时间。此时,极致的成本优化是首要目标。
- 关键动作:
allocate
、freeze
(旧版) /searchable_snapshot
(推荐)allocate
: 类似于 Warm 阶段,可以将索引分配到成本最低的“冷节点” (Cold Nodes) 上。freeze
(旧版,逐渐被替代):freeze
操作会关闭索引,然后重新打开它,但将其加载到内存中的数据结构最小化。这会显著减少内存占用,但查询速度会变得非常慢,因为它需要在查询时才加载必要的数据结构。冻结的索引是只读的。searchable_snapshot
(推荐): 这是更现代、更强大的方式。ILM 可以自动为索引创建可搜索快照 (Searchable Snapshots),并将这些快照存储在低成本的对象存储(如 AWS S3, Azure Blob Storage, Google Cloud Storage, MinIO 等)中。原始索引可以随后删除。当需要查询这些数据时,ES 可以直接在对象存储上“挂载”快照进行查询,而无需将所有数据恢复到 ES 集群的磁盘上。这极大地降低了存储成本,同时仍然保留了查询能力(尽管查询速度会比 Hot/Warm 慢)。你甚至可以创建一个frozen
阶段专门用于管理这些可搜索快照。- 效果: 将长期数据归档到最便宜的存储介质(如对象存储)中,最大限度地降低存储成本,同时通过可搜索快照等技术保留了按需查询的能力。
(可选) 阶段四:Frozen - 极寒冰封,按需解冻
这是 Cold 阶段的延伸,通常完全依赖于可搜索快照。数据完全存储在对象存储中,集群本身几乎不占用存储资源。查询时需要先“挂载”快照,性能最低,但成本也最低。
阶段五:Delete - 清理空间,功成身退
当数据保存期限已到,不再有任何价值时,ILM 可以自动执行 delete
操作,彻底删除索引,释放存储空间。
- 关键动作:
delete
- ILM 怎么做? 在策略的
delete
阶段设置一个最小年龄(min_age
),例如365d
。一旦索引从上一个阶段(比如 Cold)进入 Delete 阶段,并且其年龄达到了 365 天,ILM 就会自动删除该索引。 - 效果: 自动化数据清理,避免无用数据无限期占用宝贵的存储资源。
- ILM 怎么做? 在策略的
实战演练:创建一个简单的日志 ILM 策略
虽然在 Kibana 界面上点几下就能创建 ILM 策略,但了解其背后的 JSON 结构也很有帮助。下面是一个简化的示例策略 my_log_policy
:
PUT _ilm/policy/my_log_policy
{
"policy": {
"phases": {
"hot": {
"min_age": "0ms",
"actions": {
"rollover": {
"max_size": "50gb",
"max_age": "7d"
},
"set_priority": { // 热阶段索引优先级最高,优先恢复
"priority": 100
}
}
},
"warm": {
"min_age": "7d", // 进入 warm 阶段的最小时间
"actions": {
"allocate": { // 分配到 warm 节点
"require": {
"data": "warm"
}
},
"shrink": { // 收缩到 1 个主分片
"number_of_shards": 1
},
"forcemerge": { // 合并段到 1 个,提升查询性能
"max_num_segments": 1
},
"set_priority": {
"priority": 50
}
}
},
"cold": {
"min_age": "90d",
"actions": {
"allocate": { // 分配到 cold 节点
"require": {
"data": "cold"
}
},
"set_priority": {
"priority": 0
}
// 这里可以添加 searchable_snapshot 动作
// "searchable_snapshot": {
// "snapshot_repository": "my_s3_repository"
// }
}
},
"delete": {
"min_age": "365d",
"actions": {
"delete": {}
}
}
}
}
}
创建好策略后,你还需要创建一个索引模板 (Index Template),将这个策略应用到所有匹配 applogs-*
模式的新索引上,并指定用于 rollover
的别名。
PUT _index_template/applogs_template
{
"index_patterns": ["applogs-*"],
"template": {
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1,
"index.lifecycle.name": "my_log_policy", // 应用 ILM 策略
"index.lifecycle.rollover_alias": "applogs-write" // 指定 rollover 别名
}
}
}
最后,你需要手动创建第一个索引并让别名指向它,启动整个流程:
PUT applogs-000001
{
"aliases": {
"applogs-write": {
"is_write_index": true // 标记这是写入别名
}
}
}
之后,ILM 就会接管 applogs-*
索引的生命周期管理了!
拥抱 ILM 的核心优势
总结一下,使用 Elasticsearch ILM 管理时序数据(尤其是日志和监控数据)能带来实实在在的好处:
- 成本优化显著:通过数据分层(Hot/Warm/Cold/Frozen),将旧数据自动迁移到成本更低的存储介质,特别是结合可搜索快照使用对象存储,能大幅降低存储开销。
- 性能保持稳定:
rollover
机制确保活跃索引大小可控,维持写入和查询性能。forcemerge
优化旧索引的查询速度。 - 自动化管理:设定好策略后,ILM 自动执行,无需人工干预索引的迁移、优化和删除,大大减少运维负担和出错风险。
- 灵活性高:可以根据不同的数据类型和业务需求,定制不同的生命周期策略。
注意事项和最佳实践
- 仔细规划:在实施 ILM 前,充分了解你的数据访问模式、保留策略和成本/性能需求,设计合理的阶段和动作。
- 监控 ILM:使用
GET /<index>/_ilm/explain
API 或 Kibana 的 ILM UI 监控策略执行状态,确保一切按预期进行。 - 资源预留:像
shrink
和forcemerge
这样的操作会消耗资源,确保集群有足够的 CPU 和 I/O 能力来处理这些后台任务,尤其是在高峰时段之外执行。 - 测试先行:在非生产环境充分测试你的 ILM 策略,确认其行为符合预期,再应用到生产环境。
- 节点角色和属性:合理规划和配置 Hot、Warm、Cold 节点的角色和属性,这是实现数据分层的基础。
结语
面对海量的时序数据,特别是日志和监控指标,Elasticsearch 的 ILM 功能提供了一个强大而灵活的自动化解决方案。它不仅仅是简单地删除旧数据,更是一种精细化的管理哲学,通过在数据的整个生命周期中应用不同的策略和动作,实现了成本、性能和可用性之间的最佳平衡。如果你还在为不断增长的日志数据头疼,那么深入了解并用好 ILM,绝对能让你的 ES 集群管理工作事半功倍,既省钱又省心!