es routing
官网简介:https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-routing-field.html
ES 建索引时默认是根据文档标识符 _id 将文档均分至多个分片。当搜索数据时,默认查询所有分片结果然后汇总,而并不必须知道数据到底存在哪个分片上。
计算公式:shard_num = hash(_id) % num_primary_shards
但是现在我们有这样的需求,一个订单查询服务,存储2018年一年的订单信息,如果按 _id hash均分至各个分片,查询时会去请求所有的分片,数据量较大时响应速度就比较慢。但其实每个月的数据本身分布并不均匀,5,6月的数据偏多,1,2,3月的数据偏少,理想情况下,数据偏少的月,查询性能应该更快,基于_id分片的方法并不能满足我们的需求。实际业务查询时候其实以月份为单位进行查询,比如只查询1月的数据就行,而不需要把一年的数据都扫描一遍,导致最终的结果就是慢的更慢,快的也慢,所以我们要针对性的做优化。
优化的思路就是按照月份分区,每一个月的数据都存在指定的分区中。按照 month 字段进行分片,es 中 _routing 字段支持这个需求:
计算公式:shard_num = hash(_routing) % num_primary_shards
使用 routing 的功能,大概率会出现分片大小不均匀的情况,对此 ES 采取的措施是,利用 _id 做二次路由,即相同 value 值,可以进入一个集群(shardList),而不是仅仅一个分片(shard),
计算公式:shard_num = (hash(_routing) + hash(_id) % routing_partition_size) % num_primary_shards
- 只查询一个(或者较少的)shard,避免在其他 shard 上做无用的查询,减少各个 searcher 节点压力;
- 如果只查询一个shard 能减掉合并操作;