Redis 通信協議分析

簡介

Redis本質上是一個Key-Value類型的內存數據庫,很像memcached,整個數據庫通通加載在內存當中進行操做,按期經過異步操做把數據庫數據flush到硬盤上進行保存。Redis的性能很是出色,每秒能夠處理超過 10萬次讀寫操做,是已知性能最快的Key-Value DB。html

Redis的出色之處不只僅是性能,Redis最大的魅力是支持保存多種數據結構,此外單個value的最大限制是1GB,不像 memcached只能保存1MB的數據,所以Redis能夠用來實現不少有用的功能,比方說用他的List來作FIFO雙向鏈表,實現一個輕量級的高性 能消息隊列服務,用他的Set能夠作高性能的tag系統等等。另外Redis也能夠對存入的Key-Value設置expire時間,所以也能夠被看成一 個功能增強版的memcached來用。面試

Redis利用隊列技術將併發訪問變爲串行訪問,消除了傳統數據庫串行控制的開銷。redis


Redis的主要缺點是數據庫容量受到物理內存的限制,不能用做海量數據的高性能讀寫,所以Redis適合的場景主要侷限在較小數據量的高性能操做和運算上。數據庫

 

Redis支持五種數據類型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。數組

 

Redis 通信協議

Redis 協議在如下三個目標之間進行折中:安全

  • 易於實現
  • 能夠高效地被計算機分析(parse)
  • 能夠很容易地被人類讀懂

①協議說明服務器

客戶端和服務器經過 TCP 鏈接來進行數據交互, 服務器默認的端口號爲 6379 。客戶端和服務器發送的命令或數據一概以 \r\n (CRLF)結尾。Redis 服務器接受命令以及命令的參數。服務器會在接到命令以後,對命令進行處理,並將命令的回覆傳送回客戶端。在這個協議中, 全部發送至 Redis 服務器的參數都是二進制安全(binary safe)的。數據結構

②協議模板併發

*<參數數量> CR LF
$<參數 1 的字節數量> CR LF
<參數 1 的數據> CR LF
...
$<參數 N 的字節數量> CR LF
<參數 N 的數據> 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"

稍後咱們會看到, 這種格式除了用做命令請求協議以外, 也用在命令的回覆協議中: 這種只有一個參數的回覆格式被稱爲批量回復(Bulk Reply)

統一協議請求本來是用在回覆協議中, 用於將列表的多個項返回給客戶端的, 這種回覆格式被稱爲多條批量回復(Multi Bulk Reply)

一個多條批量回復以 *<argc>\r\n 爲前綴, 後跟多條不一樣的批量回復, 其中 argc 爲這些批量回復的數量。

②回覆協議

Redis 命令會返回多種不一樣類型的回覆。

經過檢查服務器發回數據的第一個字節, 能夠肯定這個回覆是什麼類型:

  • 狀態回覆(status reply)的第一個字節是 "+"
  • 錯誤回覆(error reply)的第一個字節是 "-"
  • 整數回覆(integer reply)的第一個字節是 ":"
  • 批量回復(bulk reply)的第一個字節是 "$"
  • 多條批量回復(multi bulk reply)的第一個字節是 "*"

服務器使用批量回復來返回二進制安全的字符串,字符串的最大長度爲 512 MB 。

客戶端:GET mykey
服務器:foobar

服務器發送的內容中:

  • 第一字節爲 "$" 符號
  • 接下來跟着的是表示實際回覆長度的數字值
  • 以後跟着一個 CRLF
  • 再後面跟着的是實際回覆數據
  • 最末尾是另外一個 CRLF

對於前面的 GET 命令,服務器實際發送的內容爲:

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

若是被請求的值不存在, 那麼批量回復會將特殊值 -1 用做回覆的長度值, 就像這樣:

客戶端:GET non-existing-key
服務器:$-1

這種回覆稱爲空批量回復(NULL Bulk Reply)。

當請求對象不存在時,客戶端應該返回空對象,而不是空字符串: 好比 Ruby 庫應該返回 nil , 而 C 庫應該返回 NULL (或者在回覆對象中設置一個特殊標誌), 諸如此類。

像 LRANGE 這樣的命令須要返回多個值, 這一目標能夠經過多條批量回復來完成。

多條批量回復是由多個回覆組成的數組, 數組中的每一個元素均可以是任意類型的回覆, 包括多條批量回復自己。

多條批量回復的第一個字節爲 "*" , 後跟一個字符串表示的整數值, 這個值記錄了多條批量回復所包含的回覆數量, 再後面是一個 CRLF 。

客戶端: LRANGE mylist 0 3
服務器: *4
服務器: $3
服務器: foo
服務器: $3
服務器: bar
服務器: $5
服務器: Hello
服務器: $5
服務器: World

在上面的示例中,服務器發送的全部字符串都由 CRLF 結尾。

正如你所見到的那樣, 多條批量回復所使用的格式, 和客戶端發送命令時使用的統一請求協議的格式如出一轍。 它們之間的惟一區別是:

  • 統一請求協議只發送批量回復。
  • 而服務器應答命令時所發送的多條批量回復,則能夠包含任意類型的回覆。

如下例子展現了一個多條批量回復, 回覆中包含四個整數值, 以及一個二進制安全字符串:

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

在回覆的第一行, 服務器發送 *5\r\n , 表示這個多條批量回復包含 5 條回覆, 再後面跟着的則是 5 條回覆的正文。

多條批量回復也能夠是空白的(empty), 就像這樣:

客戶端: LRANGE nokey 0 1
服務器: *0\r\n

無內容的多條批量回復(null multi bulk reply)也是存在的, 好比當 BLPOP 命令的阻塞時間超過最大時限時, 它就返回一個無內容的多條批量回復, 這個回覆的計數值爲 -1 :

客戶端: BLPOP key 1
服務器: *-1\r\n

客戶端庫應該區別對待空白多條回覆和無內容多條回覆: 當 Redis 返回一個無內容多條回覆時, 客戶端庫應該返回一個 null 對象, 而不是一個空數組。

 

參考

redis面試總結

redis用法詳解

相關文章
相關標籤/搜索