溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

redis協(xié)議指的是什么

發(fā)布時間:2020-11-16 13:51:46 來源:億速云 閱讀:240 作者:小新 欄目:關(guān)系型數(shù)據(jù)庫

這篇文章主要介紹redis協(xié)議指的是什么,文中介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們一定要看完!

Redis客戶端通過使用一種叫RESP(REdis Serialization Protocol, redis序列化協(xié)議)協(xié)議與Redis服務(wù)器交互。雖然這個協(xié)議是為Redis而設(shè)計的,但它也可以用于其他client-server架構(gòu)的軟件系統(tǒng)。(譯注: 從一些公開的資料來看,陌陌的IM協(xié)議設(shè)計就參考了Redis協(xié)議)

RESP 權(quán)衡了以下幾個方面:

實現(xiàn)要簡單解析要快方便人閱讀

RESP可以序列化不同的數(shù)據(jù)類型,像integers、strings、arrays,對于錯誤也設(shè)計了特殊的類型??蛻舳艘宰址畢?shù)數(shù)組的請求形式發(fā)送給Redis服務(wù)器執(zhí)行,Redis返回命令相關(guān)的數(shù)據(jù)類型。

RESP是二進(jìn)制安全(binary-safe)的,并且不需要解析由一個進(jìn)程發(fā)送給另一個進(jìn)程的bulk 數(shù)據(jù),因為它使用長度前綴來傳輸bulk 數(shù)據(jù)。

注意:這里所說的協(xié)議只用于client-server的通信。Redis Cluster使用不同的二進(jìn)制協(xié)議在node間進(jìn)行消息交互。

網(wǎng)絡(luò)層

客戶端通過建立端口為6379的TCP連接與Redis通信。

雖然RESP從技術(shù)上來說并不是TCP相關(guān)的,但對Redis來說該協(xié)議只用于TCP(或者其他流式協(xié)議如Unix域協(xié)議)。 (譯注:反觀memcached, 既支持tcp, 也支持udp, 但實際上生產(chǎn)環(huán)境基本只用tcp。我認(rèn)為這是一種過度設(shè)計了,搞不好還可能被駭客利用來做 memcached udp 反射攻擊。。。)

請求響應(yīng)模型

Redis 接收不同參數(shù)構(gòu)成的命令。當(dāng)命令接收到后就會被處理,然后響應(yīng)發(fā)送給客戶端。

這是最簡單的模型了,但有兩點(diǎn)例外:

Redis支持 pipelining (后文會提及)。所以客戶端可以一次發(fā)送多個命令,然后等待響應(yīng)。當(dāng)客戶端訂閱了一個 Pub/Sub channel, 該協(xié)議會改變語意而變成一個推送協(xié)議,也就是說客戶端不用發(fā)送命令,因為服務(wù)端在收到消息后會自動給客戶端發(fā)送新的消息(對客戶端訂閱了的channel)。

除了這兩點(diǎn),Redis協(xié)議就是一個簡單的請求-響應(yīng)協(xié)議。

RESP協(xié)議描述

RESP協(xié)議在Redis 1.2引入,但它現(xiàn)在成為Redis 2.0的標(biāo)準(zhǔn)交互協(xié)議。你應(yīng)該實現(xiàn)Redis客戶端時采用該協(xié)議。

RESP事實上是一個支持以下類型的序列化協(xié)議:Simple Strings, Errors, Integers, Bulk Strings 和 Arrays。

RESP作為一種請求響應(yīng)協(xié)議,在Redis中使用的方式如下:

客戶端發(fā)送命令到Redis服務(wù)器,以RESP Bulk Strings數(shù)組的方式。服務(wù)器根據(jù)不同的命令實現(xiàn),返回相應(yīng)的RESP實現(xiàn)。

在RESP中,一些數(shù)據(jù)的類型由第一個字節(jié)確定:

對于SImple Strings 響應(yīng)的第一個字節(jié)是“+”對于Errors 響應(yīng)的第一個字節(jié)是 "-"對于Integers 響應(yīng)第一個字節(jié)是 ":"對于Bulk Strings 響應(yīng)第一個字節(jié)是 "$" 對于Arrays 響應(yīng)第一個字節(jié)是 "*"

另外RESP可以用特殊的Bulk String或數(shù)組來表示 Null 值,后文會提及。

在RESP中協(xié)議不同部分總是用 "\r\n" (CRLF) 分隔。

