3. Redis的通信協(xié)議
先貼一個 官方文檔
3.1 RESP
RESP(redis Serialization Protocol)是Redis的序列化協(xié)議,主要優(yōu)勢在于:
- 實(shí)現(xiàn)過程簡單
- 解析性能極好
- 可讀性強(qiáng)
RESP可序列化不同的數(shù)據(jù)類型,包括:簡單字符串、錯誤類型、整數(shù)、批量字符串和數(shù)組。請求從客戶端發(fā)送到Redis服務(wù)器,作為表示要執(zhí)行命令的參數(shù)的字符串?dāng)?shù)組,Redis-server會使用特定的數(shù)據(jù)類型進(jìn)行回復(fù)。
RESP是二進(jìn)制安全的,不需要處理從一個進(jìn)程傳輸?shù)搅硪粋€進(jìn)程的批量數(shù)據(jù),因?yàn)樗褂们熬Y來確定是否傳輸批量數(shù)據(jù)。
注意:RESP 雖然是為 Redis 設(shè)計(jì)的,但是同樣也可以用于其他 C/S 的軟件。Redis Cluster使用不同的二進(jìn)制協(xié)議(gossip),以便在節(jié)點(diǎn)之間交換消息。
Redis協(xié)議將傳輸?shù)慕Y(jié)構(gòu)數(shù)據(jù)分為5種最小單元類型,單元結(jié)束時統(tǒng)一加上回車換行符"\r\n"(CRLF)結(jié)束。
- "+"表示簡單字符串 Simple Strings,即:單行字符串
- "$"表示批量字符串Bulk Strings,后跟字符串長度
- ":"表示整數(shù)
- "-"表示錯誤消息
- "*"表示數(shù)組
3.2 驗(yàn)證RESP
SET key value #對應(yīng)的resp通信協(xié)議串
*3
$3
SET
$3
key
$5
value
第一次看到這個通信協(xié)議串,看不懂不必?fù)?dān)心,我們按照RESP的協(xié)議說明慢慢看,并且下文會有詳細(xì)的講解。
這里大概翻譯一下這段傳輸?shù)臄?shù)據(jù)含義:
- 第一行
*3表示這條發(fā)給Redis server的命令是數(shù)組,數(shù)組有3個元素(其實(shí)就是SET、key、value這仨字符串);
后面的6行數(shù)據(jù),分別是對數(shù)組三個元素的表示,每個元素用兩行; - 數(shù)組第一個元素:<
3`代表Bulk Strings字符串長度為3,內(nèi)容是SET。
- 數(shù)組第二個元素:<
3`代表Bulk Strings字符串長度為3,內(nèi)容是key。
- 數(shù)組第三個元素:
$5 value``$5代表Bulk Strings字符串長度為5,內(nèi)容是value。
3.3 具體類型說明
3.3.1簡單字符串Simple Strings
簡單字符串按以下方式編碼:+字符,后跟不能包含CR或LF字符的字符串(不允許換行),由CRLF終止(即“\r\n”)。
Simple Strings用于以最小的開銷、傳輸非二進(jìn)制安全字符串。例如,許多Redis命令在成功時僅回復(fù)“OK”,因?yàn)镽ESP Simple String使用以下5個字節(jié)進(jìn)行編碼:
+OK\r\n
當(dāng)Redis使用Simple String回復(fù)時,該字符串由'+'之后的第一個字符組成,直到字符串結(jié)尾,不包括最終的CRLF字節(jié)。
3.3.2 RESP錯誤
RESP具有特定的錯誤數(shù)據(jù)類型。實(shí)際上錯誤與RESP Simple Strings完全相同,但第一個字符是減-字符而不是加號。RESP中簡單字符串和錯誤之間的真正區(qū)別在于客戶端將錯誤視為異常,組成錯誤類型的字符串是錯誤消息本身。
基本格式是:-ERR errorMsg\r\n
錯誤回復(fù)僅在發(fā)生錯誤時發(fā)送,例如,如果你嘗試對錯誤的數(shù)據(jù)類型執(zhí)行操作,或者命令不存在等等。收到錯誤答復(fù)時,庫客戶端應(yīng)引發(fā)異常。
以下是錯誤回復(fù)的示例:
-ERR unknown command 'foobar'
-WRONGTYPE Operation against a key holding the wrong kind of value
“-”之后的第一個單詞,直到第一個空格或換行符,表示返回的錯誤類型。這只是Redis使用的約定,不是RESP錯誤格式的一部分。
例如,ERR是一般錯誤,而WRONGTYPE更具體的錯誤意味著客戶端嘗試對錯誤的數(shù)據(jù)類型執(zhí)行操作。這稱為錯誤前綴,是一種允許客戶端理解服務(wù)器返回的錯誤類型的方法,而不依賴于給定的確切消息,這可能隨時間而變化。
下面是幾個使用redis-cli的實(shí)際錯誤的例子:
127.0.0.1:6379> TaoBeier
-ERR unknown command 'TaoBeier'\r\n # 服務(wù)端實(shí)際返回, 下同
---
(error) ERR unknown command 'TaoBeier' # redis-cli 客戶端顯示, 下同
127.0.0.1:6379> set name TaoBeier love
-ERR syntax error\r\n
---
(error) ERR syntax error
客戶端實(shí)現(xiàn)可以針對不同的錯誤返回不同類型的異常,或者可以通過直接將錯誤名稱作為字符串提供給調(diào)用者來提供捕獲錯誤的通用方法。
但是,錯誤類型很少有用,并且有限的客戶端實(shí)現(xiàn)可能只是返回一般的錯誤條件,例如false。
3.3.3整數(shù)類型
此類型只是一個CRLF終止的字符串,表示一個以:字節(jié)為前綴的整數(shù)。例如:0 \r\n或:1000 \r\n是整數(shù)回復(fù)。
很多Redis命令返回RESP整數(shù)類型,比如INCR,LLEN和LASTSAVE。
返回的整數(shù)沒有特殊含義,它只是INCR的增量數(shù),LASTSAVE的UNIX時間等等。但是,返回的整數(shù)保證在有符號的64位整數(shù)范圍內(nèi)。
整數(shù)回復(fù)也被廣泛使用以返回真或假。例如,EXISTS或SISMEMBER之類的命令將返回1表示true,0表示false表示。
如果操作實(shí)際執(zhí)行,其他命令如SADD,SREM和SETNX將返回1,否則返回0。
下面的命令都是整數(shù)類型回復(fù):SETNX,DEL, EXISTS,INCR,INCRBY,DECR,DECRBY,DBSIZE,LASTSAVE, RENAMENX,MOVE,LLEN,SADD,SREM,SISMEMBER,SCARD。
3.3.4 Bulk Strings類型
翻譯過來,是指批量、多行字符串。
Bulk Strings用于表示長度最大為512MB的單個二進(jìn)制安全字符串。
批量字符串按以下方式編碼:
- 一個
$字節(jié)后跟組成字符串的字節(jié)數(shù)(一個前綴長度),由CRLF終止。 - 實(shí)際的字符串?dāng)?shù)據(jù)。
- 最終的CRLF。
所以字符串“foobar”的編碼如下:
$6\r\n
foobar\r\n"
一個完整的Bulk Strings,主要包括兩行:
第一行,$后面跟上字符串長度;
第二行,就是實(shí)際的字符串。
如下面執(zhí)行set、get的例子:
127.0.0.1:6379> set site ljheee
+OK\r\n # 服務(wù)端實(shí)際返回, 下同
---
OK # redis-cli 客戶端顯示, 下同
127.0.0.1:6379> get site
$6\r\
ljheee\r\n
---
"ljheee"
在執(zhí)行set site value時,客戶端給Redis server發(fā)送RESP命令后,Redis server返回的是simple strings類型+OK\r\n,redis-cli命令行客戶端給我們只顯示了有效字符、省略了最后的CRLF。
在執(zhí)行get site時,Redis server返回的是Bulk Strings類型,第一行$6代表site對應(yīng)的value值length為6,第二行是實(shí)際value值。
當(dāng)只是一個空字符串時,表示為:$0\r\n
Bulk Strings也可用于使用用于表示Null值的特殊格式來表示值的不存在。在這種特殊格式中,長度為-1,并且沒有數(shù)據(jù),因此Null表示為:$-1\r\n,這稱為Null Bulk String。
3.3.5 數(shù)組類型
客戶端使用數(shù)組、將命令發(fā)送到Redis服務(wù)器。類似地,某些Redis命令將元素集合返回給客戶端使用數(shù)組類型回復(fù)。如LRANGE命令,它返回元素列表其實(shí)就是數(shù)組類型。
RESP數(shù)組使用以下格式發(fā)送:
- 它以 “*” 開頭,后面跟著返回元素的個數(shù),后跟CRLF。
- 然后就是數(shù)組中各元素自己的類型了,數(shù)組每個元素可以是任意的RESP類型。
最典型的是 LRRANGE 命令,返回的就是數(shù)組類型
LRANGE info 0 -1
*2\r\n
$3\r\
abc\r\n
$6\r\n
ljheee\r\n
--- # 實(shí)際redis-cli顯示
1) "abc"
2) "ljheee"
返回的結(jié)果,*2代表數(shù)組長度為2,數(shù)組的第一個元素$3是長度為3的字符串a(chǎn)bc;數(shù)組的第二個元素$6是長度為6的字符串ljheee。