索引生命周期管理
1. 索引别名
# 创建别名
POST /_aliases
{
"actions": [
{ "add": { "index": "my-index-v1", "alias": "my-index" } }
]
}
# 原子切换别名:单次请求内完成 remove + add
POST /_aliases
{
"actions": [
{ "remove": { "index": "my-index-v1", "alias": "my-index" } },
{ "add": { "index": "my-index-v2", "alias": "my-index" } }
]
}_aliases 请求能原子地完成别名关系变更,但这只覆盖切换瞬间,不等于业务全程无中断,也不保证迁移期间的数据一致性——后者取决于迁移前的同步、切换期间的写入协调和切换后的验证(见 §4.2)。业务读写入口应通过别名访问索引,避免把具体索引名写死在应用配置中。
2. 索引模板
索引模板用于为新创建的索引自动应用 Settings 和 Mappings。模板只在索引创建时生效,不会为已有索引补齐配置。结合 ILM 使用时,模板还需配置生命周期策略名和滚动别名:
PUT /_index_template/my-template
{
"index_patterns": ["logs-*"],
"priority": 100,
"template": {
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1,
"index.lifecycle.name": "my-policy",
"index.lifecycle.rollover_alias": "logs"
},
"mappings": {
"properties": {
"timestamp": { "type": "date" },
"message": { "type": "text" }
}
}
}
}模板本身不会启动滚动流程:使用 ILM 管理滚动索引时,还需先创建生命周期策略,再手动创建匹配 index_patterns 的首个索引并绑定写别名(见 §3)。
3. ILM (Index Lifecycle Management)
ILM 策略定义了索引在各阶段的行为。以下示例在 hot 阶段按大小(max_size)或时间(max_age)触发滚动,warm 阶段收缩分片,滚动 30 天后删除。对已滚动的索引,warm.min_age: 7d 和 delete.min_age: 30d 以 Rollover 时间为基准计算,而非索引创建时间;min_age 是进入该阶段的最早门槛,实际执行动作还会受 ILM 轮询调度和前序动作完成情况影响,可能晚于门槛时刻:
PUT /_ilm/policy/my-policy
{
"policy": {
"phases": {
"hot": {
"actions": {
"rollover": { "max_size": "50GB", "max_age": "1d" }
}
},
"warm": {
"min_age": "7d",
"actions": {
"shrink": { "number_of_shards": 1 }
}
},
"delete": {
"min_age": "30d",
"actions": { "delete": {} }
}
}
}
}要使 ILM rollover 正常工作,还需完成以下步骤:
创建首个索引并绑定写别名。使用省略目标索引名、由 Elasticsearch 自动生成下一个索引名的常规 Rollover(ILM 自动滚动属于此类)时,索引名需要以数字结尾,如 logs-000001,这样 rollover 才能自动生成下一个索引名。同时要满足三项配置关系:索引名匹配模板的 index_patterns、index.lifecycle.rollover_alias 与实际写别名一致、首个索引在该别名下设置 is_write_index: true:
PUT /logs-000001
{
"aliases": {
"logs": { "is_write_index": true }
}
}此后所有写入都通过别名 logs 进行。当 rollover 条件触发时,ILM 自动创建 logs-000002 并将写别名指向新索引;旧索引要等满足阶段门槛(示例中为滚动 7 天后)和前序条件,才会进入 warm 阶段。
注意:
max_size和max_age是触发条件,不保证在精确时刻完成滚动。max_size统计索引全部主分片的存储大小之和(不含副本分片),max_primary_shard_size以最大的单个主分片为阈值;配置时按想限制的是主分片总量还是单个分片大小来选择。官方 ILM 教程当前用max_primary_shard_size配合max_age作为滚动条件示例。ILM 按indices.lifecycle.poll_interval(默认 10 分钟)轮询检查,且一次滚动可能分多个步骤、由 ILM 多次执行完成,实际滚动时间可能晚于条件满足时刻。排查滚动状态可用GET /logs-*/_ilm/explain查看当前索引所处的 ILM 阶段、动作和执行步骤。
4. Reindex(重建索引)
当需要修改 Mapping(如字段类型变更)时,需要通过 Reindex 重建索引。_reindex 不会自动复制源索引的 Mapping 和 Settings,目标索引必须提前创建并配置好所需结构。
4.1 基本用法
# 1. 先创建目标索引(配置新的 Mapping 和 Settings)
PUT /my-index-v2
{
"settings": { "number_of_shards": 3, "number_of_replicas": 1 },
"mappings": {
"properties": {
"title": { "type": "text" },
"status": { "type": "keyword" }
}
}
}
# 2. 将数据从 v1 复制到 v2
POST /_reindex
{
"source": { "index": "my-index-v1" },
"dest": { "index": "my-index-v2" }
}4.2 迁移策略
_reindex 复制的是启动时刻的快照,源索引在复制期间继续接收的写入不会自动出现在目标索引中。根据业务对停写的容忍度,选择以下策略:
场景一:允许短暂停写
- 暂停所有写入源索引的业务入口(不只给索引加写保护),并确认进行中的写请求已完成
- 对源索引设置写保护并执行
_reindex:PUT /my-index-v1/_settings { "index.blocks.write": true } - 校验目标索引文档数量与关键业务数据:
GET /my-index-v2/_count。数量相同不代表内容一致,关键字段还需抽样或按业务口径汇总核对 - 通过单次
_aliases请求原子切换业务实际使用的读写别名(切换请求需与 §1 一致,别名指向目标索引) - 恢复业务写入(后续请求全部走新别名),保留旧索引观察一段时间作为回滚备份,确认无误后删除
场景二:迁移期间要求持续写入
持续写入场景不能仅靠一次全量 Reindex 和一次时间戳增量 Reindex 保证数据一致。全量复制期间,源索引中的文档可能继续被更新或删除:时间戳 range 查询只能复制 updated_at 变化的文档,删除不会同步;目标索引中已存在的同 _id 文档,op_type: create 不会更新,conflicts: proceed 只会让任务跳过冲突继续执行。所以重复执行增量任务不会让这些文档自动补齐,任务「成功执行」也不等于数据一致。
生产迁移应使用能可靠追踪变更的机制,例如双写或 CDC,并处理变更顺序、删除同步和失败重试;切换前建立明确的同步屏障,确认源端变更已全部应用到目标索引,再原子切换别名。如果业务无法提供可靠的增量变更机制,应重新评估是否能安排短暂停写,而不是把时间戳查询当作无损迁移方案。
下面的请求只演示按时间窗筛选增量文档并跳过冲突这一机制,不代表可重复执行达成最终一致的迁移方案。使用前先完成全量 _reindex 并记录开始时间 T,把 gte 替换为 T;同时要求 updated_at 可靠记录了所有相关更新、业务没有删除或删除另行处理、且接受同 _id 文档不会被更新:
POST /_reindex
{
"source": {
"index": "my-index-v1",
"query": { "range": { "updated_at": { "gte": "<全量复制开始时间 T>" } } }
},
"dest": { "index": "my-index-v2", "op_type": "create" },
"conflicts": "proceed"
}筛选和冲突处理确认无误、数据核对通过后,按场景一的方式原子切换别名并保留旧索引回滚。
注意:别名切换 API 本身是原子的,但这只保证切换瞬间无中断,不等于整个迁移过程的数据一致性。迁移的可靠性取决于上述同步策略,而非切换动作本身。
5. 索引模板最佳实践
- 使用
index_patterns匹配多个索引(如logs-*) - 多个可组合索引模板匹配同一索引时,
priority决定优先采用哪个模板;最终生效的 Settings 和 Mappings 还受组件模板组合与合并规则影响,不能理解为高优先级模板无条件整体覆盖低优先级模板 - 结合 ILM 时,模板中配置
index.lifecycle.name和index.lifecycle.rollover_alias(见 §2、§3 完整示例) - 对于新增的时序数据场景,优先评估 Data Stream,以减少手动管理滚动索引和写别名的工作;数据保留和生命周期管理仍需按需配置 ILM,Data Stream 可以直接挂接 ILM 策略,两者不是替代关系
6. 常用索引管理 API
# 查看索引设置
GET /my-index/_settings
# 修改副本数
PUT /my-index/_settings
{
"number_of_replicas": 2
}
# 修改刷新间隔
PUT /my-index/_settings
{
"index.refresh_interval": "5s"
}
# 打开/关闭索引(关闭后不可读写,释放部分运行时资源,但数据仍占用磁盘)
POST /my-index/_close
POST /my-index/_open
# 强制合并(仅对不再写入的只读索引使用)
POST /my-index/_forcemerge?max_num_segments=17. 索引管理注意事项
- 业务读写通过别名访问索引,避免把具体索引名写死在应用配置中;运维排查、数据校验和迁移任务可按需直接访问具体索引
- ILM 阶段按数据保留期限、访问频率和存储成本设计,不必每个策略都走 Hot → Warm → Cold → Delete;数据量较小或访问模式简单的场景可以只配置需要的阶段
- Rollover 条件按写入速率和主分片大小设计,§3 示例中的 50GB/1天是该示例的配置值,不是通用默认值
- 对已停止写入的历史索引,可评估是否执行 forcemerge 以减少 Segment 数量、优化查询性能。执行前检查磁盘余量(
max_num_segments=1的最坏情况可能需要高达三倍的临时空间,用于容量规划而非必然消耗)、节点负载和任务并发。避免对持续写入的索引例行执行max_num_segments=1,否则可能生成超大 Segment(可能超过 5GB,具体阈值与版本和合并策略有关),难以再被常规合并有效处理,反而导致磁盘占用上升和搜索性能下降 - 删除索引前务必确认别名已切换