背景
前两天Redis cluster 集群节点宿主机故障,等故障主机恢复后,我启动实例重新加入集群后,因为业务服务器配置的原因,新加入节点连接数瞬间被打满,几番重启后,发现在执行redis-cli --cluster check时,集群出现nodes don’t agree about configuration 。字面意思是有节点保存的集群状态不一致。但具体是什么不一致,百度一番还是有点一头雾水。
源代码分析
由于是使用的5.0.7版本的redis-cli 做的集群管理。不方方便查看源代码,想到低版本的redis-trib.rb 这个ruby脚本逻辑和5.0.7 的redis-cli 几乎一致。于是从redis-trib.rb 查看源代码,首先检索关键字 don’t agree about configuration :
632 def check_config_consistency
633 if !is_config_consistent?
634 cluster_error "[ERR] Nodes don't agree about configuration!"
635 else
636 xputs "[OK] All nodes agree about slots configuration."
637 end
638 end
639
640 def is_config_consistent?
641 signatures=[]
642 @nodes.each{|n|
643 signatures << n.get_config_signature
644 }
645 return signatures.uniq.length == 1
646 end
发现主要由函数 is_config_consistent 检测集群配置是否一致。ruby 咱也不会,具体语法可以现场查询。is_config_consistent 主要逻辑是通过get_config_signature方法将每个node的配置信息去重并写入到 signatures 列表中,最后如果sinagures列表的长度大于1则表示集群内至少有一个节点的配置信息和其他节点不一致。
再根据 get_config_signature 检索redis-trib.rb,查看这个方法具体做什么事情
269 def get_config_signature
270 config = []
271 @r.cluster("nodes").each_line{|l|
272 s = l.split
273 slots = s[8..-1].select {|x| x[0..0] != "["}
274 next if slots.length == 0
275 config << s[0]+":"+(slots.sort.join(","))
276 }
277 config.sort.join("|")
278 end
根据 get_config_signature 函数定义,发现全是关于slot的。大概意思应该是从当前节点所存储的集群信息里,过滤出每个node和它对应的slot,并记录到config 列表并排序。
定位配置不一致的地方
至此,基本确定是有节点存储的集群信息(cluster nodes)里,记录和节点和槽位的分布于其他节点不一致。于是通过如下命令分别获取每个实例所存储的集群信息情况:
redis-cli -h ip -p port -a password cluster nodes > ip-port.nodes 2>/dev/null
后面对比分析具体的实例与slot的对应关系就是体力活了,不同人用不同的办法。
问题处理
很庆幸,经过对比,发现是一台slave节点 cluster nodes 信息里,记录的有两个master节点的槽位错乱导致。解决过程是直接kill 掉slave进程,手动修改该slave实例的nodes.conf(配置文件cluster-config-file定义的名字) 文件,将node与slot的信息修改为和其他节点一致,然后重启slave节点。再次 check 集群状态,发现ALL nodes agree about configuration !搞定。