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 归档的完整数据流与阶段迁移路径:

ILM Hot-Warm-Cold-Frozen 架构流程 日志采集 Hot 阶段 SSD · 写入 · 滚动 Warm 阶段 HDD · 合并 · 收缩 Cold 阶段 HDD · 可搜索快照 Frozen 对象存储 时间 → 0~1天 1~30天 30~90天 90天+ 各阶段核心动作说明 • Hot: rollover (max_size/max_age/max_docs) → 控制索引分片大小 • Warm: force_merge (max_num_segments=1) + shrink (number_of_shards=1) → 减少段文件和分片数 • Cold: searchable_snapshot → 创建可搜索快照,本地只保留缓存 • Frozen: searchable_snapshot + delete → 完全依赖对象存储,本地不保留副本 存储成本与查询性能权衡曲线 Hot (SSD): 成本 10x, 查询延迟 <10ms Warm (HDD): 成本 2x, 查询延迟 50~200ms Cold (HDD+快照): 成本 1x, 查询延迟 500ms~2s Frozen (对象存储): 成本 0.1x, 查询延迟 2~10s (首次加载)

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 万元。