歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> Redis 協議

Redis 協議

日期:2017/2/27 16:00:32   编辑:Linux教程

Redis協議是從以下幾個方面做的一個折中方案:

  • 容易實現
  • 機器解析要快
  • 容易被人理解

網絡層

客戶端通過創建到6379端口的TCP連接來連接到一個Redis服務器。每個Redis命令或者客戶端和服務器之間傳輸的數據都以\r\n (CRLF)結束。

請求

Redis可以接受由不同參數組成的命令。只要接收到一個命令,這個命令就會被執行,然後一個答復會被返回給客戶端。

新的統一請求協議

新的統一協議是在Redis1.2中引入的,但是在Redis2.0中成為了與Redis服務器交互的標准方式。在統一協議中所有發送到Redis服務器的參數都是二進制安全的。這是總體格式:

*<number of arguments> CR LF
$<number of bytes of argument 1> CR LF
<argument data> CR LF
...
$<number of bytes of argument N> CR LF
<argument data> CR LF

看下這個例子:

*3
$3
SET
$5
mykey
$7
myvalue

這是以上命令以帶引號的字符串展現的樣子,這樣就可以看到這個請求中每個字節的准確內容:

"*3\r\n$3\r\nSET\r\n$5\r\nmykey\r\n$7\r\nmyvalue\r\n"

就像你一會將會看到的,這個格式還會被用在Redis回復中。這個被用於每個參數中的格式$6\r\nmydata\r\n叫做Bulk 回復。Redis實際上使用的統一請求協議會返回內容列表,叫做Multi-bulk回復。它是由N個不同的Bulk 回復合在一起,並且有一個字符串前綴*<argc>\r\n其中<argc>是後面參數(Bulk回復)的數量。

回復

Redis會以不同類型的回復對命令進行響應。可以通過服務器發送的第一個字節來判定回復的類型:

  • 如果是單行回復,那麼第一個字節是「+」
  • 如果回復的內容是錯誤信息,那麼第一個字節是「_」
  • 如果回復的內容是一個整型數字,那麼第一個字節是「:」
  • 如果是bulk回復,那麼第一個字節是「$」
  • 如果是multi-bulk回復,那麼第一個字節是「*」

狀態回復

一個狀態回復(或者:單行回復)的格式是以「+」開頭,以「\r\n」結束的單行字符串。舉個例子:

+OK

客戶端庫要返回「+」後面的所有內容,這個例子裡邊是字符串「OK」。

錯誤回復

錯誤的發送方式和狀態回復很像。唯一的不同是第一個字節用「-」替代了「+」。 錯誤回復只有當一些奇怪的事情發生時才會被發送,例如如果你想要用錯誤的數據類型執行一個操作,或者這個命令不存在等等。所以客戶端庫應該在接收到一個錯誤回復的時候拋出一個異常。

整形回復

這個類型的回復就是一個代表整數以CRLF結束的字符串,並且用一個字節的字符「:」作為前綴。例如「:0\r\n」,或者「:1000\r\n」 都是整形回復。 像INCR或者LASTSAVE命令使用整型回復來返回一個沒有特別含義的整型數字。對於INCR來說返回的是增加後的數字,對於LASTSAVE來說是 一個UNIX時間等等。 像EXISTS這樣的命令會返回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

Bulk回復

Bulk回復被服務器用來返回一個二進制安全的字符串。

C: GET mykey
S: $6\r\nfoobar\r\n

服務器以這種方式來發送數據:第一行是一個字節的內容「$」,之後跟著具體內容的字節數,接下來是CRLF,然後具體數據內容被發送,接下來是額外的兩個字節的CRLF。服務器實際發送的序列是:

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

如果請求的內容不存在,那麼bulk回復將會使用特殊值-1作為數據長度,例如:

C: GET nonexistingkey
S: $-1

當請求對象不存在,客戶端庫API不要返回一個空字符串,應該是一個nil對象。舉個例子一個Ruby庫應該返回「nil」,一個C庫應該返回NULL(或者在回復對象中設置一個特殊標記),等等。

Multi-bulk回復

