Elasticsearch ILM 策略生成器(ILM Policy Generator)设计方案

在 Elasticsearch 生产环境中,索引生命周期管理(ILM, Index Lifecycle Management) 是实现自动化运维的核心功能。然而,手动编写 ILM 策略 JSON 容易出错、难以标准化。

为此,我们设计一套 Elasticsearch ILM 策略生成器(ILM Policy Generator),支持:

  • 可视化配置 ILM 阶段;
  • 自动生成标准 JSON;
  • 导出为模板或直接应用;
  • 支持 Hot-Warm-Cold-Delete 全流程;
  • 适配日志、监控、业务数据等场景。

本文提供一个 可落地的 ILM 策略生成器设计方案 + Python 实现模板


一、目标与核心功能

功能说明
✅ 可视化配置表单式输入,无需手写 JSON
✅ 自动生成策略输出标准 ILM JSON
✅ 多场景模板预设日志、指标、商品等模板
✅ 参数校验检查 min_age 顺序、单位合法性
✅ 导出与应用支持导出 JSON / 直接调用 ES API
✅ 命令行 + Web 两种模式满足不同使用习惯

二、ILM 策略结构回顾

{
  "policy": {
    "phases": {
      "hot": { ... },
      "warm": { ... },
      "cold": { ... },
      "delete": { ... }
    }
  }
}

每个阶段可包含多个 Actions,如 rolloverforcemergeshrinkmigratedelete 等。


三、ILM 策略生成器设计

1. 输入参数模型

