导读:本期聚焦于小伙伴创作的《如何用Elasticsearch索引生命周期管理实现冷热数据分离?》,敬请观看详情。时序数据量持续增长后,集群会同时承载高频写入与低频查询,如果所有索引都放在同样的硬件上,要么浪费高性能节点,要么拖慢历史查询。Elasticsearch 提供了索引生命周期管理(ILM)机制,可以通过定义策略自动完成索引在 hot、warm、cold、delete 四个阶段的流转。本文会从冷热分离的架构设计入手,说明节点角色划分、分片分配过滤规则,再结合一个完整的 ILM 策略示例,演示如何让索引按时间或大小自动从热节点迁移到冷节点。同时也会分析生命周期管理中常见的坑,比如滚动条件配置不当导致索引无限膨胀、冷节点没有足够副本、策略更新后历史索引不生效等,并给出对应的排查思路和调整方法。读完你能够直接为自己的日志或指标数据搭建一套可落地的冷热分离方案。

对于每天产生数十 GB 甚至上百 GB 日志或指标数据的团队来说,Elasticsearch 集群的存储成本与查询性能往往是一对矛盾。把所有数据都放在 SSD 节点上,半年后的账单会非常难看;但把历史数据直接移到机械盘,又会拖慢偶尔的全文检索。实际上,数据本身有明显的冷热属性:最近几天甚至几小时的索引有大量写入和频繁查询,而一个月前的索引几乎不会更新,查询频率也低很多。Elasticsearch 从 6.6 版本开始把索引生命周期管理(Index Lifecycle Management,ILM)作为内置功能提供,目的就是让索引能够在 hot、warm、cold、delete 四个阶段之间自动流转,配合不同硬件配置的节点,实现真正的冷热分离。

如何用Elasticsearch索引生命周期管理实现冷热数据分离?

在动手配置 ILM 之前,需要先把集群的节点角色划分清楚。最简单的做法是给热节点打上 data_hot 角色,给冷节点打上 data_cold 角色,还可以根据需要设置 data_warmdata_frozen。每个节点可以在 elasticsearch.yml 中配置 node.roles,比如热节点写成 node.roles: [ data_hot, ingest, master ],冷节点写成 node.roles: [ data_cold ]。但仅靠角色并不能阻止分片分配,还需要在节点的配置或启动参数中设置属性,例如热节点设置 node.attr.temperature: hot,冷节点设置 node.attr.temperature: cold。这些自定义属性会被索引的分片分配过滤规则使用,保证索引在正确阶段只落在正确类型的节点上。如果没有这一步,ILM 策略执行时只会修改索引的查询状态而不会真正迁移分片。

另一种常见做法是利用 zone 或 rack 级别的感知属性做更细粒度的调度,不过对于冷热分离,temperature 属性已经足够直观。需要注意的是,冷节点通常使用大容量机械盘或高密度存储服务器,CPU 和内存可以适当降低,但网络带宽不能太差,因为迁移分片时需要跨节点复制数据。另外,冷节点最好也加入 data_content 角色或者保持默认的 data 角色,否则专门用于序列化数据的 data_cold 角色在某些版本中无法直接接收常规索引。

ILM 策略如何定义冷热阶段

ILM 策略本质上是一个描述索引生命周期规则的 JSON 文档,通常使用 Kibana 的图形界面或者通过 REST API 创建。策略中可以指定每个阶段进入的条件、要执行的动作以及优先级。以最常见的时序场景为例,策略会先定义一个 hot 阶段:当索引大小达到 30GB 或者文档数量超过 1 亿时触发 rollover,创建新索引继续写入,旧索引进入 warm 阶段。warm 阶段可以设置索引为只读、强制合并段、缩小分片数,并设置分片分配过滤到 warm 节点。cold 阶段进一步将索引移动到冷节点,并可能关闭索引或改为可搜索快照。最后 delete 阶段设置一个保留天数,到期后自动删除索引。

下面是一个完整的 ILM 策略示例,它演示了从 hot 自动滚动到 warm 再到 cold 最后删除的完整生命周期。通过 Kibana 的 Dev Tools 执行以下请求即可创建策略:

PUT _ilm/policy/logs-cold-hot-policy
{
  "policy": {
    "phases": {
      "hot": {
        "min_age": "0ms",
        "actions": {
          "rollover": {
            "max_age": "1d",
            "max_size": "30gb",
            "max_docs": 100000000
          },
          "set_priority": {
            "priority": 100
          }
        }
      },
      "warm": {
        "min_age": "3d",
        "actions": {
          "forcemerge": {
            "max_num_segments": 1
          },
          "shrink": {
            "number_of_shards": 1
          },
          "allocate": {
            "number_of_replicas": 1,
            "require": {
              "temperature": "warm"
            }
          },
          "set_priority": {
            "priority": 50
          }
        }
      },
      "cold": {
        "min_age": "15d",
        "actions": {
          "allocate": {
            "number_of_replicas": 0,
            "require": {
              "temperature": "cold"
            }
          },
          "set_priority": {
            "priority": 20
          }
        }
      },
      "delete": {
        "min_age": "45d",
        "actions": {
          "delete": {}
        }
      }
    }
  }
}

上面的策略中,min_age 是相对于索引创建时间还是 rollover 之后的新索引?这取决于索引是否被 rollover。对于被管理的索引,ILM 会使用索引的 index.lifecycle.indexing_complete 或原始索引的创建时间作为基准。通常我们建议在写入别名上关联 ILM 策略,这样 rollover 生成的每个新索引都会自动套用同一策略,并且 min_age 是从每个索引自己的创建时间开始计算。因此不会出现所有历史索引在同一时间突然涌入下一个阶段,而是逐个索引到期后自动流转。这也是为什么 ILM 适合大规模时序数据的原因之一。

