Redis協議規範(譯文)

原文地址: haifeiWu的博客
博客地址:www.hchstudio.cn
歡迎轉載,轉載請註明做者及出處,謝謝!redis

Redis客戶端使用名爲RESP(Redis序列化協議)的協議與Redis服務器進行通訊。 雖然該協議是專爲Redis設計的,但它能夠用於其餘CS軟件項目的通信協議。數組

RESP是如下幾方面的考慮:安全

  • 易於實現
  • 快速解析
  • 可讀性高

RESP能夠序列化不一樣的數據類型,如整型,字符串,數組。 還有一種特定的錯誤類型。 請求將要執行的命令做爲字符串數組從Redis客戶端發送到Redis服務器。Redis使用特定數據類型的命令進行回覆。bash

RESP是二進制安全的,不須要處理從一個進程傳輸到另外一個進程的批量數據,由於它使用前綴長度來傳輸批量數據。服務器

注意: 此處概述的協議僅用於客戶端 - 服務器通訊。 Redis Cluster使用不一樣的二進制協議,以便在節點之間交換消息。網絡

網絡層

客戶端鏈接到Redis服務器,是建立TCP鏈接到端口6379。 雖然RESP在技術上是非TCP特定的,但在Redis的上下文中,協議僅用於TCP鏈接(或相似的面向流的鏈接,如Unix套接字)。
ui

請求 - 響應模型

Redis接受由不一樣參數組成的命令。 收到命令後,將對其進行處理並將回覆發送回客戶端。 這是最簡單的模型,但有兩個例外:編碼

  • Redis支持流水線操做(本文檔稍後介紹)。 所以,客戶端能夠一次發送多個命令,並等待稍後的回覆。
  • 當Redis客戶端處於 Pub/Sub 時,協議會更改語義併成爲推送協議,即客戶端再也不須要發送命令,由於服務器會在它們接收到命令時發自動向客戶端發送新消息。

排除上述兩個例外,Redis協議是一個簡單的請求 - 響應協議。
spa

RESP 協議描述

RESP協議在Redis 1.2中引入,但它成爲與Redis 2.0中的Redis服務器通訊的標準方式。 這是每個Redis客戶端中應該實現的協議。翻譯

RESP其實是一個支持如下數據類型的序列化協議:單行字符串,錯誤信息,整型,多行字符串和數組。 RESP在Redis中用做請求 - 響應協議的方式以下:

  • 客戶端將命令做爲字符串數組發送到Redis服務器。
  • 服務器根據命令實現回覆一種RESP類型數據。

在 RESP 中, 一些數據的類型經過它的第一個字節進行判斷:

  • 單行回覆:回覆的第一個字節是 "+"

  • 錯誤信息:回覆的第一個字節是 "-"

  • 整形數字:回覆的第一個字節是 ":"

  • 多行字符串:回覆的第一個字節是 "$"

  • 數組:回覆的第一個字節是 "*"

此外,RESP可以使用稍後指定的Bulk Strings或Array的特殊變體來表示Null值。 在RESP中,協議的不一樣部分始終以「\ r \ n」(CRLF)結束。

RESP 單行字符串(簡單字符串)

簡單字符串按如下方式編碼:加號字符,後跟不能包含CR或LF字符的字符串(不容許換行),由CRLF終止(即「\ r \ n」)。
Simple Strings用於以最小的開銷傳輸非二進制安全字符串。 例如,許多Redis命令成功回覆時只有「OK」,由於RESP 單行字符串使用如下5個字節進行編碼:

"+OK\r\n"
複製代碼

爲了發送二進制安全字符串,使用RESP 多行字符串代替。
當Redis使用Simple String回覆時,客戶端庫應該向調用者返回一個字符串,該字符串由「+」以後的第一個字符組成,直到字符串結尾,不包括最終的CRLF字節。

RESP 錯誤信息

RESP具備錯誤的特定數據類型。 實際上錯誤與RESP 單行字符串徹底相同,但第一個字符是減號' - '字符而不是加號。

RESP中單行字符串和錯誤之間的真正區別在於客戶端將錯誤視爲異常,組成錯誤類型的字符串是錯誤消息自己。 基本格式以下:

"-Error message\r\n"
複製代碼

錯誤回覆僅在發生錯誤時發送,例如,若是您嘗試對錯誤的數據類型執行操做,或者命令不存在等等。 收到錯誤回覆時,客戶端應將異常拋出。

如下是錯誤回覆的示例:

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

「 - 」以後的第一個單詞,直到第一個空格或換行符,表示返回的錯誤類型。 這只是Redis使用的約定,不是RESP錯誤格式的一部分。

例如,ERR是通常錯誤,而WRONGTYPE是一個更具體的錯誤,意味着客戶端嘗試對錯誤的數據類型執行操做。 這稱爲錯誤前綴,是一種容許客戶端理解服務器返回的錯誤類型的方法,而不依賴於給定的確切消息,這可能隨時間而變化。

客戶端實現能夠針對不一樣的錯誤返回不一樣類型的異常,或者能夠經過直接將錯誤名稱做爲字符串提供給調用者來提供捕獲錯誤的通用方法。

可是,這樣的功能不該該被認爲是相當重要的,由於它不多有用,而且有限的客戶端實現可能只返回通用的錯誤條件,例如false。

RESP 整型數據

