RESP 協議簡介
Redis 的客戶端和服務端之間在 TCP 協議的上層采用一種獨立名為 RESP(REdis Serialization Protocol) 協議作為進行通訊的標準方式,
Redis 協議在以下幾點之間做出了折衷:
- 簡單的實作
- 快速地被計算機決議
- 簡單得可以能被人工決議
新的統一協議已在Redis 1.2中引入,但是在Redis 2.0中,這就成為了與Redis服務器通訊的標準方式,在這個統一協議里,發送給Redis服務端的所有引數都是二進制安全的,Redis用不同的回復型別回復命令,它可以從服務器發送的第一個位元組開始校驗回復型別:
- 單行回復(單行字串回復),回復的第一個位元組將是“+”
- 錯誤訊息(單行字串回復的另外展示形式),回復的第一個位元組將是“-”
- 整型回復(正整形數字回復),回復的第一個位元組將是“:”
- 批量回復(多行字串回復),回復的第一個位元組將是“$”
- 多個批量回復(陣列回復),回復的第一個位元組將是“*”
傳輸層及網路層
傳輸層仍然是底層 TCP 傳輸,Redis在TCP埠6379上監聽到來的連接,客戶端連接到來時,Redis服務器為此創建一個TCP連接,在客戶端與服務器端之間傳輸的每個Redis命令或者資料都以\r\n結尾,Redis接收由不同引陣列成的命令,一旦收到命令,將會立刻被處理,并回復給客戶端,
關于校驗回復型別
單行回復(單行字串回復):"+"
狀態回復(或者單行回復)以“+”開始以“\r\n”結尾的單行字串形式,例如:
> set name leeprince
+OK\r\n # 服務端實際回傳
---
OK # redis-cli 客戶端顯示
錯誤訊息(單行字串回復的另外展示形式):"-"
錯誤回復發送類似于狀態回復,唯一的不同是第一個位元組用“-”代替“+”,
錯誤回復僅僅在一些意料之外的事情發生時發送,例如:如果你試圖執行一個操作來應付錯誤的資料型別,或者如果命令不存在等等,所以當收到一個錯誤回復時,客戶端將會出現一個例外,例如:
> leeprince
-(error) ERR unknown command `leeprince`, with args beginning with:\r\n # 服務端實際回傳
---
(error) ERR unknown command `leeprince`, with args beginning with: # redis-cli 客戶端顯示
整型回復(正整形數字回復):":"
這種回復型別只是用CRLF結尾字串來表示整型,用一個位元組的“:”作為前綴,例如:“:0\r\n”,或者“:1000\r\n”是整型回復,
像INCR或者LASTAVE命令用整型回復作為實際回復值,此時對于回傳的整型沒有特殊的意思,它僅僅是為INCR、LASTSAVE的UNIX時間等增加數值,
一些命令像EXISTS將為true回傳1,為false回傳0,
其它命令像SADD、SREM和SETNX如果操作實際完成了的話將回傳1,否則回傳0,例如:
>rpush intkey intvalue01 intvalue02 intvalue03
:3\r\n # 服務端實際回傳
---
(integer) 3 # redis-cli 客戶端顯示
以下命令都是回復一個整型:
SETNX、DEL、EXISTS、INCR、INCRBY、DECR、DECRBY、DBSIZE、LASTSAVE、RENAMENX、MOVE、LLEN、SADD、SREM、SISMEMBER、SCARD,
批量回復(多行字串回復):”$“
批量回復被服務器用于回傳一個單二進制安全字串,服務器發送第一行回復,該行以“$”開始后面跟隨實際要發送的位元組數,隨后是CRLF,然后發送實際資料,隨后是2個位元組的額外資料用于最后的CRLF,例如:
>get bulkkey
$9\r\nbulkvalue\r\n # 服務端實際回傳
---
"bulkvalue" # redis-cli 客戶端顯示
如果請求的值不存在,批量回復將使用特殊的值-1來作為資料長度,例如:
>get bulkkey_
$-1 # 服務端實際回傳
---
(nil) # redis-cli 客戶端顯示
多個批量回復(陣列回復):”*“
像命令LRNGE需要回傳多個值(串列的每個元素是一個值,而LRANGE需要回傳多于一個單元素),使用多批量寫是有技巧的,用一個初始行作為前綴來指示多少個批量寫緊隨其后,批量回復的第一個位元組總是*,例如:
127.0.0.1:6379> rpush arraykey a01 a0101
(integer) 2 # redis-cli 客戶端顯示
127.0.0.1:6379> lrange arraykey 0 -1
# 服務端實際回傳
*2\r\n$3\r\na01$5\r\na0101\r\n
---
# redis-cli 客戶端顯示
1) "a01"
2) "a0101"
正如您可以看到的多批量回復是以完全相同的格式使用Redis統一協議將命令發送給服務器,
服務器發送的第一行是*4\r\n,用于指定緊隨著4個批量回復,然后傳送每個批量寫,
如果指定的鍵不存在,則該鍵被認為是持有一個空的串列,且數值0被當作多批量計數值來發送,例如:
127.0.0.1:6379> LRANGE nokey 0 1
# 服務端實際回傳
*0
---
# redis-cli 客戶端顯示
(empty list or set)
當BLPOP命令超時時,它回傳nil多批量回復,這種型別多批量回復的計數器是-1,且值被當作nil來解釋,例如:
127.0.0.1:6379> BLPOP nokey 1
# 服務端實際回傳
*-1
---
# redis-cli 客戶端顯示
(nil)
(1.09s)
當這種情況發生時,客戶端庫API將回傳空nil物件,且不是一個空串列,這必須有別于空串列和錯誤條件(例如:BLPOP命令的超時條件),
多命令和管道(pipelining)
客戶端能使用同樣條件為了發出多個命令,管道用于支持多命令能夠被客戶端用單寫操作來發送,它不需要為了發送下一條命令而讀取服務器的回復,所有回復都能在最后被讀出,
通常Redis服務器和客戶端擁有非常快速的連接,所以在客戶端的實作中支持這個特性不是那么重要,如果一個應用需要在短時間內發出大量的命令,管道仍然會非常快,
管道(Pipelining) VS 腳本(Scripting)
大量 pipeline 應用場景可通過 Redis 腳本(Redis 版本 >= 2.6)得到更高效的處理,后者在服務器端執行大量作業,腳本的一大優勢是可通過最小的延遲讀寫資料,讓讀、計算、寫等操作變得非常快(pipeline 在這種情況下不能使用,因為客戶端在寫命令前需要讀命令回傳的結果),
應用程式有時可能在 pipeline 中發送 EVAL 或 EVALSHA 命令,Redis 通過 SCRIPT LOAD 命令(保證 EVALSHA 成功被呼叫)明確支持這種情況,
Redis 大量資料插入
pipe mode的作業原理是什么?
難點是保證redis-cli在pipe mode模式下執行和netcat一樣快的同時,如何能理解服務器發送的最后一個回復,
這是通過以下方式獲得:
redis-cli –pipe試著盡可能快的發送資料到服務器,
讀取資料的同時,決議它,
一旦沒有更多的資料輸入,它就會發送一個特殊的ECHO命令,后面跟著20個隨機的字符,我們相信可以通過匹配回復相同的20個字符是同一個命令的行為,
一旦這個特殊命令發出,收到的答復就開始匹配這20個字符,當匹配時,就可以成功退出了,
同時,在分析回復的時候,我們會采用計數器的方法計數,以便在最后能夠告訴我們大量插入資料的資料量,
對PHP后端技術,對PHP架構技術感興趣的朋友,我的官方群1023755567點擊此處,一起學習,相互討論,
群內已經有管理將知識體系整理好(原始碼,學習視頻等資料),歡迎加群免費領取,

PHP進階學習思維導圖、面試;檔案、視瞥澩免費獲取
參考
http://www.redis.cn/topics/protocol.html
http://www.redis.cn/topics/pipelining.html
http://www.redis.cn/topics/mass-insert.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/368.html
標籤:PHP