创建索引模板并关联别名

策略定义好之后,还需要告诉 Elasticsearch 哪些索引要使用这个策略。推荐做法是创建一个索引模板,将 ILM 策略名称和写入别名绑定到模板中。这样新写入的索引会自动匹配模板,并使用别名进行读写。索引模板中还需要设置 index.routing.allocation.require.temperature 的初始值为 hot,确保新索引在刚创建时只分配到热节点上。同时不要在模板中指定具体的索引名,而是使用通配模式,例如 logs-app-*

下面是一个索引模板的示例,注意模板中同时定义了 settings 和 mappings,并指定了 ILM 策略名称和 rollover 别名:

PUT _index_template/logs-cold-hot-template
{
  "index_patterns": ["logs-cold-hot-*"],
  "template": {
    "settings": {
      "index.lifecycle.name": "logs-cold-hot-policy",
      "index.lifecycle.rollover_alias": "logs-cold-hot-write",
      "index.routing.allocation.require.temperature": "hot",
      "number_of_shards": 3,
      "number_of_replicas": 1
    },
    "mappings": {
      "properties": {
        "@timestamp": {
          "type": "date"
        },
        "message": {
          "type": "text"
        },
        "level": {
          "type": "keyword"
        },
        "host": {
          "type": "keyword"
        }
      }
    }
  }
}

建立模板后,需要手动创建第一个索引并指定别名为 logs-cold-hot-write,同时设置 is_write_index 为 true。后续所有写入都通过这个别名进行,rollover 动作会自动把写索引切换到新索引。第一个索引的初始名称可以是 logs-cold-hot-000001,创建请求如下:

PUT logs-cold-hot-000001
{
  "aliases": {
    "logs-cold-hot-write": {
      "is_write_index": true
    }
  }
}

之后就可以通过 logs-cold-hot-write 别名持续写入数据。当日志量达到 hot 阶段设定的 rollover 条件时,Elasticsearch 会自动创建 logs-cold-hot-000002,并将旧索引的写状态移除。旧索引的 min_age 从它创建那一刻开始计时,到了 3 天之后就会进入 warm 阶段,执行 forcemerge、shrink 和迁移到 warm 节点的动作。这里有一个细节:如果旧索引的主分片数大于 1,shrink 动作需要先分配到一个单独的节点,并且在 shrink 之前会先执行 forcemerge,整个过程会增加一些资源开销。因此如果数据量不大,可以省略 shrink,只保留 forcemerge 和 allocate。

验证索引阶段流转与常见问题排查

配置完成后,可以通过 GET _ilm/status 查看 ILM 是否正常运行,通过 GET logs-cold-hot-000001/_ilm/explain 查看某个索引当前所处的阶段、下一步动作以及可能卡住的原因。如果发现索引一直没有从 hot 流转到 warm,首先检查 index.routing.allocation.require.temperature 的值是否与 warm 节点的 node.attr.temperature 匹配。很多故障都是因为节点属性拼写不一致,例如模板里写的是 hot 而节点上配置的是 data_hot。另外,如果集群里根本没有 warm 或 cold 节点,allocate 动作会一直等待,ILM 会进入 error 或 retry 状态,此时需要先添加对应的节点再重试该索引。

另一个常见的误区是把删除阶段设置得太短,导致索引在滚动发生后很快被自动删除,数据丢失。ILM 的 min_age 是相对于索引创建时间的,而不是相对于进入该阶段的时间。例如 hot 阶段 min_age: 0ms,warm 阶段 min_age: 3d,cold 阶段 min_age: 15d,delete 阶段 min_age: 45d,那么一个索引在创建后第 3 天进入 warm,第 15 天进入 cold,第 45 天被删除。这个时间线是线性的,不会因为前面的阶段延迟而顺延。因此设置保留时间时要充分考虑从写入到删除的总时长,而不是只考虑冷阶段停留多少天。

对于已经存在的大量历史索引,如果希望它们也应用冷热分离策略,不能直接修改策略的 min_age 来追溯处理已经超龄的索引,因为 ILM 只会评估索引创建时间与当前时间的差值,如果已经超过 delete 阶段的 min_age,可能会立即触发删除。这时候应该先调整策略,或者手动将历史索引的 index.lifecycle.name 改为新策略,然后使用 POST /logs-old-*/_ilm/retry 逐步推进。另外注意冷节点上的索引副本数如果设为 0,会降低查询并发能力,但能大幅节省存储。如果冷阶段偶尔有全文检索需求,建议保留 1 个副本或者改用可搜索快照,把索引以快照形式挂载到内存中提供只读查询,代价是首次查询会有额外延迟。

最后需要强调的一点是,ILM 本身不负责节点间的硬件监控或自动扩容,它只根据策略中定义的规则触发分片分配和索引操作。冷热分离的底层依赖 Elasticsearch 的 shard allocation filtering 机制,所以任何情况下都能通过 GET _cluster/allocation/explain 分析分片为什么没有从热节点迁移到冷节点。结合 ILM explain 输出,基本可以定位到是策略没有触发、节点属性不匹配、磁盘水位过高还是分片正在恢复中。掌握这两个排查工具,冷热分离的排障效率会提升很多。

Elasticsearch_ILM冷热数据分离索引生命周期修改时间:2026-08-13 05:10:03

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。