此類型只是一個CRLF終止的字符串,表示一個以「:」字節爲前綴的整數。 例如「:0 \ r \ n」或「:1000 \ r \ n」是整數回覆。 許多Redis命令返回RESP 整型,如INCR,LLEN和LASTSAVE。

返回的整數沒有特殊含義,它只是INCR的增量編號,LASTSAVE的UNIX時間等等。 可是,返回的整數應保證在有符號的64位整數範圍內。

整數回覆也被普遍使用,以便返回真或假。 例如,EXISTS或SISMEMBER之類的命令將返回1表示true,0表示false。

若是實際執行操做,其餘命令(如SADD,SREM和SETNX)將返回1,不然返回0。

如下命令將回復整數回覆:SETNX,DEL,EXISTS,INCR,INCRBY,DECR,DECRBY,DBSIZE,LASTSAVE,RENAMENX,MOVE,LLEN,SADD,SREM,SISMEMBER,SCARD。

RESP 多行字符串

多行字符串用於表示長度最大爲512 MB的單個二進制安全字符串。

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

  • 一個「$」字節後跟組成字符串的字節數(一個前綴長度),由CRLF終止。
  • 字符串數據。
  • 最終的CRLF。

因此字符串「foobar」的編碼以下:

"$6\r\nfoobar\r\n"
複製代碼

當只是一個空字符串時:

"$0\r\n\r\n"
複製代碼

RESP 多行字符串也可用於使用用於表示Null值的特殊格式來表示值的不存在。 在這種特殊格式中,長度爲-1,而且沒有數據,所以Null表示爲:

"$-1\r\n"
複製代碼

當服務器使用Null 多行字符串回覆時,客戶端庫API不該返回空字符串,而應返回nil對象。 例如,Ruby庫應返回'nil',而C庫應返回NULL(或在reply對象中設置特殊標誌),依此類推。

RESP 數組

客戶端使用RESP 數組將命令發送到Redis服務器。 相似地,某些Redis命令將元素集合返回給客戶端使用RESP 數組是回覆類型。 一個例子是LRANGE命令,它返回列表的元素。

RESP數組使用如下格式發送:

  • *字符做爲第一個字節,後跟數組中的元素數做爲十進制數,後跟CRLF。
  • 數組的每一個元素的附加RESP類型。

因此空數組就是如下內容:

"*0\r\n"
複製代碼

那麼兩個RESP批量字符串「foo」和「bar」的數組編碼爲:

"*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n"
複製代碼

正如您在數組前面加上* CRLF部分以後所看到的那樣,組成數組的其餘數據類型將一個接一個地鏈接起來。 例如,三個整數的數組編碼以下:

"*3\r\n:1\r\n:2\r\n:3\r\n"
複製代碼

數組能夠包含混合類型,元素沒必要具備相同的類型。 例如,四個整數和批量字符串的列表能夠編碼以下:

*5\r\n
:1\r\n
:2\r\n
:3\r\n
:4\r\n
$6\r\n
foobar\r\n
複製代碼

服務器發送的第一行是* 5 \ r \ n,以指定將跟隨五個回覆。 而後發送構成多重回復項目的每一個回覆。

Null 數組的概念也存在,而且是指定Null值的替代方法(一般使用Null 多行字符串,但因爲歷史緣由,咱們有兩種格式)。

例如,當BLPOP命令超時時,它返回一個計數爲-1的Null數組,以下例所示:

"*-1\r\n"
複製代碼

當Redis使用Null數組回覆時,客戶端庫API應返回空對象而不是空數組。 這是區分空列表和不一樣條件(例如BLPOP命令的超時條件)所必需的。

RESP中可使用數組中嵌套數組。 例如,兩個數組的數組編碼以下:

*2\r\n
*3\r\n
:1\r\n
:2\r\n
:3\r\n
*2\r\n
+Foo\r\n
-Bar\r\n
複製代碼

第二個元素是Null。 客戶端庫應返回以下內容:

["foo",nil,"bar"]
複製代碼

注意,這不是前面部分中所述的例外,而只是進一步指定協議的示例。

發送命令到 Redis 服務端

既然熟悉RESP序列化格式,那麼編寫Redis客戶端庫的實現將很容易。 咱們能夠進一步講述客戶端和服務器之間的交互如何工做:

  • 客戶端向Redis服務器發送僅由Bulk Strings組成的RESP陣列。
  • Redis服務器回覆發送任何有效RESP數據類型做爲回覆的客戶端。

所以,例如,典型的交互能夠是如下所示。

客戶端發送命令LLEN mylist以獲取存儲在密鑰mylist中的列表長度,服務器回覆一個Integer回覆,以下例所示(C:是客戶端,S:服務器)。

C: *2\r\n
C: $4\r\n
C: LLEN\r\n
C: $6\r\n
C: mylist\r\n
S: :48293\r\n
複製代碼

一般咱們將協議的不一樣部分與換行符分開以簡化,但實際的交互是客戶端發送 * 2 \ r \ n 4 \ r \ nLLEN \ r \ n 6 \ r \ nmylist \ r \ n 總體。

小結

這是樓主第一次嘗試翻譯一篇技術文檔,相對來講技術文檔的英文閱讀起來仍是比較舒服的,相信有了第一次嘗試,以後確定會愈來愈順利。因爲樓主水平有限,文章中不免有紕漏,指望小夥伴的指出,感謝……。

參考連接

相關文章
相關標籤/搜索