【注】 本文的源代碼分析是基於redis-2.4.3版本的。redis
redisServer主要記錄了server的全局信息,如數據庫,連入的client,支持的全部操做,從配置文件中讀取的配置信息等。數據庫
1數據結構 2架構 3併發 4app 5異步 6socket 7函數 8spa 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
redisClient主要記錄了某個接入客戶端的狀態信息,如客戶端鏈接句柄,操做的數據庫,發送的命令,返回的結果列表等。爲每一個client創建一個這種數據結構,能夠很方便的支持多用戶併發訪問。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
下圖描述了client與redis server的整個交互過程,圖中只描述了代碼關鍵路徑。
(1)首先,從redis.c文件中的main函數開始:
Main函數首先調用:
1 |
|
該函數主要完成如下功能:設定默認的參數值,並讀取配置文件redis.conf,若用戶配置了某個參數,則用該參數值替換默認值。
接下來,調用:
1 |
|
該函數主要對server進行初始化,初始化內容包括:
調用anetTcpServer函數建立socket server做爲redis server,並將該server的句柄加到epoll/kqueue的監聽隊列中。一旦有client接入,便會對該client觸發操做acceptTcpHandler,該操做是調用aeCreateFileEvent註冊的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
【注】aeCreateFileEvent函數用於註冊監聽鏈接事件,即某個client向server發起鏈接或者發出一個命令後,會觸發這個事件;而aeCreateTimeEvent函數用於註冊定時任務serverCron,該函數每隔100 毫秒執行一次,主要進行一些後臺處理,如:記日誌,清除無效key,清除無效連接。
acceptTcpHandler函數會調用acceptCommonHander,而acceptCommonHander又會調用createClient來爲該client建立一個redisClient對象….,最終,redis會根據用戶輸入的命令調用已經寫好的命令執行函數,這些函數已經被寫死,保存到一個全局只讀表中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
用戶輸入get命令,redis最終會調用getCommand函數,用戶輸入set命令,redis最終會調用setCommand函數…..。該表是在initServerConfig()函數中,被加載到一個hash table中的,以便於後面的查找:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
(2)redis執行完用戶的一個命令後,會將結果寫入到redisClient對象中的reply list中,而sendReplyToClient函數會不斷的從該list中數據,異步地發送給client。須要注意的是,sendReplyToClient函數也是經過aeCreateFileEvent註冊的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
上面只是粗略講了一下代碼架構,只算是拋磚引玉了,若是讀者想更進一步瞭解redis代碼架構,最好親自讀一下代碼。整體而言,redis代碼結構很清晰,架構也是比較簡單。