Redis 之 RESP 协议

Redis 之 RESP 协议

RESP 协议简介

Redis 的客户端和服务端之间在 TCP 协议的上层采用一种独立名为 RESP(REdis Serialization Protocol) 协议作为进行通讯的标准方式。

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

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

新的统一协议已在Redis 1.2中引入,但是在Redis 2.0中,这就成为了与Redis服务器通讯的标准方式。在这个统一协议里,发送给Redis服务端的所有参数都是二进制安全的。Redis用不同的回复类型回复命令。它可以从服务器发送的第一个字节开始校验回复类型:

  • 单行回复(单行字符串回复),回复的第一个字节将是“+”
  • 错误消息(单行字符串回复的另外展示形式),回复的第一个字节将是“-”
  • 整型回复(正整形数字回复),回复的第一个字节将是“:”
  • 批量回复(多行字符串回复),回复的第一个字节将是“$”
  • 多个批量回复(数组回复),回复的第一个字节将是“*”

传输层及网络层

传输层仍然是底层 TCP 传输。Redis在TCP端口6379上监听到来的连接,客户端连接到来时,Redis服务器为此创建一个TCP连接。在客户端与服务器端之间传输的每个Redis命令或者数据都以\r\n结尾。Redis接收由不同参数组成的命令。一旦收到命令,将会立刻被处理,并回复给客户端。

关于校验回复类型

单行回复(单行字符串回复):"+"

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

> set name leeprince
+OK\r\n  # 服务端实际返回
---
OK # redis-cli 客户端显示

错误消息(单行字符串回复的另外展示形式):"-"

错误回复发送类似于状态回复。唯一的不同是第一个字节用“-”代替“+”。
错误回复仅仅在一些意料之外的事情发生时发送,例如:如果你试图执行一个操作来应付错误的数据类型,或者如果命令不存在等等。所以当收到一个错误回复时,客户端将会出现一个异常。例如:

> leeprince
-(error) ERR unknown command `leeprince`, with args beginning with:\r\n  # 服务端实际返回
---
(error) ERR unknown command `leeprince`, with args beginning with:  # redis-cli 客户端显示

整型回复(正整形数字回复):":"

这种回复类型只是用CRLF结尾字符串来表示整型,用一个字节的“:”作为前缀。例如:“:0\r\n”,或者“:1000\r\n”是整型回复。
像INCR或者LASTAVE命令用整型回复作为实际回复值,此时对于返回的整型没有特殊的意思。它仅仅是为INCR、LASTSAVE的UNIX时间等增加数值。
一些命令像EXISTS将为true返回1,为false返回0。
其它命令像SADD、SREM和SETNX如果操作实际完成了的话将返回1,否则返回0。例如:

>rpush intkey intvalue01 intvalue02 intvalue03
:3\r\n   # 服务端实际返回
---
(integer) 3 # redis-cli 客户端显示

以下命令都是回复一个整型:

SETNX、DEL、EXISTS、INCR、INCRBY、DECR、DECRBY、DBSIZE、LASTSAVE、RENAMENX、MOVE、LLEN、SADD、SREM、SISMEMBER、SCARD。

批量回复(多行字符串回复):”$“

批量回复被服务器用于返回一个单二进制安全字符串。服务器发送第一行回复,该行以“$”开始后面跟随实际要发送的字节数,随后是CRLF,然后发送实际数据,随后是2个字节的额外数据用于最后的CRLF。例如:

>get bulkkey
$9\r\nbulkvalue\r\n   # 服务端实际返回
---
"bulkvalue"  # redis-cli 客户端显示

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

>get bulkkey_
$-1 # 服务端实际返回
---
(nil) # redis-cli 客户端显示

多个批量回复(数组回复):”*“

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

127.0.0.1:6379> rpush arraykey a01 a0101
(integer) 2 # redis-cli 客户端显示
127.0.0.1:6379> lrange arraykey 0 -1
# 服务端实际返回
*2\r\n$3\r\na01$5\r\na0101\r\n  
--- 
# redis-cli 客户端显示    
1) "a01"
2) "a0101"

正如您可以看到的多批量回复是以完全相同的格式使用Redis统一协议将命令发送给服务器。
服务器发送的第一行是*4\r\n,用于指定紧随着4个批量回复。然后传送每个批量写。
如果指定的键不存在,则该键被认为是持有一个空的列表,且数值0被当作多批量计数值来发送,例如:

127.0.0.1:6379> LRANGE nokey 0 1
# 服务端实际返回
*0
---
# redis-cli 客户端显示    
(empty list or set)

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

127.0.0.1:6379> BLPOP nokey 1
# 服务端实际返回
*-1
---
# redis-cli 客户端显示 
(nil)
(1.09s)

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

多命令和管道(pipelining)

客户端能使用同样条件为了发出多个命令。管道用于支持多命令能够被客户端用单写操作来发送,它不需要为了发送下一条命令而读取服务器的回复。所有回复都能在最后被读出。
通常Redis服务器和客户端拥有非常快速的连接,所以在客户端的实现中支持这个特性不是那么重要,如果一个应用需要在短时间内发出大量的命令,管道仍然会非常快。

管道(Pipelining) VS 脚本(Scripting)

大量 pipeline 应用场景可通过 Redis 脚本(Redis 版本 >= 2.6)得到更高效的处理,后者在服务器端执行大量工作。脚本的一大优势是可通过最小的延迟读写数据,让读、计算、写等操作变得非常快(pipeline 在这种情况下不能使用,因为客户端在写命令前需要读命令返回的结果)。
应用程序有时可能在 pipeline 中发送 EVAL 或 EVALSHA 命令。Redis 通过 SCRIPT LOAD 命令(保证 EVALSHA 成功被调用)明确支持这种情况。

Redis 大量数据插入

pipe mode的工作原理是什么?

难点是保证redis-cli在pipe mode模式下执行和netcat一样快的同时,如何能理解服务器发送的最后一个回复。
这是通过以下方式获得:

redis-cli –pipe试着尽可能快的发送数据到服务器。
读取数据的同时,解析它。
一旦没有更多的数据输入,它就会发送一个特殊的ECHO命令,后面跟着20个随机的字符。我们相信可以通过匹配回复相同的20个字符是同一个命令的行为。
一旦这个特殊命令发出,收到的答复就开始匹配这20个字符,当匹配时,就可以成功退出了。

同时,在分析回复的时候,我们会采用计数器的方法计数,以便在最后能够告诉我们大量插入数据的数据量。

参考

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

推荐阅读更多精彩内容