RESP Simple Strings

Simple Strings通過以下方式編碼:一個加號,后跟一個字符串, 字符串不包含CR或LF字符(不能有換行),以CRLF ("\r\n")結(jié)束。

SImple Strings 以最小的代價來傳輸非二進(jìn)制安全的字符串。例如很多Redis命令在成功時響應(yīng)"OK",就是用RESP Simple String 來編碼的5個字節(jié):

"+OK\r\n"

為了傳輸二進(jìn)制安全的字符串,要用RESP Bulk Strings。

當(dāng)Redis響應(yīng)一個Simple String時,客戶端庫應(yīng)該給調(diào)用者返回從第一個"+"字符到字符串結(jié)尾的字符串,不包括CRLF 字節(jié)。

RESP Errors

RESP 對于error有一種特殊的數(shù)據(jù)類型。實際上error就像RESP Simple String一樣,但第一個字符串是"-"而不是加號。在RESP中 Simple Strings和Errors兩者的真正區(qū)別在于errors被客戶端作為異常,構(gòu)成Error類型的字符串就是字符串本身?;靖袷绞牵?/p>

"-Error message\r\n"

Error響應(yīng)只會在有錯誤發(fā)生時才會發(fā)送,例如你操作了錯誤的數(shù)據(jù)類型,或者命令不存在等。當(dāng)收到Error響應(yīng)時,客戶端應(yīng)該拋出一個異常。

以下是error響應(yīng)的例子:

-ERR unknown command 'foobar'-WRONGTYPE Operation against a key holding the wrong kind of value

在"-"到第一個空格或新行間的第一個詞,表示返回的錯誤類型。這只是Redis自己的一種約定,并不是RESP Error 所規(guī)定的格式。

例如,ERR 是通用錯誤,而 WRONGTYPE 是一種更加具體的錯誤,表示客戶端嘗試操作錯誤的數(shù)據(jù)類型。這稱為 Error Prefix (Error前綴),客戶端可從此得知服務(wù)器返回錯誤的類型而不需依賴于那個確切的消息描述,后者會隨時改變。

一個客戶端的實現(xiàn)可能對不同的error返回不同類型的異常,或者向調(diào)用者返回代表錯誤的字符串。然而這種特性并不是必須的,因為這并沒什么卵用,一些精簡的客戶端實現(xiàn)可能簡單的返回一般的錯誤情況,例如 false。

RESP Integers

這種類型就是一個代表整數(shù)的以CRLF結(jié)尾的字符串,并以“:”字節(jié)開頭。例如 ":0\r\n", 或 ":1000\r\n" 都是整數(shù)響應(yīng)。

很多Redis命令返回RESP Integers, 像 INCR, LLEN 和 LASTSAVE。

返回的整數(shù)并沒什么特殊的含義,它就是 INCR 增加后的數(shù)字,LASTSAVE 的UNIX時間戳等。但返回的整數(shù)可以保證是在64位有符號整數(shù)的范圍內(nèi)。

整數(shù)響應(yīng)也被大量的用于表示true或false。例如EXISTS和 SISMEMBER 等命令會返回1表示true, 0表示false。

以下命令會返回一個整數(shù): SETNX, DEL, EXISTS, INCR, INCRBY, DECR, DECRBY, DBSIZE, LASTSAVE, RENAMENX, MOVE, LLEN, SADD, SREM, SISMEMBER, SCARD。

RESP Bulk Strings

Bulk Strings 用于表示一個二進(jìn)制安全的字符串,最大長度為512M。

Bulk Strings 的編碼格式如下:

“$” 后跟字符串字節(jié)數(shù)(prefix length),以CRLF結(jié)束實際的字符串CRLF結(jié)束

所以字符串"foobar" 被編碼成:

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

空字符串:

"$0\r\n\r\n"

RESP Bulk String 也可以用一種代表Null值的特殊格式來表示不存在的值。這種特殊格式的長度值為-1, 并且沒數(shù)據(jù),所以Null表示為:

"$-1\r\n"

這稱為 Null Bulk String。

當(dāng)服務(wù)器返回Null Bulk String時,客戶端API不應(yīng)該返回空串,而是nil 對象。例如Ruby庫應(yīng)該返回 'nil' 而 C 庫應(yīng)該返回 NULL (或在返回的對象設(shè)置特殊的標(biāo)記),等等。

RESP Arrays

