通过索引生命周期管理实现冷热数据分离

更新时间:
复制 MD 格式

Elasticsearch 6.6.0及以上版本提供了索引生命周期管理(ILM,Index Lifecycle Management)功能,将索引生命周期分为hot、warm、cold、delete四个阶段,结合冷热集群架构实现数据自动流转和存储成本优化。

阶段

描述

hot

热数据阶段。处理时序数据的实时写入,可根据索引的文档数、大小、时长决定是否调用rollover API滚动更新索引。

warm

温数据阶段。索引不再写入,主要提供查询。

cold

冷数据阶段。索引不再更新,查询频率低,查询速度较慢。

delete

删除阶段。索引将被删除。

为索引添加生命周期管理策略有两种方式:

  • 为索引模板添加策略:策略应用到别名覆盖的所有索引,本文以此为例。

  • 为单个索引添加策略:只覆盖当前索引,新滚动的索引不受该策略影响。

本文以冷热数据场景为例,演示以下配置流程:

  1. 将索引数据实时写入Elasticsearch,当数据增加到一定量时自动写入新索引。

  2. 旧索引在hot阶段停留30分钟后进入warm阶段。

  3. warm阶段完成Merge及Shrink操作后,索引在1小时(从滚动更新时算起)后进入cold阶段。

  4. cold阶段将数据迁移到冷数据节点,索引在2小时(从滚动更新时算起)后被删除。

操作流程

  1. 步骤一:创建冷热集群并查看节点的冷热属性

    在创建集群时设置节点的冷热属性。

  2. 步骤二:为索引配置生命周期管理策略

    定义ILM策略,并将该策略应用到别名覆盖的所有索引下。

  3. 步骤三:验证数据分布

    验证cold阶段索引的shard是否分布在冷数据节点上。

  4. 步骤四:更新ILM策略

    更新已有策略。

  5. 步骤五:切换ILM策略

    在不同策略间实现滚动切换。

步骤一:创建冷热集群并查看节点的冷热属性

冷热集群包含冷、热两种属性的节点,热节点处理实时写入,冷节点存储历史数据,两者区别如下。

节点类型

存储数据要求

读写性能要求

规格要求

存储要求

热节点(hot)

近期数据,例如最近2天的日志数据。

高

高,例如32核64 GB

建议使用SSD云盘。

冷节点(warm)

历史数据,例如2天之前的日志数据。

低

低,例如8核32 GB

建议使用高效云盘,或使用OpenStore实现海量冷数据Serverless存储。

阿里云Elasticsearch中,冷数据节点的box_type值为warm(非cold),这是因为冷数据节点在Elasticsearch原生架构中对应warm tier。
  1. 在创建阿里云Elasticsearch实例时,启用冷数据节点,即可创建冷热集群。

  2. 启用冷数据节点并购买后,系统会在节点启动参数中加入-Enode.attr.box_type参数:

    • 热数据节点:-Enode.attr.box_type=hot

    • 冷数据节点:-Enode.attr.box_type=warm

    只有启用冷数据节点后,数据节点才会变成热节点。
  3. 登录该集群的Kibana控制台,具体操作请参见通过Kibana连接集群。

  4. 在左侧导航栏,单击Dev Tools 。

  5. 在 Console 中,执行如下命令,查看集群冷热节点属性。

    GET _cat/nodeattrs?v&h=host,attr,value

    返回结果中包含hot和warm节点,表示集群已支持冷热架构。

