记一次非典型Redis故障的解决与解决过程中学到的

内容纲要

非典型故障的发生

某日在去公司路上就接到运维电话,说某现网项目挂掉了,任何功能都访问不了,访问任何功能都是500错误。考虑到这项目之前的情况,让运维重启项目入口的微服务,怀疑是项目入口微服务挂掉了。

刚到公司,电脑还在启动,运维电话又来了,说重启没有作用,还是一样的错误,但是看到了后台的错误,报的是redis无法连接。

这时候问题就比较大了,这个项目是从别的项目组接过来的,他们因为项目时间比较紧,前后一共只花了两个礼拜在这个项目上,而且用了大量他们并不熟悉的技术,例如Redis、kafka等,因此这个项目存在大量的设计不合理的地方,redis的使用就是其中之一。

redis这块存在的问题是大量的缓存是一次性写入的,并没有有效的恢复的地方,如果redis出了问题,里面的数据没有持久化而被清空的话,大量的数据是找不回来的。因此赶紧打开电脑查看项目的状态。

非典型故障的排查

电脑启动起来,连接上几个项目查看后台日志,发现统一报的都是connection refused错误,也就是项目无法连接上Redis。考虑到Redis是集群部署的,在快一年前出现过一次类似的问题,因为redis的某个节点所有主备都挂掉了,造成了类似的错误,因此这回的排查一开始也放在了这个地方进行排查。

但是排查的结果是Redis集群每一个节点都正常存活,并且直连每个节点进行查询都正常。怀疑是不是机房进行了某些操作,导致微服务宿主机到Redis集群的网络结构改变,而造成连接不上Redis集群端口的情况。

应用宿主机出于安全考虑,并没有安装Telnet,一时也想不起怎么尝试连接Redis集群的办法。因此只是通过redis集群本机的客户端连上了集群,感觉并没有问题。于是将客户端SCP到了应用机上,对集群进行访问,结果是毫无问题。这时机房的也反馈回来了,故障发生时间并没有进行操作。

因为机房并没有进行操作,因此怀疑是不是应用的访问包被拦截了,因此用SpringBoot和Jedis写了一个测试客户端传到应用机上进行访问,结论是访问集群没有问题。

到此认为应用已经没有问题了,但是仍然找不到拒绝访问到底出现在哪。于是怀疑Redis集群出现问题,一开始怀疑的对象是Redis集群连接数超了,将每个节点都进行了重启,但是问题仍然没有解决。

因此只能考虑将Redis数据转存,然后重建Redis集群。

通过Redis Save命令将数据转存到DUMP文件中,并CP到安全目录,然后对每个节点进行了shutdown操作,之后删除了节点data下的AOP和node文件,然后通过集群命令重新构建了整个Redis集群。这时整个集群是空白的,其他程序操作集群正常,但是就是应用访问失败。

到这里已经尝试了所有办法,而时间也已经过去了7个小时……

非典型故障的解决

这时候重新回去研究了一下应用的报错日志,发现报错是从最前面的Filter抛出来的,而不是从应用的缓存查询抛出来的,但是抛出来的类并不是我们项目中的类。

其实到这就有点线索了,回想了一遍类似项目的操作,发现有个地方被忽略了,那就是跑应用的TOMCAT。

检查TOMCAT的Context.xml文件,发现类似如下代码:

<Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve"/>
<Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager"
    host="xxx.xxx.xxx.xxx"
    port="6379"
    database="0"
    maxInactiveInterval="60"
    />

果然是灯下黑,这是TOMCAT Session共享的插件,去掉这段东西之后,应用启动后不报错了,但是无法登录了,因此说明此段代码还有有用的。

然后检查了一遍插件指向的地址,发现Redis集群里某台节点通过独立配置文件的方式启动了一台单机Redis专门用于Tomcat的Session共享功能,然后这台单机Redis挂掉了……

启动这个单机Redis后,这个问题历时8小时后解决……

经验与教训

这次故障的起因是因为原来项目组为了TOMCAT Session共享功能,启动了一台单机Redis作为Session的缓存,但是这个单机配置并没有反应在交接给我们的文档中,我们并不知道这个单点故障点的存在。同时应为他们使用的TOMCAT插件并不支持Redis集群,并不能直接使用原有的集群作为Session存放点。

然后我们在排查问题的时候,因为认为只有一个Redis集群,所以先入为主的去查原有的没有问题的集群,而忽略了日志里反馈出来的其他信息,当注意到这些信息后,问题就昭然若揭了。

而对于系统架构来说,目前的TOMCAT的Session共享插件只支持单节点Redis,而不是支持集群,这是一个极大的风险点,这是后期需要改的地方。不过在其他微服务项目中的Session共享功能已经使用上了集群,因此改动是一件很快的事情。

而这次因为是在新冠肺炎疫情期间发生这样的事,各个方面反馈的速度都比不上疫情之前,直接造成整体解决的时间长度长达8小时,而起因只是一个单机Redis的挂掉,而这种影响整体的单点故障还不知道在这个项目里埋了多少……