Elasticsearch 分片路由算法的实现机制
Elasticsearch 通过 分片路由算法 确定文档应该写入哪个主分片,核心逻辑如下:
1. 路由公式
Elasticsearch 使用以下公式计算目标分片位置:
text
shard_num = hash(_routing) % number_of_primary_shards
_routing
:路由键(默认等于文档_id
,可自定义)。number_of_primary_shards
:主分片数量(索引创建时固定,不可修改)。
2. 关键步骤
(1)路由键选择
默认行为:使用文档的
_id
作为_routing
值。json
PUT my_index/_doc/1 // _id=1 作为路由键 { "name": "foo" }
自定义路由:可通过
routing
参数指定(如按用户ID分片)。json
PUT my_index/_doc/2?routing=user123 { "name": "bar" }
(2)哈希计算
对
_routing
值计算 Murmur3 哈希(一种高性能非加密哈希函数),生成一个整数。
(3)取模定位分片
将哈希值对
number_of_primary_shards
取模,得到目标分片编号(shard_num
)。
3. 代码级实现
Elasticsearch 的实际逻辑在 IndexRouting
类中实现:
java
// 伪代码:分片定位逻辑 public int shardId(String routing, int numShards) { int hash = Murmur3HashFunction.hash(routing); // 计算哈希 return Math.floorMod(hash, numShards); // 取模得分片ID }
4. 设计特点
特性 | 说明 |
---|---|
确定性 | 相同 _routing 始终映射到同一分片,保证文档可被正确检索。 |
均匀分布 | Murmur3 哈希确保数据均匀分布在所有分片上。 |
不可变性 | 主分片数量(number_of_primary_shards )一旦创建不可更改,否则路由失效。 |
5. **写入流程示例
客户端发送文档到协调节点(Coordinating Node)。
协调节点通过路由公式计算目标主分片(如
shard_num=2
)。协调节点将请求转发到主分片所在的数据节点(Data Node)。
主分片写入成功后,并行同步到副本分片。
6. **自定义路由的典型场景
局部性优化:将同一用户的文档存储在同一分片,提升查询效率。
json
PUT orders/_doc/1?routing=user_123 { "user": "user_123", "order_id": 1 }
避免热点:若默认
_id
导致数据倾斜,可通过业务键(如时间戳+ID)分散负载。
7. **注意事项
分片数量不可变:修改
number_of_primary_shards
会导致路由失效,必须重建索引。哈希冲突:不同
_routing
可能哈希到同一分片(概率极低)。性能影响:自定义路由需确保均匀性,否则可能导致分片负载不均。
总结
Elasticsearch 的分片路由算法通过 哈希取模 实现简单高效的数据分布,兼具确定性和扩展性。理解其机制有助于优化索引设计和查询性能。