步骤二:为索引配置生命周期管理策略

  1. 在Kibana控制台中,执行如下命令,定义ILM策略。

    PUT /_ilm/policy/game-policy
    {
      "policy": {
        "phases": {
          "hot": {
            "actions": {
              "rollover": {
                "max_size": "1GB",
                "max_age": "1d",
                "max_docs": 1000
              }
            }
          },
          "warm": {
            "min_age": "30m",
            "actions": {
              "forcemerge": {
                    "max_num_segments":1
                  },
              "shrink": {
                    "number_of_shards":1
                  }
            }
          },
          "cold": {
            "min_age": "1h",
            "actions": {
              "allocate": {
                "require": {
                  "box_type": "warm"
                }
              }
            }
          },
          "delete": {
            "min_age": "2h",
            "actions": {
              "delete": {}
            }
          }
        }
      }
    }

    参数

    说明

    hot

    索引满足任一条件(数据达到1 GB、使用超过1天、文档数超过1000)时触发滚动更新。旧索引在滚动更新后等待30分钟进入warm阶段。rollover支持max_docs、max_size、max_age三种条件,满足任一即触发。

    warm

    将索引收缩到1个分片,强制合并为1个段。完成后,索引在1小时(从滚动更新时算起)后进入cold阶段。

    cold

    将索引从hot节点迁移到warm(冷数据)节点。完成后,索引在2小时后进入delete阶段。

    delete

    索引被删除。

    策略名创建后无法更改。通过Kibana控制台也可以创建策略,但Kibana上max_age最小单位为小时,API方式最小单位为秒。
  2. 创建索引模板,在settings中指定冷热属性,数据写入后存储在hot节点上。

    PUT _template/gamestabes_template
    {
      "index_patterns" : ["gamestabes-*"],
      "settings": {
        "index.number_of_shards": 5,
        "index.number_of_replicas": 1,
        "index.routing.allocation.require.box_type":"hot",
        "index.lifecycle.name": "game-policy",
        "index.lifecycle.rollover_alias": "gamestabes"
      }
    }

    参数

    说明

    index.routing.allocation.require.box_type

    指定索引新建时分配的节点类型。

    index.lifecycle.name

    指定生命周期策略名称。

    index.lifecycle.rollover_alias

    指定rollover别名。

  3. 基于序号创建初始索引。

    PUT gamestabes-000001
    {
    "aliases": {
        "gamestabes":{
           "is_write_index": true
            }
          }
    }

    也可以基于时间创建索引,详情请参见using date math。

  4. 通过别名写入数据。当数据达到rollover条件并触发ILM检测周期后,索引将进行滚动更新。

    PUT gamestabes/_doc/1
    {
        "EU_Sales" : 3.58,
        "Genre" : "Platform",
        "Global_Sales" : 40.24,
        "JP_Sales" : 6.81,
        "Name" : "Super Mario Bros.",
        "Other_Sales" : 0.77,
        "Platform" : "NES",
        "Publisher" : "Nintendo",
        "Year_of_Release" : "1985",
        "na_Sales" : 29.08
    }
    ILM默认10分钟检测一次符合策略标准的索引。可通过indices.lifecycle.poll_interval参数修改检测周期。
  5. (可选)在Kibana中查看索引生命周期状态。

    1. 在左侧导航栏,单击 Management 。

    2. 在 Elasticsearch 区域中,单击 Index Management 。

    3. 单击 Lifecycle phase 下拉列表,选择生命周期阶段过滤索引。

    4. 单击过滤后的索引名称,查看索引详细配置。

步骤三:验证数据分布

当索引进入cold阶段后,验证其shard是否已分布在冷数据节点上。

  1. 在Kibana控制台中,查询进入cold阶段的索引名称。

  2. 执行以下命令,查询该索引的shard分布情况。将shrink-gamestables-000012替换为实际的索引名称。

    GET _cat/shards/shrink-gamestables-000012

    返回结果中,如果shard所在节点的box_type为warm,表示cold阶段的索引数据已分布在冷数据节点上。

步骤四:更新ILM策略

  1. 执行以下命令更新已有的ILM策略。以修改game-policy的delete阶段时间为例:

    PUT /_ilm/policy/game-policy
    {
      "policy": {
        "phases": {
          "hot": {
            "actions": {
              "rollover": {
                "max_size": "1GB",
                "max_age": "1d",
                "max_docs": 1000
              }
            }
          },
          "warm": {
            "min_age": "30m",
            "actions": {
              "forcemerge": {
                    "max_num_segments":1
                  },
              "shrink": {
                    "number_of_shards":1
                  }
            }
          },
          "cold": {
            "min_age": "1h",
            "actions": {
              "allocate": {
                "require": {
                  "box_type": "warm"
                }
              }
            }
          },
          "delete": {
            "min_age": "3h",
            "actions": {
              "delete": {}
            }
          }
        }
      }
    }
  2. 查看更新后的策略版本。

    1. 在左侧导航栏,单击 Management 。

    2. 在 Elasticsearch 区域中,单击 Index Lifecycle Policies 。

    3. 查看策略版本号。更新后版本号增加1,当前正在滚动写入的索引仍使用旧版本策略,新策略在下次滚动更新时生效。

