elasticsearch之routing(转载整理)
Elasticsearch路由机制介绍
Elasticsearch的路由机制与其分片机制有着直接的关系。Elasticsearch的路由机制即是通过哈希算法,将具有相同哈希值的文档放置到同一个主分片中。这个和通过哈希算法来进行负载均衡几乎是一样的。
而Elasticsearch也有一个默认的路由算法:它会将文档的ID值作为依据将其哈希到相应的主分片上,这种算法基本上会保持所有数据在所有分片上的一个平均分布,而不会产生数据热点。
而我们为什么会需要自定义的Routing模式呢?首先默认的Routing模式在很多情况下都是能满足我们的需求的——平均的数据分布、对我们来说是透明的、多数时候性能也不是问题。但是在我们更深入地理解我们的数据的特征之后,使用自定义的Routing模式可能会给我们带来更好的性能。
假设你有一个100个分片的索引。当一个请求在集群上执行时会发生什么呢?
1. 这个搜索的请求会被发送到一个节点
2. 接收到这个请求的节点,将这个查询广播到这个索引的每个分片上(可能是主分片,也可能是复制分片)
3. 每个分片执行这个搜索查询并返回结果
4. 结果在通道节点上合并、排序并返回给用户
因为默认情况下,Elasticsearch使用文档的ID(类似于关系数据库中的自增ID,当然,如果不指定ID的话,Elasticsearch使用的是随机值)将文档平均的分布于所有的分片上,这导致了Elasticsearch不能确定文档的位置,所以它必须将这个请求广播到所有的100个分片上去执行。这同时也解释了为什么主分片的数量在索引创建的时候是固定下来的,并且永远不能改变。因为如果分片的数量改变了,所有先前的路由值就会变成非法了,文档相当于丢失了。
而自定义的Routing模式,可以使我们的查询更具目的性。我们不必盲目地去广播查询请求,取而代之的是:我们要告诉Elasticsearch我们的数据在哪个分片上。
原来的查询语句:“请告诉我,USER1的文档数量一共有多少”
使用自定义Routing(在USESR ID上)后的查询语句:“请告诉我,USER1的文档数量一共有多少,它就在第三个分片上,其它的分片就不要去扫描了”
索引分片分配能够控制索引分片在节点上怎么分布,那对于具体的文档能否控制具体节点的分布呢?答案是可以,根据路由公式shard = hash(routing) % number_of_primary_shards,Elasticsearch使用相同的routing参数来实现这个功能,但我们在创建索引时需如下进行配置:
"mappings":{
"doc": {
"_routing": {
"required": true,
"path":"_routing"
},
"properties": {
"title": {
"type":"string"
}
}
}
}
如果我们想在建索引时将相关的文档存放到一个分片下就可以这样做:
curl- XPUT localhost: 9200 / documents / doc / 1 - d '
{
"title": "Document No.1",
"_routing":"A"
}'
curl- XPUT localhost: 9200 / documents / doc / 2 - d '
{
"title": "Document No.1",
"_routing":"A"
}'
curl- XPUT localhost: 9200 / documents / doc / 3 - d '
{
"title": "Document No.1",
"_routing":"B"
}'
这样将id为1和2的文档将会存在统一个分片上去。
既然索引文档的时候使用了路由,那么肯定得在查询的时候利用了,在查询的时候使用routing参数将使得查询更加高效,如下:
curl-XGET 'localhost:9200/documents/_search?pretty&q=*:*&routing=A'
路由机制的总结
实际上,如果不明确指明使用路由机制,实际上路由机制也是在发挥作用的,只是默认的路由值是文档的id而已。而个性化路由的需求主要是和业务相关的。默认的路由(如果是自动的生成的id)直观上会把所有的文档随机分配到一个分片上,而个性化的路由值就是和业务相关的了。这也会造成一些潜在的问题,比如user123本身的文档就非常多,有数十万个,而其他大多数的用户只有几个文档,这样的话就会导致user123所在的分片较大,出现数据偏移的情况,特别是多个这样的用户处于同一分片的时候,现象会更明显。具体的使用还是要结合实际的应用场景来选择的。