客戶端用RESP Arrays向Redis服務(wù)器發(fā)送命令。同樣某些Redis命令要返回一個元素集合時也使用RESP Arrays作為返回的類型。一個例子是LRANGE 命令返回一個元素列表。

RESP Arrays使用以下格式發(fā)送:

“*” 為第一個字節(jié),后跟數(shù)組的元素個數(shù),然后CRLF。然后是數(shù)組中的每一個RESP類型表示的元素。

例如一個空數(shù)組表示為:

"*0\r\n"

而有兩個RESP Bulk Strings "foo" 和 "bar" 的數(shù)組編碼為:

"*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n"

正如你所見,在數(shù)組前面的 *<count>CRLF 后,數(shù)組中的其他的數(shù)據(jù)類型一個接一個的連接在一起。例如一個有三個整數(shù)的數(shù)組編碼如下:

"*3\r\n:1\r\n:2\r\n:3\r\n"

數(shù)組可以包含混合類型,它不要求所有的元素都是相同的類型。例如,一個有4個interges和1個bulk string的數(shù)組可以編碼為:

*5\r\n
:1\r\n
:2\r\n
:3\r\n
:4\r\n
$6\r\n
foobar\r\n

(為清晰起見響應(yīng)被分為多行)。

服務(wù)器發(fā)送的第一行 *5\r\n 表示后跟有5個響應(yīng),然后每個代表元素的響應(yīng)被發(fā)送。

Null 數(shù)組的概念同樣存在,它是Null值的替代方式 (通常使用Null Bulk String,但由于歷史原因我們有兩種格式)。

例如當(dāng)BLPOP命令超時,它返回一個長度為-1的Null 數(shù)組,如下所示:

"*-1\r\n"

在服務(wù)端返回Null數(shù)組時,客戶端庫API應(yīng)該返回null對象而不是空數(shù)組。區(qū)分返回空的列表與其他的情況(如BLPOP命令超時的情況)是有必要的。

RESP允許數(shù)組的數(shù)組。例如一個含兩個數(shù)組的數(shù)組編碼如下:

*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協(xié)議

盡管Redis協(xié)議非??勺x并且容易實現(xiàn),它卻可以兼得二進(jìn)制協(xié)議的高效。

RESP使用長度前綴來傳輸bulk 數(shù)據(jù),所以不需要像JSON一樣掃描數(shù)據(jù)負(fù)載中的特殊符號,或者用引號括住數(shù)據(jù)負(fù)載。

Bulk和Multi Bulk長度的處理可以一次處理一個字符,同時可以掃描CR字符,像如下的C代碼:

#include <stdio.h>

int 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;
}

當(dāng)?shù)谝粋€CR被識別后,后面的LF可以忽略不處理。然后bulk數(shù)據(jù)可以一次讀取而不需要分析 數(shù)據(jù)負(fù)載。最后剩下的CR和LF字符串可以丟棄不處理。

與二進(jìn)制協(xié)議比較性能時,Redis協(xié)議在大部分的高級語言實現(xiàn)起來足夠簡單,減少了客戶端軟件的bug數(shù)量。

注:

1. 協(xié)議中的CR和LF相當(dāng)于分割符,命令間存在多個CRLF不應(yīng)影響后續(xù)解析,應(yīng)為多個CRLF應(yīng)被忽略掉。例如:

$> (printf "PING\r\nPING\r\nPING\r\n\r\n\rPING\r\n"; sleep 1) | nc localhost 6379
+PONG
+PONG
+PONG
+PONG

2. 對比一下memcached的協(xié)議,redis的協(xié)議確實設(shè)計得比較精簡:

(1) 一致的請求形式。redis的請求都是以 Bluk String 數(shù)組發(fā)送,不同命令只是數(shù)組的元素個數(shù)不同,所有命令的處理可以先讀取完整個數(shù)組再根據(jù)不同命令解析數(shù)組的參數(shù);而不是像mc協(xié)議一樣,不同請求的命令格式不同,那么在讀取網(wǎng)絡(luò)字節(jié)流的過程中就要對不同命令做不同的處理,增加了協(xié)議解析的難度。

(2) 長度前綴是高效解析協(xié)議的關(guān)鍵。字段長度信息并不是二進(jìn)制協(xié)議的專利,文本協(xié)議也可以有。

以上是redis協(xié)議指的是什么的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對大家有幫助,更多相關(guān)知識,歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI