Index Lifecycle Management(ILM)实战

22 May 2026 – wusfe · 4 min read

Index Lifecycle Management(ILM)实战

运维 ES 最烦的事情之一:每天建新索引、删旧索引、处理数据迁移。如果是日志类数据,每天一个 log-2025-06-01log-2025-06-02……手动管理会死人的。

ILM(索引生命周期管理)就是 ES 内置的自动化引擎:定义规则 → 自动执行 hot → warm → cold → delete,全程不需要人介入。

ILM 的四个阶段

Hot(热) → Warm(温) → Cold(冷) → Delete(删)
  ↑           ↑           ↑            ↑
写入活跃     只读         很少查询     滚蛋
SSD/高性能   普通磁盘     廉价存储

Hot 阶段

索引正在被频繁写入。注重写入性能和快速可见。

  • 通常 SSD,高 IOPS
  • refresh_interval: 1s
  • 副本数 1+

Warm 阶段

索引不再写入,但仍经常被查询。

  • 可以迁到普通磁盘
  • forcemerge 到较少 segment,优化查询
  • 缩减副本(如果查询负载不高)

Cold 阶段

数据几乎不查了,但出于合规需要保留。

  • 迁到最便宜的存储
  • 甚至可以 searchable snapshot 挂载快照(不占本地磁盘)

Delete 阶段

数据超过保留期限,自动删除。

实战:日志索引 30 天生命周期

假设日志每天产生一个新索引,保留 30 天。规则:

  • Hot:写入 7 天
  • Warm:第 8 天转为只读,forcemerge
  • Cold:第 15 天迁到冷节点
  • Delete:第 30 天自动删除

第一步:配置 ILM Policy

PUT /_ilm/policy/logs_policy
{
  "policy": {
    "phases": {
      "hot": {
        "min_age": "0ms",
        "actions": {
          "rollover": {
            "max_size": "50GB",
            "max_age": "1d"
          },
          "set_priority": { "priority": 100 }
        }
      },
      "warm": {
        "min_age": "7d",
        "actions": {
          "forcemerge": { "max_num_segments": 1 },
          "shrink": { "number_of_shards": 1 },
          "allocate": {
            "require": { "data": "warm" }
          },
          "set_priority": { "priority": 50 }
        }
      },
      "cold": {
        "min_age": "15d",
        "actions": {
          "allocate": {
            "require": { "data": "cold" }
          },
          "set_priority": { "priority": 0 }
        }
      },
      "delete": {
        "min_age": "30d",
        "actions": {
          "delete": {}
        }
      }
    }
  }
}

关键字段解释:

动作 作用
rollover 索引达到 50GB 或 1 天后自动滚动(创建新索引)
forcemerge 合并为 1 个 segment,搜索性能最优
shrink 缩减分片数,减少集群资源占用
allocate 把索引迁到指定标签的节点
delete 删除索引

第二步:创建 Index Template 绑定 Policy

PUT /_index_template/logs_template
{
  "index_patterns": ["logs-*"],
  "data_stream": {},
  "template": {
    "settings": {
      "index.lifecycle.name": "logs_policy",
      "number_of_shards": 1,
      "number_of_replicas": 1
    }
  }
}

第三步:创建初始索引

PUT /logs-000001
{
  "aliases": {
    "logs_write": { "is_write_index": true }
  }
}

之后 ILM 会自动创建 logs-000002logs-000003……并按时执行各阶段操作。

第四步:查 ILM 状态

# 查看某个索引当前在哪个阶段
GET /logs-000001/_ilm/explain

# 查看 policy 的当前运行情况
GET /_ilm/policy/logs_policy

# 手动触发迁移到下一阶段
POST /logs-000001/_ilm/retry

Rollover:滚动索引的核心

Rollover 是 ILM 最关键的一环——它在索引达到一定条件时自动创建一个新索引,并把写入流量切过去。

PUT /logs_write/_rollover
{
  "conditions": {
    "max_size": "50GB",
    "max_age": "1d",
    "max_docs": 10000000
  }
}

满足任一条件即触发滚动。三种条件建议同时使用:

  • max_size:索引太大,搜索变慢 → 滚动
  • max_age:按天分割,方便管理 → 滚动
  • max_docs:文档数太多,segment 碎片化 → 滚动

与其他索引方案对比

方案 优点 缺点
ILM 全自动,策略统一 需要 7.x+ 版本
Curator(老方案) 灵活,可自定义脚本 需要外部 cron,已不再维护
手动脚本 完全可控 运维负担重,易出错
Data Stream(ES 7.9+) 与 ILM 深度集成,自动管理后备索引 只适合时序数据

Data Stream:ILM 的最佳搭档

如果你所有数据都是时序追加的(日志、指标、事件),Data Stream 比直接管理索引更省心:

// 创建 data stream(自动绑定 ILM + rollover)
PUT /_index_template/logs_template
{
  "index_patterns": ["logs-*"],
  "data_stream": {},  // 标记为 data stream
  "template": {
    "settings": { "index.lifecycle.name": "logs_policy" }
  }
}

// 写入时直接往 data stream 写
POST /logs/_doc
{ "@timestamp": "2025-06-01T10:00:00Z", "message": "server started" }

// ES 自动路由到 logs 的下一个后备索引

Data Stream 特点:

  • 只能追加,不能 update(完美匹配日志场景)
  • 自动管理后备索引的创建、滚动和删除
  • @timestamp 字段必须存在

常见坑

坑 1:shrink 后节点磁盘空间不够

Shrink 需要先把所有分片迁到一个节点再合并为一个。如果 8 个分片共 40GB,shrink 目标节点需要 40GB 可用空间。

解决:shrink 前确保目标节点有足够盘,或者用 number_of_shards: 1 从根源上避免。

坑 2:rollover 条件配得太大

max_size: 500GB + max_age: 90d——等你哪天想删数据时,一个 500GB 的索引删了集群半天喘不过气。

解决:控制单索引大小在 30-50GB 以内。用小索引容易管理,删除也快。

坑 3:忘了配 delete 阶段

热 → 温 → 冷都配好了,唯独没配 delete。磁盘满了才想起来。

解决:ILM Policy 上线前必须四个阶段都确认一遍。

总结

ILM 解决的是"人管索引太累"的问题。规划三原则:

  1. 小步快滚——索引达到 30-50GB 就滚动,别让它长成巨无霸
  2. 四个阶段都要配——特别是 delete,磁盘满了救不回来
  3. Data Stream 优先——如果是时序数据,用 Data Stream 比手动管理索引省一个数量级的工作量