ElasticSearch-Routing路由简介-脑裂问题以及解决方案

什么是Routing

当使用ES的客户端client,往ES中插入一条数据,也就是创建一个Document的时候,ES就会决定该Doc具体存在于哪一个索引(index)上的哪一个分片(shard)上,而这一个过程就叫做路由。

Routing的作用

默认情况下,ES根据文档的Id来进行路由,以此来均匀分配数据。
下面是路由的默认公式:

shard_num = hash(_rounting) % num_primary_shards

参数说明:

参数 意义
shard_num 代表最终数据落在的shard的编号
_rounting 默认为文档的Id(默认情况下Id唯一)
num_primary_shards 主分片数量

注意:
这里用到了num_primary_shards,也因此,索引在定义的时候就确定好了分片的数量,并且不可以更改,因为改了,这里的路由算法就失效了。

自定义路由

下面,上文竟然说了,_rounting默认为文档的Id,那是不是说明还可以我们自己定义路由的值呢?
举个例子:
1.创建文档,指定路由的值为hello

PUT cluster/test-type/1?routing=hello
{
    
    
	"title":"天气预报",
	"city":"杭州",
	"count":"西湖"
}

2.但是查询的时候,也必须指定路由

GET cluster/test-type/1?routing=hello

3.term查询,指定路由

GET cluster/_search
{
    
    
	"query":{
    
    
		"terms":{
    
    
			"_routing":["hello"]
		}
	}
}

4.强制查询or插入数据要指定路由,需要在索引设置的时候就配置
部分如下:

"mapping":{
    
    
	"_routing":{
    
    
		"required":true
	}
}

自定义路由的问题

自定义路由,容易让数据分配不均匀,因为所有指定路由都相同的数据,全部集中在同一个shards上了,导致严重的数据倾斜。

解决自定义路由产生的数据倾斜

设置index属性:

routing_partition_size:

一旦设置后,路由的公式就不再是上文的公式,改为:

shard_num = (hash(_rounting) + hash(_id) % routing_partition_size) % num_primary_shards

并且需要注意:

  1. 1 < routing_partition_size < primary_shard_of_number
  2. 使用后,无法创建join-field关系映射
  3. 使用后,_routing必须开启,否则报错。

ES-脑裂问题

脑裂问题:
集群中,不同的节点对master的选择出现了分歧,出现了多个竞争master的节点,并造成主分片与副本的识别出现了分歧,最终造成操作混乱,也就是精神失常。这就是ES脑裂

产生的原因

  1. 内存回收:data节点上的ES进程占用的内存过大,引发JVM大规模的内存回收(常见)
  2. 节点负载:主节点同时扮演了master和data数据存储的角色,一旦访问量过大,造成主节点压力过大,产生高延迟,让别的节点以为你master挂了,因此开始选举新的master(实际没有挂)
  3. 网络问题:集群间的网络延迟问题,导致一些节点访问不到master,认为master挂了(与第二条很像,实际没有挂)

解决方案

1.更改超时相关配置:

discovery.zen.ping.timeout

默认是3s,可以适当延长,比如6s,10s一类的。一旦节点在设定的时间内,没有响应,那么就认为他挂了,如果适当的延长,就可以一定程度上降低网路延迟所造成的的脑裂问题的可能性。
2.更改选举相关配置

discovery.zen.minimum_master_nodes:1

默认为1,用于控制选举行为发生的最小的集群主节点数量
假设配置个数为n
那么同时满足以下几种情况的时候,会开始新的选举

  1. 备选主节点个数>=n
  2. 认为master挂了的主节点个数>=n

注:ES官网推荐设置的值为:n/2+1,这里的n代表的是备主节点的个数。也就是配置Node.master:true的节点

3.尽量做到角色分离:
master和data角色分离
master配置:

node.master: true
node.data: false

data配置:

node.master: false
node.data: true

如果已经产生脑裂问题,如何解决?

重启集群
首先说明一个点:ES集群启动后,默认将第一个启动的节点(node.master为true)作为master。
这里需要注意了:
**注意启动顺序,**ES认为选举出来的节点上的分片为主分片,也就是主拷贝,ES会把这个分片上的数据分发到集群上的其他节点上,进行数据覆盖,那么假设我们第一个启动的是一个client节点呢,上面的数据还是过期的,那么第一个启动后,ES把过期的数据分发到所有节点上,并数据覆盖,那么这个后果是很严重的,造成数据的丢失。

因此建议:

  1. 给所有的数据重新建立索引。
  2. 单独启动各个节点,分析每个节点上的数据是否是重要的,并且分析他的有效性
  3. 最终确定一个最具有效果的节点,选择他第一个启动
  4. 然后把剩余的节点一并启动即可。

猜你喜欢

转载自blog.csdn.net/Zong_0915/article/details/107717324
今日推荐