淺談Redis通信協議

Redis客戶端和服務器端使用的通信協議叫做RESP(Redis Serialization Protocol)。它是特意爲Redis設計的,同時也可以用於其他軟件工程。

RESP在以下事項之間進行妥協:

  • 實現簡單

  • 快速解析

  • 可讀性強

RESP可以序列化多種不同的數據類型,比如:整型、字符串、數組。錯誤是一種特定的類型。Redis客戶端把參數用數組來表示。回覆的是一種特殊的數據格式。

RESP是二進制安全的,它不需要處理從一個進程到另一個進程的批量數據,因爲採用的是前綴長度來傳輸批量數據。

注意:這裏的協議只適用用與客戶端-服務器通信。Redis集羣使用的是不同的協議

一般情況下,RESP是一種簡單的請求-響應式協議。二般情況是:

  • Redis支持管道,所以有可能一次發送多個命令,然後一起響應

  • 如果Redis客戶端訂閱了Pub/Sub頻道,那麼協議就會變成一種推送協議,當服務器接收到新的數據時會自動推送給客戶端

RESP協議支持的數據類型有:Simple Strings,Errors,Integers,Bulk Strings和Arrays。它的使用方法有:

  • 客戶端以Bulk Strings數組的形式發送命令

  • 服務器端返回的結果是協議支持的類型之一

RESP協議中,上述類型是通過首個字節區分的:

  • +代表簡單字符串(Simple Strings)

  • -代表錯誤類型(Errors)

  • :代表整型(Integers)

  • $代表多行字符串(Bulk Strings)

  • *代表數組(Arrays)

此外,每一部分結束時,Redis統一使用“\r\n”表示結束。

看到這裏你是否有疑問呢?爲什麼沒有表示null的方法呢?彆着急我們一會就會解釋。

RESP簡單字符串

簡單字符串中不允許出現\r\n,只能有一行。它用於以最小開銷傳輸非二進制安全字符串,例如回覆的OK

1"+OK\r\n"

如果要發送二進制安全的字符串,應該使用多行字符串。

RESP錯誤

RESP有特定的錯誤類型,它與簡單字符串類似,只不過是把開頭的+換成了-,而兩者之間真正的區別是客戶端將錯誤視爲異常,而錯誤中的字符串只是表示錯誤信息。

1"-Error message\r\n"

當客戶端收到錯誤信息時,通常會拋出一個異常。我們來看一些例子:

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

從第一個字符“-”之後,到第一個空格或新的一行,這之間的字符串表示錯誤類型。這只是Redis的一種約定,並不是RESP的錯誤格式。

例如ERR是普通錯誤,而WRONGTYPE表示客戶端試圖對錯誤的數據類型執行操作。

RESP整型

整型只是以\r\n結尾,以:開頭的純整數的字符串。

1:1000\r\n

很多Redis命令都會返回整型,例如INCR、LLEN和LASTSAVE。

返回的整數需要在64位有符號整數範圍內,同時也可以用於表示真或假。

RESP多行字符串

多行字符串是二進制安全的,最大長度是512MB。

多行字符串的編碼方式如下:

  • $+數字開頭,以\r\n結束

  • 數據都是字符串

  • 結尾是\r\n

所以“foobar”應該編碼爲

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

空字符串表示爲:

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

多行字符串也可以用來null

1"$-1\r\n"

當服務器返回Null多行字符串時,正常客戶端是不應該返回空字符串的,而是應該返回nil對象。

RESP數組

客戶端向服務器端發送命令時使用的就是RESP數組。類似的,某些命令返回的元素集合也是RESP數組的類型。

RESP數組遵循以下規則:

  • 第一個字符是*,後面跟的十進制數字是數組元素的數量,然後跟着\r\n

  • 每個元素都是RESP類型的

空數組表示爲:

1"*0\r\n"

數組中的元素可以是不同類型的:

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

第一行的*5\r\n表示數組有5個元素,後面每行是一個元素。

RESP也有NULL數組的表示方法,這是NULL的另一種表示方法,通常用多行字符串的NULL來表示,不過由於歷史原因,就保留了兩種形式。

當BLPOP命令超時時,就會返回NULL數組

1"*-1\r\n"

當服務器返回NULL數組時,客戶端應該返回null對象而不是空數組。

數組中的NULL

數組中的元素可以是NULL,通常表示數組中某個元素缺失,而不是空字符串:

1*3\r\n
2$3\r\n
3foo\r\n
4$-1\r\n
5$3\r\n
6bar\r\n

其中第二個元素時NULL,客戶端的返回結果應該是:

1["foo",nil,"bar"]
小結

到此我們已經瞭解了RESP協議,RESP中雖然有大量的冗餘\r\n,但是仍然有很多開源項目使用。

往期精彩回顧



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章