导读:本期聚焦于上海GEO公司创作的《Elasticsearch routing路由字段是什么?如何用它提升查询性能?》,敬请观看详情。一条文档写入Elasticsearch后到底落在哪个分片上,其实是由routing字段参与计算决定的。默认情况下ES使用文档_id做哈希分布,而当业务查询总是围绕某个维度(比如用户ID、租户ID、订单归属)展开时,显式指定routing可以让同类文档集中到同一分片,查询时也带上相同routing,就能跳过对全部分片的广播检索,显著降低IO与CPU开销。本文将深入讲解routing的底层计算原理、写入与查询时的使用方式、routing与自定义routing可能引发的数据倾斜问题,以及_id与routing组合的注意事项,帮助你安全地把routing用进生产环境。

Elasticsearch的分布式架构把索引切分成多个分片,文档写入时会根据一个路由值决定它归属哪个分片。这个路由值就是routing。大多数开发者在默认配置下从未显式接触过它,因为ES默认用文档的_id参与分片计算。但当你的查询场景高度集中在某个业务维度上时,合理使用routing字段可以大幅减少查询需要扫描的分片数量,是性能优化中性价比极高的手段。本文将从原理、用法、风险三个层面完整讲清楚routing。

Elasticsearch routing路由字段是什么?如何用它提升查询性能?

一、routing的底层计算原理

理解routing首先要明白分片位置的确定逻辑。Elasticsearch内部使用一个类似MurmurHash3的哈希函数对路由值计算哈希,再对分片数量取模,公式可以简化表示为:

// 伪代码:计算文档所在分片
shard = hash(routing_value) % number_of_primary_shards

默认情况下,routing_value就是文档的_id。这意味着_id相同的文档必然落在同一个分片,但业务上相关的文档(例如同一个用户的多条订单)会被打散到不同分片。而一旦显式指定routing,计算结果就完全由你传入的值决定。举个典型例子:以user_id作为routing写入100万条订单,同一用户的所有订单会集中在单个分片上。

这里有一个非常关键的推论:routing参与分片计算,决定了文档的物理位置。因此写入时用了什么routing,查询、更新、删除时必须传同样的routing,否则ES根本找不到这篇文档。这是routing使用中最常见的翻车点,很多团队在写入时指定了routing,查询时忘了带,导致明明数据存在却查不到。

二、写入与查询时如何使用routing

使用routing的方式非常直接。写入文档时,把routing值放在URL查询参数或请求体中均可:

// 方式一:URL参数
PUT /orders/_doc/1?routing=user_10086
{
  "user_id": "user_10086",
  "amount": 199.00,
  "status": "paid"
}

// 方式二:bulk批量写入,每条操作单独指定routing
POST /_bulk
{ "index": { "_index": "orders", "_id": "1", "routing": "user_10086" } }
{ "user_id": "user_10086", "amount": 199.00 }
{ "index": { "_index": "orders", "_id": "2", "routing": "user_10086" } }
{ "user_id": "user_10086", "amount": 58.50 }

查询时同样携带routing参数,ES就只会把请求转发到对应的那一个分片,而不是广播到所有分片再汇总:

// 只会命中一个分片,而不是扫描全部分片
GET /orders/_search?routing=user_10086
{
  "query": {
    "term": { "user_id": "user_10086" }
  }
}

更新和删除也一样,只要操作指定了routing的文档,就必须带上routing,否则ES会返回404文档未找到的错误。此外,还可以在映射层面通过index.routing_path(新版本)或早期版本的自定义路由插件,把某个字段声明为routing来源,写入时自动取该字段值,减少调用方遗漏routing的概率。

性能收益体现在哪?假设索引有20个主分片,普通查询需要协调节点把请求发到20个分片、聚合20份结果;带上正确routing后只请求1个分片。在大分片数、高并发查询的场景下,网络开销、线程池占用和查询延迟都会有明显下降,官方在合理场景下报告过数量级的性能提升。

三、routing带来的数据倾斜风险与应对

routing不是免费的午餐,最大的代价是数据分布不均。默认按_id哈希时,文档近乎均匀地散布到各分片;改成按业务字段routing后,如果某些routing值对应的文档量特别大(例如一个大租户的数据占总量30%),就会造成个别分片体积和负载远超其他分片,出现热点问题。

应对策略有几种思路。第一,评估业务数据分布,只有当单个routing值的文档量可控(比如单用户数据量天然有限)时才适合启用routing。第二,对于数据量差异极大的场景,可以考虑routing加后缀打散,例如user_10086_0user_10086_3四个路由值,查询时并发查四个routing再合并,牺牲一部分路由精度换取均衡。第三,结合索引别名和过滤,为不同量级的租户分配不同索引,从根本上避免倾斜。

还有一个容易被忽略的细节:主分片数量一旦确定就不可更改(除非reindex),而routing计算依赖分片数。如果你将来需要调整分片数,routing的分布结果会全部变化,历史数据的实际存储位置与按新分片数计算的位置不一致,必须通过reindex或_split/_shrink等操作配合处理,提前规划好容量非常重要。

四、routing与_id的关系及最佳实践

启用自定义routing后,文档的唯一性标识实际上变成了_id + routing的组合。也就是说,同一个_id配合不同的routing可以在同一索引中存在多篇文档。这在某些去重场景下是坑,也可能被有意利用来实现多维度存储。

如果希望强制routing与_id绑定,可以在写入时使用_id由routing推导的策略,或者在mapping中设置_source之外配合外部ID生成规则保证一致性。实践中的推荐做法是:把routing值同时冗余存储为一个普通字段并加上term查询条件,这样即使某些链路忘了传routing导致广播查询,结果依然正确,只是性能退化而不会出错。

总结一下使用routing的核心清单:写入、查询、更新、删除四类操作保持routing一致;评估数据倾斜风险并预留打散方案;查询条件中冗余routing字段兜底;规划好分片数量避免后期reindex。在多租户系统、用户维度的日志检索、按组织隔离的数据平台中,routing配合索引别名和filter,往往能构建出既快又清晰的隔离架构,值得在生产环境中认真落地。

Elasticsearch routing路由字段分片查询修改时间:2026-09-01 05:45:00

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。