Redis协议

Redis协议在以下几点之间做出了折衷:

  • 简单的实现
  • 快速地被计算机解析
  • 简单得可以能被人工解析
  • 网络层

Redis在TCP端口6379上监听到来的连接,客户端连接到来时,Redis服务器为此创建一个TCP连接。在客户端与服务器端之间传输的每个Redis命令或者数据都以\r\n结尾。

请求

Redis接收由不同参数组成的命令。一旦收到命令,将会立刻被处理,并回复给客户端。

新的统一请求协议

新的统一协议已在Redis 1.2中引入,但是在Redis 2.0中,这就成为了与Redis服务器通讯的标准方式。

在这个统一协议里,发送给Redis服务端的所有参数都是二进制安全的。以下是通用形式:

*<number of arguments> CR LF
$<number of bytes of argument 1> CR LF
<argument data> CR LF
...
$<number of bytes of argument N> CR LF
<argument data> 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"

在Redis的回复中也使用这样的格式。批量回复时,这种格式用于每个参数$6\r\nmydata\r\n。 实际的统一请求协议是Redis用于返回列表项,并调用 Multi-bulk回复。 仅仅是N个以以*<argc>\r\n为前缀的不同批量回复,<argc>是紧随的参数(批量回复)数目。</argc></argc>

回复

Redis用不同的回复类型回复命令。它可能从服务器发送的第一个字节开始校验回复类型:

  • 用单行回复,回复的第一个字节将是“+”
  • 错误消息,回复的第一个字节将是“-”
  • 整型数字,回复的第一个字节将是“:”
  • 批量回复,回复的第一个字节将是“$”
  • 多个批量回复,回复的第一个字节将是“*”

Simple Strings

状态回复(或者单行回复)以“+”开始以“\r\n”结尾的单行字符串形式。例如:

"+OK\r\n"

客户端库将在“+”后面返回所有数据,正如上例中字符串“OK”一样。

Errors

错误回复发送类似于状态回复。唯一的不同是第一个字节用“-”代替“+”。

错误回复仅仅在一些意料之外的事情发生时发送,例如:如果你试图执行一个操作来应付错误的数据类型,或者如果命令不存在等等。所以当收到一个错误回复时,客户端将会出现一个异常。

Integers

这种回复类型只是用CRLF结尾字符串来表示整型,用一个字节的“:”作为前缀。例如:“:0\r\n”,或者“:1000\r\n”是整型回复。

像INCR或者LASTAVE命令用整型回复作为实际回复值,此时对于返回的整型没有特殊的意思。它仅仅是为INCR、LASTSAVE的UNIX时间等增加数值。

一些命令像EXISTS将为true返回1,为false返回0。

其它命令像SADD、SREM和SETNX如果操作实际完成了的话将返回1,否则返回0。

接下来的命令将回复一个整型回复:SETNX、DEL、EXISTS、INCR、INCRBY、DECR、DECRBY、DBSIZE、LASTSAVE、RENAMENX、MOVE、LLEN、SADD、SREM、SISMEMBER、SCARD。

Bulk Strings

批量回复被服务器用于返回一个单二进制安全字符串。

C: GET mykey
S: $6\r\nfoobar\r\n

服务器发送第一行回复,该行以“$”开始后面跟随实际要发送的字节数,随后是CRLF,然后发送实际数据,随后是2个字节的额外数据用于最后的CRLF。服务器发送的准确序列如下:

"$6\r\nfoobar\r\n"

如果请求的值不存在,批量回复将使用特殊的值-1来作为数据长度,例如:

C: GET nonexistingkey
S: $-1

当请求的对象不存在时,客户端库API不会返回空字符串,而会返回空对象。例如:Ruby库返回‘nil’,而C库返回NULL(或者在回复的对象里设置指定的标志)等等。

Arrays

