redis报protocol error的真正原凶

前段时间写了个文章详细描述了在什么场景下会出现redis的protocol error错误,但是手抽筋, 不小心点错给删了,而且还原不了,没办法了,只能重写一下,但是没上次那么详细了,如果不太明白就看源代码吧!首先呢,这种错误是基于使用了phpredis的的长连接和multi功能才会出现!这里有两个问题

1、当你开了事务,做了N次写操作,然后又discard之后又做了M次操作(M小于N),这样请求就会被阻塞住(这个操作无论使用短连接还是长连接,都能复现),具体看代码:

$redis = new Redis();
$redis->connect('localhost', 6379);
$redis->multi();
$redis->set('test', 10);
$redis->zIncrBy('test2', 1, 'bbb');
$redis->discard();
$redis->multi();
$redis->zIncrBy('test2', 2, 'bbb');
$redis->exec();//操作会阻塞在这里

因为phpredis在discard成功后,没有清理callback list,所以卡住了。

2、开事务,做N次操作,discard之后再做M次操作(但这里M大于N),多刷几次就会出现protocol error(这个必须使用长连接才会复现)!

$redis = new Redis();
$redis->pconnect('localhost', 6379);
$redis->multi();
$redis->set('test', 10);
$redis->discard();
$redis->multi();
$redis->zIncrBy('test2', 2, 'bbb');
$redis->zIncrBy('test2', 1, 'bbb');
$redis->exec();

跟上面原因一样,discard没的清理callback list, 就会出现stream里面的数据没读完!协议就完全乱掉了,

那么上面说的callback list又是什么东西呢?在redis里面,当你使用了multi,在执行exec之前的请求基本都是返回+QUEUED(如果需要了解更详细redis协议,请见redis.io),而真正返回数据是等exec执行之后,才去解析返回数据。所以phpredis针对不同的请求处理方式是不一样的,所以在开启了multi之后,phpredis会维护一个处理函数列表,比如set(k,v)这需要绑定一个bool值处理函数,而zincrBy需要绑定一个double值处理函数,执行exec之后,去遍历这个列表处理返回数据就即可。

由于redis针对multi之后的请求都是队列并没有执行,所以客户端可以使用discard命令来清空这个队列,同时客户端也应该将之前绑定的函数列表一并清除,可是phpredis对于discard的处理仅仅是发送了discard命令到redis服务端,却没有清空处理函数列表。只是在下一次执行multi的时候,他仅仅是将这个处理函数列表中一个叫current的指针值为NULL(这个列表是一个单向连表,head表示头元素,current表示尾元素),可是他忽略了head,因为函数列表一旦进入处理是从head开始,只有需要新加函数到列表的时候才会用到current。所以在phpredis里面,执行一条命令,再discard,再执行两条命令之后,这个处理函数列表里只有一个函数(正确应该是两个,而且还是最开始加的那一个,后面加的两个,不翼而飞了。。),处理函数与返回数据不配对,协议自然也就乱了,这就是protocol error报错的由来....

时间: 2024-10-14 16:39:30

redis报protocol error的真正原凶的相关文章

lnk1120-vs2010运行程序报错:error LNK2019: 无法解析的外部符号

问题描述 vs2010运行程序报错:error LNK2019: 无法解析的外部符号 如题,我在vs2010环境下做C++练习题时出现该错误.程序代码如下: //array.h#ifndef ARRAY_H#define ARRAY_Htemplate<typename T>class Array{public: Array(int n);//数组首地址不用指定,待会分配 Array(Array &a); ~Array(); T getAt(int i);//返回第i个数组元素 voi

php图片上传报错error=3

问题描述 php图片上传报错error=3 upload: <?php/** Created by PhpStorm. User: rosen Date: 15-11-5 Time: 下午8:43*/print_r($_FILES['file']); ?> 为什么程序运行结果报错Array ( [name] => 2015-10-19 18:47:42屏幕截图.png [type] => [tmp_name] => [error] => 3 [size] => 0

CentOS7 编译redis报错:您选择的 CPU 不支持 x86-64 指令集

问题描述 CentOS7 编译redis报错:您选择的 CPU 不支持 x86-64 指令集 Oracle VM VirtualBox 下 CentOS7 编译redis报错,adlist.c:1:0: 错误:您选择的 CPU 不支持 x86-64 指令集 CentOS版本如下 Last login: Wed Jan 27 11:32:21 2016 from 172.31.30.139 [root@localhost ~]# uname -a Linux localhost.localdoma

ad 域访问报错-ad 域验证报LDAP: error code 49 - 80090308: LdapErr: DSID-0C0903A9错误

问题描述 ad 域验证报LDAP: error code 49 - 80090308: LdapErr: DSID-0C0903A9错误 public String checkLogin(String userName,String password) { String host = "10.130.119.101"; // AD服务器IP String port = "389"; // 端口 // String domain = "@domain.com

请教各位大神,遇到个redis报错的问题,登录时经常遇到,一登录后台就报异常

问题描述 请教各位大神,遇到个redis报错的问题,登录时经常遇到,一登录后台就报异常 不知道怎么解决了,搜了一些方法也没解决掉 代码部分就是图上划红线那里SET的时候报错 解决方案 第二个参数转的数据,类型正确吗? 看上去获取它数据有问题.

linux使用wkhtmltopdf报错error while loading shared libraries:

官网提示 linux需要这些动态库.depends on: zlib, fontconfig, freetype, X11 libs (libX11, libXext, libXrender) 在linux上执行 ./wkhtmltopdf –page-size A4 www.baidu.com pdf.pdf 报错   error while loading shared libraries: libXrender.so.1 root@mag-sit:/home/mag-sit/wkhtmlt

javascript-jquery load 加入{} Map型参数报500 error

问题描述 jquery load 加入{} Map型参数报500 error 我的jquery load方法 left.load(url,"sdas",function(){}); left.load(url,function(){}); 以上两种方法调用都能正常使用,但是下面这种方法就报服务器500error了 left.load(url,{},function(){}); 求助大神是为什么?用的jquery2以上的版本 解决方案 你的{}里面有数据没有?没有和left.load(u

mvel no context-MVEL 使用模板,当并发量大的时候, 报错 [Error: no context]

问题描述 MVEL 使用模板,当并发量大的时候, 报错 [Error: no context] Caused by: java.lang.RuntimeException: no context at org.mvel2.ParserContext.makeVisible(ParserContext.java:684) at org.mvel2.ParserContext.addVariable(ParserContext.java:477) at org.mvel2.ast.TypedVarN

arcgis-ArcSDE 做POST报错Error: Operation Failed (-1).

问题描述 ArcSDE 做POST报错Error: Operation Failed (-1). 同一主机:Windows2008 R2 64位,ArcSDE for 11g 64bit 本机Oracle11g64位服务端,Oracle11g 32位客户端,Oracle10g 32为服务端 环境变量 path C:appAdministratorproduct11.2.0client_1bin;E:appAdministratorproduct11.2.0dbhome_1bin;C:Progra