1、Elasticsearch document 数据路由原理
我们知道,一个 index 的数据会被分成多个分片 shard,所以说一个 document 只能存在与一个 shard 中。当客户端创建 document 的时候,elasticsearch 此时就需要决定这个 document 是放在这个 index 的哪个分片 shard 中, 这个过程就称之为 document routing,即数据路由。
2、document 数据路由算法
算法;shard = hash(routing) % number_of_primary_shards 举个例子,假设一个 index 有 5 个 primary shard(p0,p1,p2,p3,p4)。每次对 index 的一个 document 进行增删改查的时候,都会带过来一个 routing number,默认就是这个 documentd 的_id(可能是手动指定,也可以是自动生成),routing=_id。假设_id=1,那么就会将 routing= 1 这个 routing 值传入一个 hash 函数中,产生一个 routing 值的 hash 值,假设 hash(routing)=21,然后将 hash 函数产生的值对这个 index 的 primary shard 的数量求余数,21 % 5 = 1 也就决定了这个 document 就放在 p1 上。
注意:此这个计算过程就可以看出,决定一个 document 在哪个 shard 上,最重要的值就是 routing 值,默认是_id,也可以手动指定,相同的 routing 值,每次过来,从 hash 函数中生成的 hash 值一定是相同的。无论最后计算的 hash 值是多少,对 number_of_primary_shards 求余数,结果一定在 0~number_of_primary_shards 之间。
3、routing 实战
默认的 routing 就是_id,也可以在发送请求的时候手动指定。下面做一个比较有趣的例子先测试一下默认的 routing
// 先插入数据
PUT /test_index/_doc/10
{
“test_field”: “test10 routing _id”
}
// 获取数据不带 routing 参数
GET /test_index/_doc/10
{
“_index” : “test_index”,
“_type” : “_doc”,
“_id” : “10”,
“_version” : 1,
“_seq_no” : 0,
“_primary_term” : 1,
“found” : true,
“_source” : {
“test_field” : “test10 routing _id”
}
}
// 获取数据带 routing 参数 参数值为_id
GET /test_index/_doc/10?routing=10
{
“_index” : “test_index”,
“_type” : “_doc”,
“_id” : “10”,
“_version” : 1,
“_seq_no” : 0,
“_primary_term” : 1,
“found” : true,
“_source” : {
“test_field” : “test10 routing _id”
}
}
再来测试一下带上 routing 值,为了看到效果我们让_id 的值与 routing 的值不一样
// 先插入数据
PUT /test_index/_doc/11?routing=12
{
“test_field”: “test routing not _id”
}
// 获取数据不带 routing 参数
GET /test_index/_doc/11
{
“_index” : “test_index”,
“_type” : “_doc”,
“_id” : “11”,
“found” : false
}
// 获取数据带 routing 参数 参数值为自定义的值
GET /test_index/_doc/11?routing=12
{
“_index” : “test_index”,
“_type” : “_doc”,
“_id” : “11”,
“_version” : 1,
“_seq_no” : 9,
“_primary_term” : 1,
“_routing” : “12”,
“found” : true,
“_source” : {
“test_field” : “test routing not _id”
}
}
手动指定的 routing value 是很有用的,可以保证某一类的 document 一定被路由到一个 shard 中去,那么在后续进行应用级别的负载均衡以及提升批量读取的性能的时候,是很有帮助的。
4、主分片数量不可变
通过上面的分析,特别是路由算法,我们不难知道,在我们最开始创建索引的时候,确定了 primary shard 的数量,之后根据路由算法,每个 document 就被路由到了指定的 shard 上面,之后的各种操作路由规则都是一样的。试想一下,如果我们改变了 primary shard 的数量,那么路由算法取余的时候值可能就跟之前的不一样了,就会被路由到其它的 shard 上面去,就会导致数据混乱,本该已经存在的 document, 可能通过查询根本查不到,某种程度上说这也会造成数据的丢失。