我們都知道在redis客戶端向服務器發送一條命令可以實現數據的增刪改查,但是這條命令的執行過程是怎麼樣的呢?執行命令前需要哪些準備呢?
首先在所有命令執行前,必須要啓動服務器和客戶端:
1、服務器的啓動
2、客戶端地創建
其次,纔是命令的發送、執行和回覆。
服務器的啓動流程
1、初始化狀態結構
首先,redis在啓動服務器時,會先創建一個struct redisServer類型的事例變量server作爲服務器的狀態,併爲結構中的各個屬性設置默認值。
主要執行redis.c/initServerConfig函數完成。主要包括:
- 設置服務器的運行id
- 設置服務器的運行頻率
- 設置默認的文件路徑
- 設置服務器的運行架構
- 設置默認端口號
- 設置默認的RDB持久化條件和AOF持久化條件
- 初始化服務器的LRU時鐘
- 創建命令表
命令表示一個字典,key爲get,set,del等,而值爲一個redisCommond結構,每隔結構記錄了一個redis命令的實現信息。在初始化時,redis只創建了一個命令表數據結構,並沒有創建其他的數據結構。
2、載入配置選項
在給定默認配置信息後,服務器會開始載入用戶給定的配置參數和配置文件,並根據設置對server變量相關屬性就行修改(redis.conf)。
3、初始化服務器的數據結構
包含的數據結構有:
- server.clients鏈表,這個鏈表記錄了所有與服務器相連的客戶端的狀態結構
- server.db數組,數組中包含了服務器中所有的數據庫
- 用於保存頻道訂閱信息的server.pubsub_channels字典
- 用於保存模式訂閱信息的server.pubsub_patterns鏈表
- server.lua 用於執行lua腳本
- server.slowlog 屬性用於慢查詢日誌
之後服務器將調用initServer函數爲以上數據結構分配內存,並設置和關聯初始化值。同時initServer還會執行一些設置操作。
4、還原數據庫狀態
通過載入RDB文件或者AOF文件還原數據庫狀態。
5、執行事件循環
客戶端地創建
通過網絡連接與服務器進行連接,服務器會調用連接事件處理器爲客戶端創建相應的客戶端狀態,並將新的客戶端狀態添加到服務器狀態結構clients鏈表的末尾。
以上是在執行命令前的一些準備工作,下面開始進行命令的發送,執行和回覆的介紹。
主要包括四個步驟:
- 發送命令
- 讀取命令,並執行
- 服務器回覆命令給客戶端
- 客戶端接收服務器的命令回覆,並打印給用戶
發送命令請求
用戶在客戶端輸入一個命令請求,客戶端會將這個命令轉換成協議格式,然後通過連接到服務器的套接字,將協議格式的命令請求發送給服務器。
讀取命令請求
服務器調用命令請求處理器執行:
- 讀取套接字中協議格式的命令請求,並將其保存到客戶端狀態的輸入緩衝區裏面。
- 對輸入緩衝區中的命令請求進行分析,提取出命令參數,以及命令個數,然後分別保存在客戶端狀態的argv屬性和argc屬性中。
- 調用命令執行器,執行指定命令。執行命令時會將客戶端狀態中的argv[0]參數在命令表中查找參數所指定的命令,並將找到的命令保存到客戶端狀態的cmd屬性中
命令實現
服務器已經將要執行的命令保存到了客戶端狀態的cmd屬性中,並將命令的參數和個數保存到了argv和argc屬性中,當服務器要執行命令時,他只要執行以下語句就可以了:
client -->cmd -->proc(client); 即命令的實現函數只需要一個指向客戶端狀態的指針作爲參數即可,被調用的命令實現函數會執行指定的操作,併產生相應的命令回覆,這些回覆會被保存在客戶端狀態的==輸出緩衝區(buf屬性和reply屬性)==之後實現函數還會爲客戶端的套接字關聯命令回覆處理器。
將命令回覆發送給客戶端
當客戶端的套接字變成可寫狀態時,服務器執行命令回覆處理器,將保存在輸出緩衝區中的命令回覆發送給客戶端,
當命令回覆發送完成之後,回覆處理器會情況客戶端狀態的輸出緩衝區。
客戶端接收並打印命令回覆
當客戶端收到協議格式的命令回覆之後,他會將這些回覆轉換成人類可讀的格式,並打印給用戶看。
附:
輸入緩衝區
客戶端的輸入緩衝區用於保存客戶端發送的命令請求,是sds值
typedef struct redisClient{
sds querybuf; //查詢緩衝區
} rediscCient;
sds值,所以輸入緩衝區大小會根據輸入內容動態地縮小或者擴大,但他的最大大小不能超過1GB,否則服務器將關閉這個客戶端。
輸出緩衝區
執行命令所得的命令回覆都會被保存在客戶端狀態的輸出緩衝區裏面,每個客戶端都有兩個輸出緩衝區,一個緩衝區的大小是固定的,另一個緩衝區的大小是可變的。
- 固定大小的緩衝區用於保存哪些長度比較小的回覆,比如OK,簡短的字符串值、整數值、錯誤回覆等。char buf[REDIS_REPLY_CHUNK_BYTES]
- 可變大小的緩衝區用於保存長度比較大的回覆。比如一個非常長的字符串值. bufpos
typedef struct redisClient{
char buf[REDIS_REPLY_CHUNK_BYTES]; //固定大小
int bufpos; //可變大小
}redisClient;
固定大小默認是16*1024 即16KB。
可變大小的緩衝區由replay鏈表和一個或者多個字符串對象組成。通過使用鏈表來連接多個字符串對象,服務器可以爲客戶端保存一個非常長的命令回覆,而不必受到固定大小緩衝區16KB的限制。
但是爲了避免客戶端回覆過大,佔用過多的服務器資源,服務器會時刻檢查客戶端輸出緩衝區大小,並在緩衝區大小超出範圍時,執行相應的限制操作。
硬性限制:如果超過了硬性限制大小,立即關閉客戶端
軟性限制:如果超過了軟性限制大小,還沒有超過硬性限制大小,在一定時間內如果繼續超過了硬性限制,則關閉客戶端,如果在一定時間內沒有超過則不會關閉。
可以通過修改client-output-buffer-limit來設置硬性和軟性限制的值。
以上就是在redis中執行一個命令所要經歷的全過程。