常驻内存的PHP程序报redis server has gone away

常驻内存的PHP程序redis报错问题 redis server has gone away

第一次遇到问题

近半年来公司的业务开始使用redis作为临时数据的存储和简单的消息队列。在这段时间里遇到了不少问题,因为公司的服务是workerman构建的。上redis后,经常半夜三更报redis exception 错误。
在前几次的排查过程中,我们注意到redis 报错,查找资料得知:常驻内存的PHP程序如workerman,因为redis连接长时间不通讯,被redis服务端断开了。当php里再次使用这个连接时就触发了错误。

解决方案

redis服务端如果设置timeout=0,redis服务端并不会主动关闭redis连接。 于是我们修改了redis服务端的timeout=0;这样操作以后,redis竟然没有再报错误.

第二次遇到问题

正当我们以为问题解决的时候,一天晚上,大约凌晨三点十分的样子,redis再次抛出redis server went away的错误。

报错截图

我们再次开始查找各种资料,焦头烂额之时,从运维那里得知一条重要消息,当天晚上我们服务器所在的阿里云机房发生了网络抖动,已经得到了阿里云技术工程师的确认。

阿里云售后工程师回复

于是,我们开始思考,redis连接会断开的原因,
1,redis服务端主动关闭(已被我们排除)
2,连接异常断开。
第二条正好与当天阿里云发生网络抖动相吻合 于是我们猜测阿里云网络抖动导致php与redis服务端的连接中断。

解决方案

在此猜测下,我们提出了几条解决方案
1、每次使用完redis后,销毁链接。下次使用redis的时候重新初始化链接。
2、在调用redis底层接口时捕获下异常或者判断下错误码,根据异常或者错误码判断链接是否已经断开,如果断开就重新连一次,然后重新执行要执行的查询
3、使用redis连接的时候记录下本次使用连接的时间戳,下次使用的时候当前时间减去间戳等于连接空闲的时间,如果连接空闲的时间过长,则销毁连接,重新建立一个redis链接。
4、搞个定时器,定时发一个空查询给redis服务端,类似心跳的功能,检测redis连接是否存活,不存活就关闭重连。
5、每次从单例模式中拿连接的时候给redis服务端发下ping包,检测次连接是否存活,不存活就关闭重新初始化redis连接。
下面我们来分析下几条解决方案的优点和缺点
1,缺点:每次均存在redis服务器建立TCP连接三次握手及连接关闭四次挥手的开销,不能最大程度利用workerman常驻内存的优势;优点:每次使用时建立连接,不存在redis连接失效的情况
2,缺点:需要重写redis扩展提供的方法,对现有系统改动较大,代码量较大;优点:最大化利用workerman常驻内存的优势,又最好的解决了redis连接失效抛错的问题,确保每次redis请求都能成功
3,缺点:需要记录每次redis请求的时间,需要对现有的redis扩展方法做出修改,又不能完全避免redis连接失效带来的问题。
4,缺点:无法彻底避免redis连接失效带来的问题,如如果在心跳间隙内出现问题,此方法无法处理。

5,缺点:无效请求量较大,每次拿连接都需要发送Ping包,也无法完全避免连接失效的问题,例如从拿连接到下次拿连接的间隙,如果redis连接出现故障,将无法检测到;优点:对现有系统修改最小,也能很好的避免redis连接失效带来的问题
经以上分析,最可靠的方案是第二种
但是按时为了更好的与现有的系统融合,最快解决问题的思想下,我们准备先采用第五种方案,后期逐步过渡到第二种方案.
第二种方案上线后我们会持续观察效果

发现

其实我们发现虽然php的redis扩展底层有断线自动重连机制,但是并不可靠,不然就不存在上述问题了

转载于:https://my.oschina.net/fage1151/blog/994038

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值