Redis 通讯协议分析

2018-01-16 12:40:18来源:oschina作者:IamOkay人点击

分享
简介

Redis本质上是一个Key-Value类型的内存数据库,很像memcached,整个数据库统统加载在内存当中进行操作,定期通过异步操作把数据库数据flush到硬盘上进行保存。Redis的性能非常出色,每秒可以处理超过 10万次读写操作,是已知性能最快的Key-Value DB。


Redis的出色之处不仅仅是性能,Redis最大的魅力是支持保存多种数据结构,此外单个value的最大限制是1GB,不像 memcached只能保存1MB的数据,因此Redis可以用来实现很多有用的功能,比方说用他的List来做FIFO双向链表,实现一个轻量级的高性 能消息队列服务,用他的Set可以做高性能的tag系统等等。另外Redis也可以对存入的Key-Value设置expire时间,因此也可以被当作一 个功能加强版的memcached来用。


Redis利用队列技术将并发访问变为串行访问,消除了传统数据库串行控制的开销。


Redis的主要缺点是数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,因此Redis适合的场景主要局限在较小数据量的高性能操作和运算上。

Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。

Redis 通讯协议

Redis 协议在以下三个目标之间进行折中:

易于实现
可以高效地被计算机分析(parse)
可以很容易地被人类读懂

①协议说明


客户端和服务器通过 TCP 连接来进行数据交互, 服务器默认的端口号为 6379 。客户端和服务器发送的命令或数据一律以/r/n(CRLF)结尾。Redis 服务器接受命令以及命令的参数。服务器会在接到命令之后,对命令进行处理,并将命令的回复传送回客户端。在这个协议中, 所有发送至 Redis 服务器的参数都是二进制安全(binary safe)的。


②协议模板


*<参数数量> CR LF
$<参数 1 的字节数量> CR LF
<参数 1 的数据> CR LF
...
$<参数 N 的字节数量> CR LF
<参数 N 的数据> CR LF

译注:命令本身也作为协议的其中一个参数来发送


*3
$3
SET
$5
mykey
$7
myvalue

这个命令的实际协议值如下:


"*3/r/n$3/r/nSET/r/n$5/r/nmykey/r/n$7/r/nmyvalue/r/n"

稍后我们会看到, 这种格式除了用作命令请求协议之外, 也用在命令的回复协议中: 这种只有一个参数的回复格式被称为批量回复(Bulk Reply)。


统一协议请求原本是用在回复协议中, 用于将列表的多个项返回给客户端的, 这种回复格式被称为多条批量回复(Multi Bulk Reply)。


一个多条批量回复以*/r/n为前缀, 后跟多条不同的批量回复, 其中argc为这些批量回复的数量。


②回复协议


Redis 命令会返回多种不同类型的回复。


通过检查服务器发回数据的第一个字节, 可以确定这个回复是什么类型:

状态回复(status reply)的第一个字节是"+"
错误回复(error reply)的第一个字节是"-"
整数回复(integer reply)的第一个字节是":"
批量回复(bulk reply)的第一个字节是"$"
多条批量回复(multi bulk reply)的第一个字节是"*"

服务器使用批量回复来返回二进制安全的字符串,字符串的最大长度为 512 MB 。


客户端:GET mykey
服务器:foobar

服务器发送的内容中:

第一字节为"$"符号
接下来跟着的是表示实际回复长度的数字值
之后跟着一个 CRLF
再后面跟着的是实际回复数据
最末尾是另一个 CRLF

对于前面的GET命令,服务器实际发送的内容为:


"$6/r/nfoobar/r/n"

如果被请求的值不存在, 那么批量回复会将特殊值-1用作回复的长度值, 就像这样:


客户端:GET non-existing-key
服务器:$-1

这种回复称为空批量回复(NULL Bulk Reply)。


当请求对象不存在时,客户端应该返回空对象,而不是空字符串: 比如 Ruby 库应该返回nil, 而 C 库应该返回NULL(或者在回复对象中设置一个特殊标志), 诸如此类。


LRANGE这样的命令需要返回多个值, 这一目标可以通过多条批量回复来完成。


多条批量回复是由多个回复组成的数组, 数组中的每个元素都可以是任意类型的回复, 包括多条批量回复本身。


多条批量回复的第一个字节为"*", 后跟一个字符串表示的整数值, 这个值记录了多条批量回复所包含的回复数量, 再后面是一个 CRLF 。


客户端: LRANGE mylist 0 3
服务器: *4
服务器: $3
服务器: foo
服务器: $3
服务器: bar
服务器: $5
服务器: Hello
服务器: $5
服务器: World

在上面的示例中,服务器发送的所有字符串都由 CRLF 结尾。


正如你所见到的那样, 多条批量回复所使用的格式, 和客户端发送命令时使用的统一请求协议的格式一模一样。 它们之间的唯一区别是:

统一请求协议只发送批量回复。
而服务器应答命令时所发送的多条批量回复,则可以包含任意类型的回复。

以下例子展示了一个多条批量回复, 回复中包含四个整数值, 以及一个二进制安全字符串:


*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 条回复, 再后面跟着的则是 5 条回复的正文。


多条批量回复也可以是空白的(empty), 就像这样:


客户端: LRANGE nokey 0 1
服务器: *0/r/n

无内容的多条批量回复(null multi bulk reply)也是存在的, 比如当BLPOP命令的阻塞时间超过最大时限时, 它就返回一个无内容的多条批量回复, 这个回复的计数值为-1:


客户端: BLPOP key 1
服务器: *-1/r/n

客户端库应该区别对待空白多条回复和无内容多条回复: 当 Redis 返回一个无内容多条回复时, 客户端库应该返回一个 null 对象, 而不是一个空数组。

参考

redis面试总结


redis用法详解


最新文章

123

最新摄影

闪念基因

微信扫一扫

第七城市微信公众平台