发布于 

Redis集群踩坑记

背景

系统中Redis使用三台服务器(slave01,slave02,slave03),交叉搭建了三主三从集群。一段时间内,Redis集群频繁出现CLUSTERDOWN异常,使用redis-cli客户端连上集群后,使用cluster info查看集群信息,发现 cluster_state状态为fail,排查发现slave02服务器负载超高,redis服务已经连不上了。但奇怪的是该服务器上只有一个master,理论上“宕机”后,该服务器上的master(slave02:7003)的从节点(slave01:7002)应该自动failover选举成master才对,但是集群的自动切换机制并没有生效,整个集群处于CLUSTERDOWN状态,不可对外提供服务,一直等到slave02这台服务器负载恢复正常后cluster_state才恢复为ok状态。

踩坑过程

  1. 没有开启日志的痛
    没有日志啊没有日志啊,忍不住嚎啕一嗓子,发生故障只能靠猜啊,搞半天摸不着头脑啊。后来逼于无奈,还是关闭了故障节点的Redis,添加了日志配置再重启,也帮助了后续问题的排查;

  2. redis-server启动路径之坑
    由于集群的配置文件***.conf中,没有指定aof文件名和路径,因此redis默认使用appendonly.aof作为AOF文件名,且,文件位于启动命令执行的目录,也就是说,你在哪里执行redis-server启动redis,这个AOF文件就从哪里加载,找不到的话就自动生成一个新的。而由于之前狂野粗放的操作,不同节点上的启动路径并不一致,而我们也没注意到这个问题,重启Redis的时候用了一个与之前不同的路径,导致Redis重启后加载不了持久化的数据….我们也是在链接redis后发现keys没了才注意到这个问题;

  3. cluster-config-file配置文件之坑
    跟上面的问题有点类似,在配置cluster-config-file的时候,没有指定路径,因此,redis默认在启动命令执行的目录去找集群节点信息的配置文件,如果找不到,它就自己创建一个新的。听起来好像没问题,但是这样创建的Redis节点,它虽然是集群模式,却因为配置文件丢失没有加入之前的集群,这时候它自己本身成了一个独立的集群。如果你企图用redis-trib将它加入原本的集群,那么它还是一个孤零零的master(而其实我们期待它恢复成某个master节点的slave),如果当做master用,还得给它分配槽;如果你企图将它手动指定为某个master的slave,它还可能傲娇地给你说:不行,i’m not empty,你只能逼于无奈将它的数据清空再来一次;
    所以,2跟3要合起来一起看,当你重启Redis时,一定要注意redis-server这个命令的执行位置,是否跟重启前一致,也千万别删掉原来的node***.conf文件,它保存了你原始的集群节点信息(登录后执行cluster nodes命令可以看到一样的信息),只有使用这个文件启动,重启的节点才能正确地加入之前的集群。

  4. masterauth之坑
    在解决问题3之后,我们发现一个奇葩的事,明明集群已经恢复了啊,为什么master节点的数据没有同步到slave节点!!!! 同时,我们尝试着手动kill掉master节点,为什么slave节点没有自动选举成master!!!!! 好在这一次我们开启了日志,直接查看slave节点的日志,发现一直在打印一个错误“Unexpected reply to PSYNC from master: -NOAUTH Authentication required.” 这时才恍然大悟,我特么配置了requirepass要求别的节点连我要密码,但是我没有配置masterauth啊, slave节点去同步master数据时,因为没有配置这个参数,导致一直同步失败,这也就是前面发生的几个现象-为什么明明集群状态是ok了但是数据没有从master同步过来,为什么master挂了slave不能自己选举成为master-的原因。配置了masterauth后,再重启slave节点,一切如丝般润滑:正确的同步数据,生成AOF文件,keys也有了,关闭master后它也能切换成新的master了….

    这里有个意外收获:原来,虽然配置的是AOF机制,但redis slave从master同步数据的时候,还是会先生成rdb文件,然后再生成AOF文件,然后再使用aof-rewrite机制,重写AOF文件。

回顾整个踩坑过程:

  1. 第一是没有开启redis日志,导致集群其实没有配置成功但是没人知道,后续发生故障后也只能靠猜测排查问题;
  2. 第二是集群异常时,没人想到是不是集群没有配置正确,都默认以集群正确配置为前提来排查;
  3. 第三是没想到启动位置会影响redis aof文件以及集群配置文件生成的路径;
  4. 第四是没注意到只配置了自己的服务端密码(requirepass)没有配置对应另一个节点的客户端密码(masterauth)….

这几个小问题凑一起之后,就把人弄得晕头转向一头雾水,折腾了很久才搞清楚“莫名其妙的现象”背后的原因。
以此为戒,吸取教训,第一是,以后使用应用时,一定要开启日志,方便排查问题,第二个教训就是还是得了解你使用的应用的原理和主要配置项,尽量避免发生故障后临时抱佛脚。