Redis 協議介紹

jopen 12年前發布 | 39K 次閱讀 Redis NoSQL數據庫

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

  • 容易實現
  • 機器解析要快
  • 容易被人理解
  • </ul>

    網絡層

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

    請求

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

    新的統一請求協議

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

    * CR LF
    $ CR LF CR LF
    ...
    $ CR LF 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 回復合在一起,并且有一個字符串前綴*\r\n其中是后面參數(Bulk回復)的數量。

    回復

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

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

      狀態回復

      一個狀態回復(或者:單行回復)的格式是以「+」開頭,以「\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命令幾乎是一樣的,但是最后一個參數為了能夠接受二進制安全的內容,所以需要以特殊的方式進行處理。
      • </ul>

        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,所以你需要參考這個來發送命令。強烈推薦使用新的統一請求協議來替代舊的協議。

        原文:Protocol specification

        來自:http://weizhifeng.net/redis-protocol.html

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!