问题
在集群重启的时候,有一些配置会影响shard的恢复,首先,我们需要理解默认配置下,shard恢复过程会发生什么事情.
假设集群中有10个node,每个node上面有一个shard, 可能是primary shard也可能是replica shard,就比如说我们有一个index,有5个primary shard,每个primary shard对应有一个replica shard
如果我们将整个集群关闭了进行一些维护性的操作,比如给机器安装新的磁盘之类的事情.当我们重启集群的时候,肯定节点是一个接一个的启动的,可能会出现5个节点先启动了,然后剩下5个节点还没启动.
也许是因为剩下的5个节点还没来得及启动,或者是因为一些原因耽搁了,总之不管是什么原因,就是现在只有5个节点是在线的.这5个节点会通过gossip协议互相通信,选举出一个master,然后组成一个集群.他们会发现数据没有被均匀的分布,因为有5个节点没有启动,那么那5个节点上的shard就是不可用的,集群中就少了一半的shard.此时在线的5个node就会将部分replica shard提升为primary shard,同时为每个primary shard复制足够的replica shard.
最后,可能剩下的5个节点启动好了,加入了集群,但是这些节点发现本来是他们持有的shard已经被重新复制并且放在之前的5个node上了,此时他们就会删除自己本地的数据,然后集群又会开始进行shard的rebalance操作,将最早启动的5个node上的shard均匀分布到后来启动的5个node上去.
在这个过程中,这些shard重新复制,移动,删除,再次移动的过程,会大量的耗费网络和磁盘资源.对于数据量庞大的集群来说,可能导致每次集群重启时,都有TB级别的数据无端移动,可能导致集群启动会耗费很长时间.但是如果所有的节点都可以等待整个集群中的所有节点都完全上线之后,所有的数据都有了以后,再决定是否要复制和移动shard,情况就会好很多.
图解
就上面的例子来说,假设10个node,每个node上面一个shard,如下图:
这时,我们的集群维护重启,然后上面的5个node先启动了,如图:
下面的5个node启动起来之前,集群发现primary shard不是都在,就会认为某些primary shard宕机了,此时,那些primary shard对应的replica shard就会提升为primary shard
接下来,集群又会发现,没有任何一个replica shard是存在的,因为我们定义的是每个primary shard都要有一个replica shard, 此时又会进行复制操作,结果如下图:
当剩下的5个node启动起来了,如下:
这时候,集群会发现shard已经过剩了,有primary shard也有replica shard,这时候,后面启动起来的这些node会把自己的shard删除,如下:
删除之后呢,集群又发现shard分配不均匀,因为上面的5个node上每个都有两个shard,下面的5个node一个都没有,此时就会触发rebalance操作, rebalance之后,就又会变成每个node上面一个shard,和集群重启之前的状态一样,如下:
所引发的问题
在上面的重启过程中一共引发了如下几个问题:
- 平白无故多复制了5个shard出来
- 后上线的5个node将自己本地的数据删除
- 最后又有5个shard做了网络传输和移动
解决方案
问题我们现在知道了,那么就可以通过一些设置来解决这个问题,首先需要设置一个参数gateway.recover_after_nodes
,这个参数意思是让es有足够的node上线之后,再开始shard recovery的过程,所以这个参数的值是跟具体的集群相关的,根据集群中的节点数量去设置.
此外,还应该设置一个集群中至少要有多少个node和等待那些node的时间,通过gateway.expected_nodes
和gateway.recover_after_time
这两个参数去设置
假设我们的配置如下:1
2
3gateway.recover_after_nodes: 8
gateway.expected_nodes: 10
gateway.recover_after_time: 5m
就是说在es集群中,等待至少8个节点都在线,然后最多等待5分钟,或者说10个节点都在线的时候,再开始shard recovery的过程,这样可以避免少数node启动的时候就立即开始shard recovery,消耗大量网络和磁盘资源