Appearance
路由机制
要理解Elasticsearch(以下简称ES)的路由机制,需要先明确其核心目标:在分布式环境中,将文档精准分配到对应的分片(Shard),并在查询时快速定位到存储文档的分片。它是ES实现水平扩展和高性能的关键基础。
一、路由的核心逻辑:从"文档"到"分片"的映射
ES的路由机制本质是通过「路由键(Routing Key)」计算分片序号,公式是:
java
shard = hash(routing_key) % number_of_primary_shards这个公式是路由机制的"灵魂",我们拆解每个部分的含义和细节:
1. 关键概念解析
路由键(Routing Key):
用于计算分片的"输入值",默认是文档的_id字段(无论是ES自动生成的UUID,还是用户指定的_id)。如果用户在索引/查询时自定义了routing参数(比如用user_id作为路由键),则优先使用该参数的值。哈希函数(Hash Function):
ES使用MurmurHash3算法(128位版本)对路由键进行哈希计算。选择它的原因是:- 计算快:适合高并发的分布式场景;
- 分布均匀:能将不同的路由键映射到离散的哈希值,减少"分片倾斜"(某分片数据量远大于其他分片);
- 低碰撞率:几乎不会出现不同路由键生成相同哈希值的情况。
主分片数(number_of_primary_shards):
索引创建时指定的主分片数量(一旦创建无法修改!)。取模运算的结果就是文档要写入的主分片序号(从0开始)。为什么是"主分片数"而不是"总分片数(主+副本)"?
因为副本分片是主分片的冗余复制,路由只需要决定"主分片",副本会自动同步主分片的数据。
2. 示例:路由计算过程
假设我们有一个索引my_index,主分片数是5(number_of_primary_shards=5):
- 文档A的
_id是"doc1",默认路由键是"doc1"; - 通过MurmurHash3计算
"doc1"的哈希值为123456; - 取模运算:
123456 % 5 = 1→ 文档A被分配到分片1(主分片)。
如果我们自定义路由键为"user_100":
- 哈希值计算为
789012; - 取模:
789012 %5 = 2→ 文档A被分配到分片2。
二、路由的完整流程:从"写入"到"查询"
路由机制贯穿文档写入和文档查询的全生命周期,我们分别拆解:
1. 文档写入时的路由流程
当客户端向ES发送索引请求(PUT /my_index/_doc/doc1)时,路由的执行步骤如下:
- 客户端选择节点:客户端随机选择一个ES节点(称为"协调节点",Coordinating Node)发送请求;
- 协调节点计算路由:协调节点使用路由键(默认
_id)计算分片序号; - 转发请求到主分片:协调节点根据集群状态(由Master节点维护),找到该分片序号对应的主分片所在的节点,并将请求转发过去;
- 主分片处理写入:主分片节点接收请求,将文档写入本地Lucene索引,并同步到所有副本分片(Replica Shard);
- 返回确认:所有副本确认写入完成后,主分片节点向协调节点返回成功响应,协调节点再通知客户端。
2. 文档查询时的路由流程
查询的核心是快速定位到存储文档的分片,分为两种情况:
- 情况1:查询时指定
routing参数(推荐):
比如GET /my_index/_doc/doc1?routing=user_100,协调节点会直接计算分片序号,只查询该分片的主/副本,避免广播到所有分片,大幅提升查询效率。 - 情况2:未指定
routing参数:
协调节点会将查询请求广播到索引的所有分片(主+副本),每个分片返回匹配的结果,最后由协调节点合并结果后返回给客户端。这种情况的性能开销更高(尤其是分片数量大时)。
三、路由机制的关键细节与最佳实践
理解路由机制的细节,才能避免踩坑并优化性能:
1. 主分片数为什么不能修改?
因为路由公式依赖number_of_primary_shards,如果修改主分片数,所有文档的分片序号都会改变(比如从5改为6,123456%5=1变成123456%6=0),导致所有文档需要重新索引(Reindex),代价极高。
最佳实践:创建索引时根据未来1-2年的数据量估算主分片数(比如每分片容量控制在20-40GB)。
2. 自定义路由的利与弊
自定义路由(比如用user_id作为路由键)的优点:
- 查询高效:查询某用户的文档时,只需要访问对应的分片;
- 数据隔离:同一用户的所有文档都存在同一个分片,避免跨分片查询。
但需要注意风险:
- 分片倾斜:如果路由键的分布不均匀(比如某用户的文档量极大),会导致该分片成为"热点",性能瓶颈;
- 查询依赖路由键:如果查询时忘记携带
routing参数,会查不到文档(因为文档只在特定分片)。
3. 路由与分片均衡
ES的分片均衡器(Shard Balancer)会自动将分片分配到不同节点,确保负载均匀。但路由机制的"均匀性"依赖路由键的分布:
- 如果使用默认
_id(UUID):MurmurHash3会将UUID均匀映射到分片,几乎不会倾斜; - 如果自定义路由键:需要确保路由键的分布足够分散(比如用
user_id而不是gender,因为gender只有"男/女"两个值,会导致分片倾斜)。
4. 路由与副本分片
副本分片的作用是高可用和查询扩展,但路由机制不影响副本的分配:
- 主分片的序号由路由计算,副本分片会被分配到其他节点(避免单点故障);
- 查询时,协调节点会随机选择主分片或副本分片(轮询策略),提高查询吞吐量。
四、总结:路由机制的本质
ES的路由机制是分布式系统中"数据分片"的核心实现,它通过:
- 「路由键」关联文档与分片;
- 「哈希+取模」实现精准映射;
- 「主分片数固定」保证数据稳定性。
理解路由机制,才能更好地设计索引结构(比如合理设置主分片数)、优化查询性能(比如自定义路由减少分片扫描),避免"分片倾斜"等常见问题。
一句话总结:路由是ES的"地址簿",让文档知道"该去哪",让查询知道"该找谁"。
