Redis中各類操做均可以經過命令來完成,所以理解redis對命令的處理流程會有助於理解redis的整個流程。本文主要對redis的命令處理流程進行詳細分析。 redis
Redis將全部它能支持的命令以及對應的「命令處理函數」之間對應關係存放在數組redisCommandTable[]中,該數組中保存元素的類型爲結構體redisCommand,此中包括命令的名字以及對應處理函數的地址,如: 數組
首先,經過函數dictCreate()建立一個commandTableDictType類型的字典,並將該字典保存在全局變量server的commands成員中。 緩存
而後,調用函數populateCommandTable()將數組redisCommandTable[]中的命令添加到(1)中建立的字典裏,以便後續的命令查詢操做。 安全
本文後續部分將分別描述redis接受客戶端鏈接、客戶端傳遞操做命令、以及redis執行操做命令的整個流程。 服務器
流程一:redis如何接受客戶端的鏈接 網絡
Redis支持網絡域通訊(不一樣機子上的程序間經過tcp/udp鏈接(redis使用tcp)進行通訊)以及UNIX域通訊(即同一臺機子上的不通進程間使用unix域進行通訊),下面的介紹中將主要介紹網絡域通訊,unixt域的通訊過程與之相似,再也不累述。 socket
每一個客戶端經過網絡鏈接到redis時,redis將調用函數createClient()爲該鏈接建立一個客戶端結構體redisClient,以便保存該客戶端的全部信息,該新鏈接即爲業務鏈接,其主要用於客戶端與redis之間的實際數據通訊。Redis在createClient()函數中將爲鏈接設置處理函數readQueryFromClient(),也即業務鏈接上有數據到來時將調用此函數進行處理。 tcp
redis啓動時將調用initServer()函數,在該函數中將設置監聽socket的處理函數,其過程主要有如下三步: 函數
(1)調用函數anetTcpServer建立redis的監聽socket,全部客戶端對redis的網絡鏈接都鏈接到該socket所監聽的端口上。 spa
(2)調用函數aeCreateFileEvent設置監聽socket的處理函數:acceptTcpHandler(),也就是當redis的監聽socket收到數據(有新的鏈接到來)時將調用該函數進行處理。
(3)lacceptTcpHandler()中將首先調用函數anetTcpAccept爲新進來的業務鏈接建立一個業務socket;該業務socket後續將完成客戶端與服務器之間全部的業務數據傳輸;而後經過函數acceptCommonHandler()調用createClient()爲新鏈接建立一個客戶端結構體redisClient.
(4)在函數createClient()中,將調用函數aeCreateFileEvent設置該客戶端的業務數據處理函數readQueryFromClient,即,當該客戶端的業務socket中有數據到來了,則調用readQueryFromClient進行處理。
上述過程將按照如下流程進行處理:
圖一、 redis接受客戶端鏈接的調用過程
由圖1能夠看出,當客戶端有請求數據(即redis的業務數據)到來時,redis中對應該客戶端的業務socket將處於可讀就緒狀態,而後redis將調用函數readQueryFromClient()對到達的業務數據進行處理。
流程二 :redis的命令處理流程
經過流程一客戶端能夠鏈接到redis上,而後客戶端就能夠經過該鏈接向redis發送操做命令,redis接到命令以後執行相應的函數完成具體操做,而後將操做結果發送給客戶端,其具體過程以下所示:
(1)客戶端的請求數據由網絡傳遞到redis的業務socket,redis將調用函數readQueryFromClient()讀取數據到redisClient結構體的接收緩存querybuf中。
(2)readQueryFromClient()將調用processInputBuffer()對該客戶端輸入緩存中的數據進行處理。
(3)函數processInputBuffer()中,將首先解析收到的客戶端數據,此解析過程將經過調用函數processInlineBuffer()或processMultibulkBuffer()完成,此過程將解析出客戶端的命令名稱,命令的參數個數以及具體參數值,redis有其本身定義的通訊協議,只需按照此協議便可完成命令解析,其過程可參考本文最後的「附1. redis命令解析」。
(4)函數processInputBuffer()中,命令解析完成以後將調用函數processCommand()完成命令處理過程。
(5)在函數processCommand()中,將根據命令的名字查找相應的處理函數,命令的名字由前面的命令解析過程肯定,命令查詢操做將經過函數lookupCommand()完成,此函數將查找server的命令字典以快速找到對應的命令執行函數。
(6)在函數processCommand()中,查找到命令執行函數以後,還需調用call()函數來具體執行相應的「命令執行函數」。
上述處理過程可參考下圖2所示:
圖二、 redis命令執行過程
上圖中的數字標號表示同級別的執行先手順序。
----------------------------------------------------------------------------------------------------------------------
附1.redis命令解析
Redis的通訊按照其本身定義的協議進行,按照這種協議可保證命令的二進制安全,其協議規定以下:
l全部命令和數據都已\r\n(即CRLF)結尾;
l命令按照下面的格式進行組織。
例如,有以下數據:
*3\r\n$3\r\nSET\r\n$5\r\nmykey\r\n$7\r\nmyvalue\r\n
便可按照上述方式理解爲該數據的含義:它共有三個參數(即命令中開頭的字符:*3),其中第一個參數的長度是3個字節,其值爲SET;第二個參數的長度爲5,值爲mykey,第三個參數的長度爲7,值爲myvalue,所以這條數據的含義是一條以下的命令:
SETnmykey nmyvalue