Elasticsearch移除自定义路由后更新致重复记录,求无停机解决方案
无停机移除Elasticsearch自定义路由的优化方案
场景回顾
- 环境:Elasticsearch 7.8.1,原索引routing参数为可选,此前使用
customerId作为自定义路由 - 核心问题:切换为默认
docId路由后,相同_id的文档因路由值不同落在不同分片,出现重复记录;原本的更新操作变成新增重复数据,原方案存在残留数据或需停机的弊端
方案一:双写+渐进式迁移(适合大数据量场景)
- 启动双写模式
- 修改应用代码,所有写入/更新请求同时指向两个目标:
- 原索引:保持原有
customerId路由的写入逻辑,确保旧数据正常维护 - 新索引:创建时关闭自定义路由(使用默认
_id作为路由),写入时不指定_routing参数
- 原索引:保持原有
- 后台启动异步
_reindex任务,将原索引数据批量迁移至新索引,通过wait_for_completion=false让任务后台执行,同时设置合理的scroll_size控制批次,避免冲击集群性能
- 修改应用代码,所有写入/更新请求同时指向两个目标:
- 校验数据一致性
- 编写脚本对比新旧索引的文档总数,随机抽样文档内容进行校验,确保双写和迁移的数据完全一致
- 切换读流量
- 当数据一致性达标(比如差异率低于0.01%),将应用的所有读请求切换至新索引,写请求仍保持双写,确保过渡期间无数据丢失
- 停止双写并清理旧索引
- 观察24小时确认新索引读写正常后,停止往原索引写数据,最后分批清理或直接删除原索引
方案二:别名+原地清理(适合中等数据量场景)
- 统一请求入口
- 给原索引创建读写别名(如
my_index_alias),应用所有请求通过别名操作
- 给原索引创建读写别名(如
- 渐进式更新写入逻辑
- 修改应用,新写入/更新的文档不再指定
customerId路由,使用默认_id路由 - 后台启动任务,遍历原索引中带自定义路由的文档,重新写入同一索引(不指定
_routing),此时文档会落到对应分片,原分片的旧文档暂时保留
- 修改应用,新写入/更新的文档不再指定
- 清理旧路由文档
- 先更新索引映射,开启
_routing字段存储:PUT /my_index/_mapping { "_routing": {"required": false, "store": true} } - 用
_delete_by_query分批删除带自定义路由的旧文档,通过scroll和size控制批次大小,避免集群压力过高
- 先更新索引映射,开启
- 移除路由配置
- 旧文档清理完成后,修改索引配置,彻底移除自定义路由相关设置
方案优势
- 方案一:完全隔离新旧数据,切换风险极低,支持超大规模数据迁移,全程无需停机
- 方案二:无需创建新索引,节省集群资源,操作步骤更简洁,适合数据量中等的场景
内容的提问来源于stack exchange,提问作者bhushan
相关产品推荐
相关产品推荐

