数组可以包含混合类型,它不要求所有的元素都是相同的类型。例如,一个有4个interges和1个bulk string的数组可以编码为:
*5\r\n :1\r\n :2\r\n :3\r\n :4\r\n $6\r\n foobar\r\n
(为清晰起见响应被分为多行)。
服务器发送的第一行 *5\r\n 表示后跟有5个响应,然后每个代表元素的响应被发送。
Null 数组的概念同样存在,它是Null值的替代方式 (通常使用Null Bulk String,但由于历史原因我们有两种格式)。
例如当BLPOP命令超时,它返回一个长度为-1的Null 数组,如下所示:
"*-1\r\n"
在服务端返回Null数组时,客户端库API应该返回null对象而不是空数组。区分返回空的列表与其他的情况(如BLPOP命令超时的情况)是有必要的。
RESP允许数组的数组。例如一个含两个数组的数组编码如下:
*2\r\n *3\r\n :1\r\n :2\r\n :3\r\n *2\r\n +Foo\r\n -Bar\r\n
高效解析Redis协议
尽管Redis协议非常可读并且容易实现,它却可以兼得二进制协议的高效。
RESP使用长度前缀来传输bulk 数据,所以不需要像JSON一样扫描数据负载中的特殊符号,或者用引号括住数据负载。
Bulk和Multi Bulk长度的处理可以一次处理一个字符,同时可以扫描CR字符,像如下的C代码:
#includeint main(void) { unsigned char *p = "$123\r\n"; int len = 0; p++; while(*p != '\r') { len = (len*10)+(*p - '0'); p++; } /* Now p points at '\r', and the len is in bulk_len. */ printf("%d\n", len); return 0; }
当第一个CR被识别后,后面的LF可以忽略不处理。然后bulk数据可以一次读取而不需要分析 数据负载。最后剩下的CR和LF字符串可以丢弃不处理。
与二进制协议比较性能时,Redis协议在大部分的高级语言实现起来足够简单,减少了客户端软件的bug数量。
注:
1. 协议中的CR和LF相当于分割符,命令间存在多个CRLF不应影响后续解析,应为多个CRLF应被忽略掉。例如:
$> (printf "PING\r\nPING\r\nPING\r\n\r\n\rPING\r\n"; sleep 1) | nc localhost 6379 +PONG +PONG +PONG +PONG
2. 对比一下memcached的协议,redis的协议确实设计得比较精简:
(1) 一致的请求形式。redis的请求都是以 Bluk String 数组发送,不同命令只是数组的元素个数不同,所有命令的处理可以先读取完整个数组再根据不同命令解析数组的参数;而不是像mc协议一样,不同请求的命令格式不同,那么在读取网络字节流的过程中就要对不同命令做不同的处理,增加了协议解析的难度。
(2) 长度前缀是高效解析协议的关键。字段长度信息并不是二进制协议的专利,文本协议也可以有。
更多Redis相关知识,请访问Redis使用教程栏目!
以上就是redis协议是什么意思的详细内容,更多请关注其它相关文章!