步骤五:切换ILM策略

  1. 创建新策略。

    PUT /_ilm/policy/game-new
    {
      "policy": {
        "phases": {
          "hot": {
            "actions": {
              "rollover": {
                "max_size": "3GB",
                "max_age": "1d",
                "max_docs": 1000
              }
            }
          },
          "warm": {
            "min_age": "30m",
            "actions": {
              "forcemerge": {
                    "max_num_segments":1
                  },
              "shrink": {
                    "number_of_shards":1
                  }
            }
          },
          "cold": {
            "min_age": "1h",
            "actions": {
              "allocate": {
                "require": {
                  "box_type": "warm"
                }
              }
            }
          },
          "delete": {
            "min_age": "2h",
            "actions": {
              "delete": {}
            }
          }
        }
      }
    }
  2. 为模板绑定新策略。

    PUT _template/gamestabes_template
    {
      "index_patterns" : ["gamestabes-*"],
      "settings": {
        "index.number_of_shards": 5,
        "index.number_of_replicas": 1,
        "index.routing.allocation.require.box_type":"hot",
        "index.lifecycle.name": "game-new",
        "index.lifecycle.rollover_alias": "gamestabes"
      }
    }

常见问题

如何调整ILM策略检查频率?

ILM默认每10分钟检查一次符合策略的索引,在此期间数据量可能超出设定阈值。例如设置max_docs为1000,实际文档数可能在超过1000后才触发滚动更新。

通过修改indices.lifecycle.poll_interval参数可控制检查频率:

重要

检查频率过高会增加节点负载,建议根据业务需求谨慎设置。

PUT _cluster/settings
{
  "transient": {
    "indices.lifecycle.poll_interval":"1m"
  }
}

阿里云 Elasticsearch 后台会自动清理索引吗?

阿里云 Elasticsearch 后台无法自动清理索引,需使用 ILM(索引生命周期管理)管理索引。通过配置 ILM 策略,索引创建后可按设定阶段自动删除(delete 阶段)。冷热架构场景下,还可通过 ILM 自动将数据从热节点迁移到冷节点。配置方法请参见本文步骤二:为索引配置生命周期管理策略。

为什么删除数据会导致 CPU 激增或集群卡顿?如何通过 ILM 优化?

Elasticsearch 删除文档时,Lucene 底层只会生成 .del 文件,将文档标记为“已删除”。后台执行段合并时,需要读取旧段、跳过已标记的文档并写入新段。短时间内删除大量文档会使段合并消耗大量 CPU 资源,可能导致集群卡顿。

可配置 ILM(索引生命周期管理)策略,分阶段管理数据,避免集中删除带来过大的段合并压力。对于确定不再使用的索引,也可直接删除整个索引;删除索引属于元数据操作,不会产生段合并压力,但执行前必须确认该索引未被业务使用。ILM 通过自动执行删除或合并操作分散后台段合并压力,避免大量文档同时被标记删除而引发 CPU 激增。

ILM 通常需要通过命令行配置,控制台可能无法直接设置全部细节。

使用 ILM 管理索引周期时是否会误删 system 索引(如 security 索引)?

是否会删除 system 索引取决于该索引对应的 ILM(索引生命周期管理)策略。如果修改了 security 等 system 索引的默认策略,这些索引可能会被删除;如果未修改默认策略,则不会被误删。

配置 ILM 策略时,应区分 system 索引与业务索引,避免将自定义生命周期策略应用到 system 索引。

Elasticsearch 自动段合并清理数据需要多久?如何及时释放空间?

自动段合并清理数据没有固定耗时。该过程不是实时完成,实际耗时会受当前写入场景影响。

如需及时释放空间,可主动执行 _forcemerge 命令,或配置 ILM(索引生命周期管理)策略进行自动化处理。本文步骤二:为索引配置生命周期管理策略中的 warm 阶段提供了 forcemerge 配置示例,可据此配置强制合并。