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

开发服务器上Redis项目连不上,折腾了半天还没解决连接故障

这事儿发生在上周二下午,我记得特别清楚,当时我们团队的一个新功能刚开发完,准备部署到开发服务器上给测试同事看看,功能很简单,就是用户登录后把一些会话信息存到Redis里,方便后续读取,在我的本地电脑上,代码跑得一点问题没有,连接我自己装的Redis服务顺畅得很。

但是一把代码推到开发服务器上,启动应用,日志里就开始疯狂报错,最开始报的错误是"Connection refused",意思就是连接被拒绝了,我当时第一反应就是,哦,是不是服务器上的Redis服务没开啊?这太常见了,于是我立刻用SSH连上那台开发服务器,输入了检查服务状态的命令,系统提示说Redis服务是"active (running)",正在正常运行,这就奇怪了,服务明明开着,为啥连不上呢?

我琢磨着,是不是防火墙把端口给拦了?我们的Redis用的是默认的6379端口,我又在服务器上执行了查看防火墙规则的命令,结果发现6379端口明明是放行的,为了双重确认,我甚至尝试用服务器自带的Redis命令行客户端去连接本地的Redis服务,输入了连接命令后,啪一下就直接连上了,还能正常读写数据,这说明Redis服务本身确实是好的,问题不出在它身上。

这下我就有点懵了,不是服务的问题,那八成就是我的项目配置有问题了,我赶紧去检查项目的配置文件,看看连接Redis的那部分是怎么写的,配置里写着连接地址是"localhost",端口是6379,这看起来完全正确啊,因为项目就和Redis装在同一台服务器上,用"localhost"指向本机没毛病,我不放心,又把配置来回看了三遍,确认没有拼写错误,也没有多余的空格。

实在没辙了,我开始怀疑是不是网络层面有什么诡异的设置,我让项目运行起来,然后在服务器上执行了一个网络诊断命令,查看项目是否在正常监听端口,以及有没有建立到6379端口的连接,果然,在输出结果里,我根本看不到任何与6379端口相关的连接信息,这说明我的应用程序压根就没有成功发起连接,在尝试连接的阶段就失败了。

时间已经过去一个多小时了,我有点烦躁,只好去求助同事老张,他经验比较丰富,我把情况跟他说了,错误日志、服务状态、防火墙、配置都检查过了,老张听了一会儿,问了我一个问题:“你的应用是用Docker容器跑的吗?”我说是啊,为了环境一致,我们都用Docker容器部署,老张一拍大腿,说:“问题可能就在这儿!你在容器里用的‘localhost’,指的是容器自己,而不是宿主机(也就是那台开发服务器)。”

我瞬间就明白了!对啊,我的项目运行在一个Docker容器里,“localhost”是它这个容器内部的环境,而Redis服务是直接安装在宿主机上的,在容器里用"localhost"去找Redis,相当于在一个小房子里喊人,但那个人其实在房子外面的大街上,当然找不到。

找到方向就好办了,解决办法很简单,不能再用"localhost"了,需要用一个能指向宿主机的地址,我尝试了直接用宿主机的内网IP地址替换掉配置里的"localhost",然后重新构建Docker镜像并启动,这次,应用日志终于安静了,没有再报连接错误,功能测试也完全正常。

后来老张告诉我,更规范的做法是在启动Docker容器时使用特定的网络模式,host"模式,让容器直接使用宿主机的网络,这样在容器里访问"localhost"就等于访问宿主机,或者,也可以使用Docker Compose来同时管理应用容器和Redis容器,并让它们处于同一个自定义网络中,通过容器名称进行通信,但当时为了最快解决问题,直接用IP地址是最直接有效的。

折腾了两个小时,最后发现根源竟是一个最基本的概念问题——对“本地”的理解不同,在物理机时代,localhost就是机器本身;但在容器化的环境下,localhost的边界发生了变化,这次经历让我深刻体会到,排查问题时光有耐心还不够,还得对技术底层的基础概念有清晰的认识,否则很容易在表面现象上打转。

开发服务器上Redis项目连不上,折腾了半天还没解决连接故障