你知道 Redis 服務器接收到一條命令是如何執行的嗎?
本文轉載自微信公眾號「Java極客技術」,作者鴨血粉絲。轉載本文請聯系Java極客技術公眾號。
Hello 大家好,我是阿粉,Redis 作為工作中不可缺少的緩存組件,相信很多小伙伴都會使用到,我們日常使用的時候都是通過代碼或者客戶端去鏈接 Redis 服務器來操作數據的。那么一條簡單的set name ziyou 命令是如何執行的,中間都經歷了哪些過程想必很少會有人去了解。今天阿粉就帶大家看一下一條簡單的set name ziyou 命令是如何執行的。
我們可以看到在執行set name ziyou 這個命令過后,先顯示一個OK 在終端里面。下面我們看下這整個過程都經歷了哪些步驟。
命令的整個執行分為下面幾個步驟,我們先看流程,在仔細分析:
- 客戶端發送命令請求;
- 服務端讀取命令請求;
- 命令執行器進行操作
- 命令執行器查找命令實現函數;
- 命令執行器執行預備操作;
- 命令執行器調用命令的實現函數;
- 命令執行器執行后續工作;
- 服務端將命令回復發送給客戶端;
- 客戶端接收并打印命令回復內容;
客戶端發送命令請求
首先當客戶端和服務端建立好了鏈接過后,當我們輸入命令 set name ziyou 命令請求的時候,客戶端會將這個命令進行協議轉換,然后通過連接將轉換后的協議發送到服務端。
比如當我們輸入命令set name ziyou 的時候,客戶端會將這個原始命令轉換成*3\r\n$3\r\nset\r\n$4\r\nname\r\n$5\r\nziyou,這個協議大家應該比較眼熟,就是 Redis 管道的文件格式。簡單解釋下這個協議的意思,前面的*3 表示這個命令總共有三個參數,其中的$3,$4,$5 表示相應參數的長度。
服務端讀取命令請求
當服務端收到該客戶端的數據時,就會調用命令請求處理器來處理對應的消息。這塊主要涉及到三個操作,第一個是保存命令,也就是會將命名的請求信息讀取出來保存到對應客戶端的輸入緩沖區里面;保存完了過后會對輸入緩沖區里面的內容進行解析,也就是對上面轉換后的協議進行解析,解析出要執行的命令和對應的參數,將參數內容和參數個數保存到客戶端的對應參數里面;第三步是調用命令執行器來執行命令。執行的命令和參數保存在RedisClient 結構的 argv 參數中,如下圖所示,命令分析完成后,第三步才能更好的進行執行操作:
命令執行器
命令執行器查找實現函數
思考一個問題,我們這里 argv[0] 參數中的命令的是進行set 操作,在這里是個 set 字符串,那么 Redis 服務器是如何進行執行的呢?我們可以想到的是需要根據這個字符串找到對應的函數來進行操作,Redis 在內部有個的命令表,是一個字典結果,key就是對應的命令名字,字典的值就是一個個 RedisCommand 結構,記錄了命令的實現信息。
結構如下,簡單來說就是通過 argv[0] 中的命令名稱找到命令表中對應的redisCommand 結構,然后根據 proc 指針找到對應的執行命令。這里說明一下,命令名稱的大小寫沒有任何影響,我們在輸入的時候不用關心命令名稱的大小寫問題。
命令執行器執行預備操作
在 Redis 服務器執行相關命令之前,為了保證命令能夠正確的執行,還需要進行相關的預備處理,部分預操作如下:
- 檢查命令的參數和輸入的參數個數是否一致,不一致則直接返回錯誤;
- 檢查客戶端是否通過身份驗證,未通過身份驗證則只能執行 AUTH 命令進行身份驗證;
- 檢查服務器的內容使用情況,為了保證命令執行成功,可能會需要進行內容回收;
除了上面的功能之外還有很多需要預備執行的動作,而且根據服務器部署的情況不一樣,單機還是集群需要執行的操作還有不同。只有當所有的 預備操作都執行成功過后,才會真正的執行用戶的命令。
由此可見 Redis 的性能是真正的高效,在有這么做操作流程的情況下還能保住命令執行的如此快速,不得不說真的很優秀。
命令執行器調用命令的實現函數
當前面的預備操作都完成過后,命令執行器就會調用對應的實現函數,在我們這里的例子就是調用 setCommand(redisClient *c) 函數進行數據寫入操作,具體的 key 值和 value 值在 redisClient 結構中已經保存了,所以只要傳遞一個指針進去就可以了。setCommand() 命令執行后會返回一個OK\r\n ,這個返回會被保存到客戶端的輸出緩沖區當中,輸出緩沖區的內容后續會被返回到客戶端,給用戶展示出來,如前面的圖片顯示的內容。
命令執行器執行后續工作
當命令執行器調用具體的實現函數過后,服務器還會有相應的一些操作要做,比如如果開啟了慢日志功能,會檢查是否要寫入慢日志;如果開啟了 AOF 則需要將剛剛執行的命令寫入 AOF 的緩沖區中;以及如果有服務器備份或者監聽的時候,會把剛剛執行的命令廣播過去。
服務端將命令回復發送給客戶端
實現函數執行完過后會將執行結果保存到客戶端的輸出緩沖區中,此時服務器的命令回復處理器會將緩沖區中的命令回復發送給客戶端。命令回復處理器發送完數據過后會將客戶端的輸出緩沖區清理,方便后續的命令存入數據,同樣回復的數據也是經過協議轉換的。
客戶端接收并打印命令回復內容
客戶端收到回復數據過后就數據轉換成可讀的形式,輸出到控制臺。這樣就得到了我們第一張圖片的結果。
總結
通過上面所有的過程,我們可以看到,就是一個簡單的set name ziyou 這樣的語句,整個執行的過程也還是很復雜的,Redis 服務器在設計的時候要考慮很多東西,安全,性能等等方面。
引用
《Redis 設計與實現第二版》