← 返回题目列表

Elasticsearch 如何用 alias 和 reindex 做零停机重建索引?

高频 中等 第 11 / 30 题 更新于 2026/07/29
ElasticsearchAliasReindex零停机

简化版

ES 的 mapping 很多变更不能原地修改,常用“新建索引 -> reindex 数据 -> 双写或补增量 -> 原子切换 alias”的方式零停机迁移。业务读写访问 alias,而不是直接访问物理索引名。

详细版

典型流程是:旧索引 products_v1,别名 products 指向它;创建 products_v2 并设置新 mapping;用 _reindex 从 v1 拷贝数据到 v2;处理迁移期间增量写入;最后用 aliases API 在一个原子操作里移除旧指向、添加新指向。

POST /_aliases
{
  "actions": [
    { "remove": { "index": "products_v1", "alias": "products" } },
    { "add": { "index": "products_v2", "alias": "products" } }
  ]
}

面试要强调:alias 切换是关键,reindex 不是自动同步,增量数据和回滚方案要设计。

完整版教学

一、为什么需要重建索引

Elasticsearch 的很多 mapping 变更不能直接在原字段上修改。例如字段从 text 改成 keyword,分词器变更,字段类型从字符串改数字,都需要重建索引。

如果业务直接访问物理索引名,迁移时就会影响调用方。alias 的价值是给业务一个稳定入口,底层索引可以换。

business -> products alias -> products_v1
                             products_v2 later

记忆钩子:物理索引可换,业务别名不变。

二、基础流程是新建、迁移、切别名

假设当前别名 products 指向 products_v1。迁移步骤:

1. 创建 products_v2,配置新 settings/mapping
2. _reindex: products_v1 -> products_v2
3. 校验文档数量和抽样查询
4. 处理迁移期间增量
5. 原子切换 alias 到 products_v2
6. 观察稳定后删除 products_v1

创建新索引:

PUT /products_v2
{
  "settings": { "number_of_shards": 3 },
  "mappings": {
    "properties": {
      "name": { "type": "text" },
      "sku": { "type": "keyword" }
    }
  }
}

三、_reindex 只复制存量,不自动追增量

_reindex 会把源索引中的文档复制到目标索引,但它不是持续同步任务。迁移期间如果业务还在写旧索引,增量数据要单独处理。

POST /_reindex
{
  "source": { "index": "products_v1" },
  "dest": { "index": "products_v2" }
}

增量处理常见方案:

方案做法适合场景
停写窗口短暂停写后 reindex小系统、低峰迁移
双写新旧索引同时写对一致性要求高
时间戳补偿迁移后按 updatedAt 补一遍有可靠更新时间
消息回放从 MQ 回放变更写链路事件化

面试中提到“增量”两个字,答案就立起来了。

四、alias 切换要用原子 actions

不要先 remove 再 add 分两次请求,否则中间可能出现 alias 短暂不存在。应该用 _aliases API 一次提交多个 actions。

POST /_aliases
{
  "actions": [
    { "remove": { "index": "products_v1", "alias": "products" } },
    { "add": { "index": "products_v2", "alias": "products" } }
  ]
}

如果 alias 用于写入,还要关注 is_write_index。多个索引共享写别名时,必须指定哪个是写索引。

{ "add": { "index": "products_v2", "alias": "products", "is_write_index": true } }

五、校验和回滚不能省

迁移前后要校验:

文档数量是否一致
关键查询结果是否一致
mapping 是否符合预期
别名是否指向正确
写入是否进入新索引
错误日志是否异常

回滚也要简单:只要旧索引还保留,就可以把 alias 切回 products_v1。所以不要迁移成功一秒后立刻删除旧索引。

保留窗口可以按业务决定,例如观察 1 到 7 天后删除。

六、性能和安全边界

_reindex 会消耗源索引查询、目标索引写入、网络和磁盘资源。大索引迁移要低峰执行,使用 slices 并行时也要控制压力。

POST /_reindex?slices=4&wait_for_completion=false
{
  "source": { "index": "products_v1" },
  "dest": { "index": "products_v2" }
}

wait_for_completion=false 可以让任务异步执行,再通过 tasks API 查看进度。并行切片不是越多越好,要看集群吞吐。

七、常见误区与追问

  • 误区:mapping 改不了就直接删索引重建。 生产应使用新索引、reindex、alias 原子切换,避免停机。
  • 误区:_reindex 会自动同步增量。 它只处理任务期间扫描到的数据,增量写入要额外设计。
  • 误区:alias 切换分两步也没关系。 分两次请求可能出现空窗,应使用 _aliases 原子 actions。
  • 追问:is_write_index 有什么用? 当别名指向多个索引时指定写入目标,避免写入歧义。
  • 追问:怎么回滚? 保留旧索引,把 alias 原子切回旧索引,并排查增量差异。
  • 追问:大索引 reindex 怎么减少影响? 低峰执行、异步任务、限速或 slices,并监控写入和查询压力。

八、加强记忆

零停机重建索引记成“业务走别名,物理建新版,存量 reindex,增量兜住,原子切换”。Alias 是稳定入口,reindex 只是搬存量,真正难点是迁移期间写入、校验和回滚。面试里只说 reindex 不够,必须把 alias 原子切换和增量方案讲出来。