像LRANGE這類的命令需要返回多個值(列表中的每個元素是一個值,LRANGE需要返回多個元素)。這通過multiple bulk write來實現,其第一行指明後面有多少個bulk write。一個multi bulk回復的第一個字節一直是*。例如:

C: LRANGE mylist 0 3
s: *4
s: $3
s: foo
s: $3
s: bar
s: $5
s: Hello
s: $5
s: World

就像你看到的,multi bulk 回復和使用統一協議發送命令到Redis服務器使用的是同樣的格式。 服務器發送的第一行是*4\r\n,用來指出下面將會有四個bulk回復。然後每個bulk write將會被傳送。 如果指定的key不存在,那麼這個key被認為擁有一個空列表,然後0會做為multi bulk的數量被發送。例如:

C: LRANGE nokey 0 1
S: *0

當BLPOP命令超時,它將返回值為nil的multi bulk回復。這個類型的multi bulk的數量為-1並且應該被解釋為nil值。例如:

C: BLPOP key 1
S: *-1

當這個發生的時候,一個客戶端庫API應該返回一個nil對象而不是一個空列表。區分一個空的列表和一個錯誤條件(比如BLPOP命令的超時條件)是必要的。

Multi-Bulk回復中的Nil元素

一個multi bulk 回復的單個元素可能會存在-1的長度,用來指明這個元素不存在並且不是空字符串。這個可能發生在啟用了GET模式選項的SORT命令,並且指定的key不存在。包含一個空元素的multi bulk回復的例子:

S: *3
S: $3
S: foo
S: $-1
S: $3
S: bar

第二個元素是nil。客戶端庫需要返回如下內容:

["foo",nil,"bar"]

多個命令和管道

一個客戶端可以使用相同的連接來發送多個命令。Redis是支持管道的,所以客戶端可以通過一次寫操作發送多個命令,不需要讀取服務器的回復才能發送下一個命令。所有的回復可以在最後讀取。 通常情況下Redis服務器和客戶端之間會有非常快的連接,所以客戶端支持這個特性不是那麼重要,但如果一個應用需要在很短的時間裡發送大量的命令那麼使用管道將會非常快。

發送命令的舊協議

在統一請求協議之前,Redis使用一個不同的協議來發送命令,這個協議仍然被支持因為通過telnet它很容易手寫。在這個協議中存在兩種命令:

  • inline 命令: 命令很簡單,就是用空格把參數分隔開來的字符串。二進制安全是不可能的。
  • Bulk 命令: bulk命令和inline命令幾乎是一樣的,但是最後一個參數為了能夠接受二進制安全的內容,所以需要以特殊的方式進行處理。

Inline命令

向Redis發送命令最簡單的方法是使用inline命令。以下是一個服務器/客戶端之間使用inline命令進行交互的例子(服務器以S:作為開始,客戶端以C:作為開始)

C: PING
S: +PONG

以下是另一個例子,一個返回整數的inline命令:

C: EXISTS somekey
S: :0

由於「somekey」不存在,所以服務器返回「:0」。 注意EXISTS命令只帶有一個參數。多個參數以空格進行分隔。

Bulk命令

當一些命令以inline命令發送的時候為了使最後一個參數支持二進制安全,需要以一個特殊的格式發送。這些命令將會把最後一個參數作為「字節計數器」,然後大量的數據會被發送(這些數據可以為二進制安全,因為服務器知道有多少字節需要讀取)。 看下面這個例子:

C: SET mykey 6
C: foobar
S: +OK

這個命令的最後一個參數是「6」。這個指明了後面數據,字符串「foobar」的字節數。注意即使這些數據被額外的二個字節大小的CRLF所截斷。 所有bulk命令的准確格式是:把最後一個參數替換成後面數據的字節數,接下來是數據本身和CRLF。為了能夠讓程序員更加清晰的理解,這是上面例子中客 戶端發送的字符串:

"SET mykey 6\r\nfoobar\r\n"

Redis有一個內部的列表,記錄了什麼命令是inline,什麼命令是bulk,所以你需要參考這個來發送命令。強烈推薦使用新的統一請求協議來替代舊的協議。

Copyright © Linux教程網 All Rights Reserved