像命令LRNGE需要返回多个值(列表的每个元素是一个值,而LRANGE需要返回多于一个单元素)。使用多批量写是有技巧的,用一个初始行作为前缀来指示多少个批量写紧随其后。批量回复的第一个字节总是*,例如:

C: LRANGE mylist 0 3
s: *4
s: $3
s: foo
s: $3
s: bar
s: $5
s: Hello
s: $5
s: World

正如您可以看到的多批量回复是以完全相同的格式使用Redis统一协议将命令发送给服务器。

服务器发送的第一行是*4\r\n,用于指定紧随着4个批量回复。然后传送每个批量写。

如果指定的键不存在,则该键被认为是持有一个空的列表,且数值0被当作多批量计数值来发送,例如:

C: LRANGE nokey 0 1
S: *0

当BLPOP命令超时时,它返回nil多批量回复。这种类型多批量回复的计数器是-1,且值被当作nil来解释。例如:

C: BLPOP key 1
S: *-1

当这种情况发生时,客户端库API将返回空nil对象,且不是一个空列表。这必须有别于空列表和错误条件(例如:BLPOP命令的超时条件)。

多批量回复中的Nil元素

多批量回复的单元素长度可能是-1,为了发出信号这个元素被丢失且不是空字符串。这种情况发送在SORT命令时,此时使用GET模式选项且指定的键丢失。一个多批量回复包含一个空元素的例子如下:

S: *3
S: $3
S: foo
S: $-1
S: $3
S: bar

第二个元素是空。客户端库返回如下:

["foo",nil,"bar"]

多命令和管道

客户端能使用同样条件为了发出多个命令。管道用于支持多命令能够被客户端用单写操作来发送,它不需要为了发送下一条命令而读取服务器的回复。所有回复都能在最后被读出。

通常Redis服务器和客户端拥有非常快速的连接,所以在客户端的实现中支持这个特性不是那么重要,如果一个应用需要在短时间内发出大量的命令,管道仍然会非常快。

旧协议发送命令

在统一请求协议出现前,Redis用不同的协议发送命令,现在仍然支持,它简单通过手动telnet。在这种协议中,有两种类型的命令:

  • 内联命令:简单命令其参数用空格分割字符串。非二进制安全。
  • 批量命令:批量命令准确如内联命令,但是最后的参数用特殊方式来处理用于保证最后参数二进制安全。 内联命令

最简单的发送Redis命令的方式是通过内联命令。下面是一个使用内联命令聊天的服务器/客户端的例子(服务器聊天用S:开始,客户端聊天用C:开始)。

C: PING
S: +PONG

下面是另外一个内联命令返回整数的例子:

C: EXISTS somekey
S: :0

因为‘somekey’不存在,所以服务器返回‘:0’。

注意:EXISTS命令带有一个参数。参数用空格分割。

批量命令

一些命令当用内联命令发送时需要一种特殊的格式用于支持最后参数二进制安全。这种命令用最后参数作为“字节计数器”,然后发送批量数据(因为服务器知道读取多少个字节,所以是二进制安全的)。

请看下面的例子:

C: SET mykey 6
C: foobar
S: +OK

这条命令的最后一个参数是‘6’。这用于指定随后数据的字节数,即字符串“foobar”。注意:虽然这个字节流是以额外的两个CRLF字节结尾的。

所有批量命令都是用这种准确的格式:用随后数据的字节数代替最后一个参数,紧跟着后面是组成参数本身的字节和CRLF。为了更清楚程序,下面是通过客户端发送字符串的例子:

"SET mykey 6\r\nfoobar\r\n"

Redis有一个内部列表,用于表示哪些命令是内联,哪些命令是批量,所以你不得不发送相应的命令。强烈建议使用新的统一请求协议来代替老的协议。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,907评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,987评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,298评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,586评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,633评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,488评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,275评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,176评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,619评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,819评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,932评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,655评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,265评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,871评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,994评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,095评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,884评论 2 354

推荐阅读更多精彩内容