当前位置:首页 > 问答 > 正文

redis端口突然连不上了,排查访问异常问题中

(根据知乎专栏“运维故事汇”、《Redis开发与运维》书籍以及个人实践经验整理)

那天下午,正忙着写代码,突然测试环境一堆报警邮件涌进来,全是连接Redis超时的错误,心里咯噔一下,这Redis好端端的,怎么突然就闹脾气连不上了呢?赶紧放下手里的活,开始这场“破案”之旅。

第一步:先确定是不是真的“死”了

最直接的想法就是,Redis服务本身是不是挂掉了,我立刻远程登录到部署Redis的那台服务器上,打开命令行,输入查看进程的命令:ps -ef | grep redis,一看,Redis的进程好端端地在那里,启动的用户、参数都正常,不像是自己崩溃退出的样子。

进程在,那是不是没响应了呢?我尝试在服务器本地,用Redis自带的命令行客户端连接一下,输入 redis-cli(因为Redis默认端口是6379,如果改了端口要用-p参数指定),结果,顺利连上去了,还能执行ping命令,返回了PONG,这说明Redis服务本身是在正常运行,并且能处理请求的,问题看来不是出在Redis服务进程的生死上,而是网络通路或者配置方面。

redis端口突然连不上了,排查访问异常问题中

第二步:检查网络“道路”通不通

既然服务本身没问题,那很可能是请求根本就没能走到Redis那里,这就像你去朋友家,朋友在家,但你走到他家门口发现路被封了,或者门牌号不对。

我先用了最常用的网络检查工具ping,从我的电脑去pingRedis服务器的IP地址,结果显示网络是通的,延迟也很正常,排除了底层网络中断的可能,但ping只能说明机器能到,不代表端口是开放的。

祭出另一个利器telnet,我在应用程序所在的服务器上(也就是客户端机器),输入命令 telnet Redis服务器IP 6379,正常情况下,会显示一个黑屏,然后出现Redis的标识之类的,或者直接是空白连接成功状态,但这次,命令行卡了几秒钟,然后提示“连接失败”或者“无法打开到主机的连接”,这明确说明了,在TCP层,客户端到Redis服务器6379端口的连接被拒绝了,这条路,果然不通。

redis端口突然连不上了,排查访问异常问题中

第三步:看看是谁“拦”住了请求

端口连不上,最常见的原因就是防火墙了,可能是服务器本身自带的防火墙(比如Linux的iptables或firewalld),也可能是云服务商平台上的网络安全组策略。

我先检查服务器本身的防火墙,我们的服务器用的是firewalld,输入命令 firewall-cmd --list-all,查看当前开放的端口列表,果然,在开放的端口里,怎么找都找不到6379的影子,不知道是谁什么时候操作,可能误关了,或者有新的策略覆盖了旧的,我立刻用命令 firewall-cmd --zone=public --add-port=6379/tcp --permanent 把6379端口加回去,然后重载防火墙规则 firewall-cmd --reload,操作完成后,我立刻再次用telnet测试,哎?还是连不上!

这就奇怪了,本地防火墙已经放行了呀,我突然想起来,我们用的是云服务器,云平台本身还有一层虚拟防火墙,叫做“安全组”,我立刻登录到云服务商的管理控制台,找到这台Redis服务器所属的安全组规则,仔细检查入站规则,发现有一条规则是允许特定IP段访问6379端口的,但是规则的生效时间好像被修改过,或者是我们应用程序的服务器IP地址最近有变动,导致它不在这个允许的IP段里了,我确认了应用服务器的当前IP,并将其添加到安全组的允许规则中,保存规则后,再次telnet测试,这次终于显示连接成功了!

redis端口突然连不上了,排查访问异常问题中

第四步:更深层次的排查

虽然问题解决了,但为了防止类似情况再发生,我多看了一眼,用redis-cli连上Redis,执行了 config get bind 命令,这个命令是查看Redis服务器被允许绑定在哪个IP地址上,默认情况下,Redis绑定在0.0.1,也就是只允许本机访问,如果是为了让其他机器访问,通常会绑定到0.0.0(所有网络接口)或者一个具体的内部IP地址,检查后发现,配置是0.0.0,这是正确的,如果这里配置成了0.0.1,那么即使防火墙全开,其他机器也永远连不上。

还检查了 config get protected-mode,Redis的保护模式是一个安全特性,当Redis没有设置密码,并且只绑定在回环地址时,它会拒绝外部连接,我们的环境因为绑定了0.0.0,所以保护模式默认是关闭的,这也是对的,如果保护模式意外开启,并且绑定地址不是0.0.1,它可能会拒绝未认证的连接尝试。

我还顺手用 netstat -tlnp | grep 6379 命令确认了一下,Redis进程确实在监听所有网络接口(0.0.0:6379)而不是仅本地(0.0.1:6379),这算是双重验证。

总结一下这次排查

这次Redis端口突然连不上的问题,根本原因在于云平台安全组的策略变动,导致客户端IP失去了访问权限,整个排查思路就像一个侦探破案:先确认“受害者”(Redis进程)是否存活;然后勘察“道路”(网络和端口连通性);接着排查“关卡”(防火墙和安全组);最后再检查一下“门锁”的配置(Redis的bind和protected-mode设置),按照这个从简到繁、从内到外的顺序,大部分网络连接类的问题都能比较快地定位和解决。telnet命令是判断端口连通性的最好帮手。