参数类型说明
namestring策略名称(如 logs-policy
hot.max_sizestring滚动条件:最大大小(如 50gb
hot.max_agestring滚动条件:最大年龄(如 1d
warm.min_agestring进入 warm 阶段的最小年龄
warm.forcemergebool是否执行 forcemerge
warm.shrinkint是否 shrink 分片数
warm.migratestring迁移到指定 node.attr.zone
cold.min_agestring进入 cold 阶段的最小年龄
cold.migratestring迁移到冷节点
delete.min_agestring删除前最小年龄
delete.deletebool是否删除

四、Python 实现:ILM 策略生成器

文件结构

ilm-generator/
├── generator.py       # 核心生成逻辑
├── templates/         # 预设模板
│   ├── logs.json
│   ├── metrics.json
│   └── products.json
├── cli.py             # 命令行接口
└── web.py             # Web 接口(可选)

1. 核心生成逻辑 generator.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Elasticsearch ILM 策略生成器
"""

import json
from typing import Dict, Optional

class ILMGenerator:
    def __init__(self):
        self.policy = {"policy": {"phases": {}}}
    
    def validate_unit(self, value: str) -> bool:
        """验证时间/大小单位"""
        if not value:
            return True
        units = ['s', 'm', 'h', 'd', 'w', 'kb', 'mb', 'gb', 'tb']
        return any(value.endswith(u) for u in units)
    
    def add_hot_phase(self, max_size: str = None, max_age: str = None):
        """添加 Hot 阶段"""
        if not max_size and not max_age:
            raise ValueError("Hot 阶段必须设置 max_size 或 max_age")
        
        actions = {}
        if max_size:
            if not self.validate_unit(max_size):
                raise ValueError(f"无效大小单位: {max_size}")
            actions['rollover'] = {'max_size': max_size}
        if max_age:
            if not self.validate_unit(max_age):
                raise ValueError(f"无效时间单位: {max_age}")
            actions['rollover'] = actions.get('rollover', {})
            actions['rollover']['max_age'] = max_age
        
        self.policy["policy"]["phases"]["hot"] = {"actions": actions}
        return self
    
    def add_warm_phase(
        self, 
        min_age: str, 
        forcemerge: bool = True, 
        shrink: int = None, 
        migrate_to: str = None
    ):
        """添加 Warm 阶段"""
        if not self.validate_unit(min_age):
            raise ValueError(f"无效时间单位: {min_age}")
        
        actions = {}
        if forcemerge:
            actions['forcemerge'] = {'max_num_segments': 1}
        if shrink:
            actions['shrink'] = {'number_of_shards': shrink}
        if migrate_to:
            actions['migrate'] = {'destination': migrate_to}
        
        self.policy["policy"]["phases"]["warm"] = {
            "min_age": min_age,
            "actions": actions
        }
        return self
    
    def add_cold_phase(self, min_age: str, migrate_to: str = None):
        """添加 Cold 阶段"""
        if not self.validate_unit(min_age):
            raise ValueError(f"无效时间单位: {min_age}")
        
        actions = {}
        if migrate_to:
            actions['migrate'] = {'destination': migrate_to}
        
        self.policy["policy"]["phases"]["cold"] = {
            "min_age": min_age,
            "actions": actions
        }
        return self
    
    def add_delete_phase(self, min_age: str):
        """添加 Delete 阶段"""
        if not self.validate_unit(min_age):
            raise ValueError(f"无效时间单位: {min_age}")
        
        self.policy["policy"]["phases"]["delete"] = {
            "min_age": min_age,
            "actions": {"delete": {}}
        }
        return self
    
    def build(self) -> Dict:
        """生成最终策略"""
        return self.policy
    
    def to_json(self, indent=2) -> str:
        """输出 JSON 字符串"""
        return json.dumps(self.policy, ensure_ascii=False, indent=indent)
    
    def save(self, filepath: str):
        """保存到文件"""
        with open(filepath, 'w', encoding='utf-8') as f:
            f.write(self.to_json())
        print(f"✅ 策略已保存到: {filepath}")
    
    def apply(self, es_client, policy_name: str):
        """直接应用到 Elasticsearch"""
        from elasticsearch import TransportError
        try:
            es_client.ilm.put_lifecycle(name=policy_name, **self.policy)
            print(f"✅ ILM 策略 '{policy_name}' 已创建")
        except TransportError as e:
            print(f"❌ 创建失败: {e}")

2. 命令行接口 cli.py

#!/usr/bin/env python3
import argparse
from generator import ILMGenerator

def main():
    parser = argparse.ArgumentParser(description="Elasticsearch ILM 策略生成器")
    parser.add_argument("--name", required=True, help="策略名称")
    parser.add_argument("--output", help="输出文件路径")
    parser.add_argument("--apply", action="store_true", help="直接应用到 ES")
    
    # Hot 阶段
    parser.add_argument("--hot-max-size", help="Hot: max_size (e.g., 50gb)")
    parser.add_argument("--hot-max-age", help="Hot: max_age (e.g., 1d)")
    
    # Warm 阶段
    parser.add_argument("--warm-min-age", help="Warm: min_age (e.g., 1d)")
    parser.add_argument("--no-forcemerge", action="store_true", help="禁用 forcemerge")
    parser.add_argument("--shrink", type=int, help="shrink 分片数")
    parser.add_argument("--migrate-to", help="迁移到指定 zone")
    
    # Cold 阶段
    parser.add_argument("--cold-min-age", help="Cold: min_age (e.g., 7d)")
    parser.add_argument("--cold-migrate-to", help="Cold 节点 zone")
    
    # Delete 阶段
    parser.add_argument("--delete-min-age", help="Delete: min_age (e.g., 30d)")
    
    args = parser.parse_args()
    
    # 构建策略
    gen = ILMGenerator()
    
    if args.hot_max_size or args.hot_max_age:
        gen.add_hot_phase(args.hot_max_size, args.hot_max_age)
    
    if args.warm_min_age:
        gen.add_warm_phase(
            min_age=args.warm_min_age,
            forcemerge=not args.no_forcemerge,
            shrink=args.shrink,
            migrate_to=args.migrate_to
        )
    
    if args.cold_min_age:
        gen.add_cold_phase(args.cold_min_age, args.cold_migrate_to)
    
    if args.delete_min_age:
        gen.add_delete_phase(args.delete_min_age)
    
    # 输出
    policy = gen.build()
    print("📊 生成的 ILM 策略:")
    print(gen.to_json())
    
    if args.output:
        gen.save(args.output)
    
    if args.apply:
        from elasticsearch import Elasticsearch
        es = Elasticsearch(["http://localhost:9200"])
        gen.apply(es, args.name)

if __name__ == "__main__":
    main()

3. 使用示例

生成日志策略
python cli.py \
  --name logs-policy \
  --hot-max-size 50gb \
  --hot-max-age 1d \
  --warm-min-age 1d \
  --shrink 1 \
  --migrate-to warm_nodes \
  --cold-min-age 7d \
  --cold-migrate-to cold_nodes \
  --delete-min-age 30d \
  --output logs-policy.json \
  --apply
生成指标策略
python cli.py \
  --name metrics-policy \
  --hot-max-size 100gb \
  --hot-max-age 7d \
  --warm-min-age 7d \
  --forcemerge \
  --delete-min-age 90d \
  --output metrics-policy.json

五、预设模板 templates/logs.json

{
  "name": "logs-policy",
  "hot": {
    "max_size": "50gb",
    "max_age": "1d"
  },
  "warm": {
    "min_age": "1d",
    "forcemerge": true,
    "shrink": 1,
    "migrate_to": "warm_nodes"
  },
  "cold": {
    "min_age": "7d",
    "migrate_to": "cold_nodes"
  },
  "delete": {
    "min_age": "30d"
  }
}

加载模板:

def load_template(name):
    with open(f"templates/{name}.json", "r") as f:
        return json.load(f)

六、Web 版本(可选)

使用 Flask 提供 Web 界面:

from flask import Flask, request, jsonify, render_template
app = Flask(__name__)

@app.route('/')
def index():
    return render_template('form.html')  # HTML 表单

@app.route('/generate', methods=['POST'])
def generate():
    data = request.json
    gen = ILMGenerator()
    # 根据 data 构建策略
    return jsonify(gen.build())

可集成到 Kibana 或运维平台。


七、最佳实践 ✅

项目建议
策略命名业务-场景-policy(如 logs-policy
min_age 顺序hot < warm < cold < delete
shrink 条件源索引主分片数 > 1
forcemerge仅用于只读索引
迁移属性配合 node.attr.zone 使用
定期审查检查策略是否仍适用
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值