问题描述:
代码是从另一个php项目拷贝过来了,都是用redis简单存储kv。本地报错有点懵逼,网上找了一下原因,大致是连接数过多,导致连接不上服务器,设置read_write_timeout=-1,重启服务等。试了没毛的用。。
use Illuminate\Support\Facades\Redis;
...
Redis::exists('proc:' . $relationId);
Redis::setex('proc:' . $v['id'], 10, 1);
$sendTimeList = Redis::get('sendTimeList');
if (!in_array($sendTime, $sendTimeList)) {
$sendTimeList[] = $sendTime;
Redis::set('sendTimeList', $sendTimeList);
}
解决方案:
问题定位到最后的Redis::set('sendTimeList', $sendTimeList);
,对比上面那两个redis发现存储的结构是数组会复杂一点,再结合偶尔会出现message:ERR Protocol error: invalid bulk length
, 试着把数组转成字符串存储后就正常运行了。。
$sendTimeList = json_decode(Redis::get('sendTimeList'), true);
if (!in_array($sendTime, $sendTimeList)) {
$sendTimeList[] = $sendTime;
Redis::set('sendTimeList', json_encode($sendTimeList));
}
复盘
之前项目redis用的是1.1.1版本的predis,redis版本是3.2,可以正常运行。
当前项目laravel用的是1.1.7版本的predis,redis版本是6.0,报错。
docker给当前项目新增一个3.2版本的测试,发现还是会报错,排除redis版本问题。
1.1.7版本的问题?。。。不想研究了
不能解决问题?尝试其他方法~以下是复制粘贴过来了,搜索引擎翻了好几页都是这个玩意
连接数过多,导致连接不上服务器??
查看进程,看看是否有大量redis状态为TIME_WAIT的tcp连接。
有的话首先考虑减少TIME_WAIT的进程,保证随时可以连接到服务器,将进程快速回收。
修改内核参数sysctl.conf,net.ipv4.tcp_timestamps=1(1为开启),
开启快速回收net.ipv4.tcp_tw_recycle=1。
tw_recycle是通过时间戳判断哪个是最新的进程,将不是最新的TIME_WAIT的进程回收,所以需要先开启tcp_timestamps。
修改后观察,果然没有继续报错。
但是使能快速回收TIME_WAIT进程,可能会丢包,导致没有收到应答,不能成功建立连接。但这种办法也不是最佳解决办法,尤其修改内核参数,涉及环节太多,需深入了解才可修改。
底层不去修改,就从predis客户端入手,源码发现有read_write_timeout这个参数,可以设置超时时间,这样读取流数据时就不会报错。Predis作者建议设置关闭redis.conf中timeout(修改timeout 0),表示不关闭与客户端的连接,我感觉这样比较耗费资源,可以适当增加timeout时间。
所以这次暂时是这样解决的,设置read_write_timeout=-1和redis.conf的timeout参数。