參考:《Redis設計與實現》
1、客戶端定義
Redis服務器是典型的一對多服務器程序,通過使用由I/O多路複用技術實現文件事件處理器,Redis服務器使用單進程單線程的方式來處理命令請求,並與多個客戶端進行網絡通信。
對於每個與服務端進行連接的客戶端,服務器都是爲這些客戶端建立對應的redis.h/redisClient結構來保存客戶端當前的狀態信息,以及相關功能需要用到的數據結構。
Redis服務器狀態結構的clients屬性是一個鏈表,保存了與服務器連接的客戶端的狀態結構。數據結構如下:
struct redisServer{
list *clients //一個保存所有客戶端狀態的鏈表
}
假設一個服務端與三個客戶端對接,他的數據結構是這樣的:
2、客戶端屬性
1、套接字描述符、名字、標誌
數據結構標識:
typedef struct redisClient{
int fd;//套接字描述符
robj *name;//名字
int flags; //標識
}
套接字描述符
僞客戶端的套接字描述符字段值爲-1,僞客戶端的處理命令來源於AOF文件或者Lua腳本,而不是網絡。普通客戶端的套接字標識符爲大於-1的整數
名字
默認情況下,連接到服務端的客戶端是沒有名字的,但是可以通過設置name字段讓客戶端的身份更明確。
標誌
客戶端的標誌屬性記錄了客戶端的角色信息
flags屬性可以是單個標誌,也可以是多個標誌的二進制或。
2、命令
命令參數與執行程序對應數據結構
typedef struct redisClient{
robj **argv //字符串數組,用來保存相應的命令內容
int argc //字符串數組的大小
struct redisCommand *cmd //命令所對應的redisCommand結構
}
服務器將客戶端發送的命令請求存儲到客戶端狀態的query_buf屬性之後,服務器會對命令的內容進行分析,將分析的結果保存到 argv和argc屬性上,具體的如果是像set key value
這樣的命令他的存儲如下:
服務器進行命令的解析時,會從argv[0]獲取值並與命令數據字典dict進行匹配,找到對應的命令信息,存儲到cmd屬性。這個屬性包含給定的參數個數、命令的總執行次數,命令的總耗時等統計信息。服務端通過調用cmd這個參數進行命令的執行。
3、緩衝區
輸入緩衝區與輸出緩衝區的結構表示:
typedef struct redisClient{
sds querybuf; //輸入緩衝區
//固定大小輸出緩衝區
char buf[REDIS_REPLY_CHUNK_BYTES]
int bufpos
list *reply; //可變大小輸出緩衝區
}
輸入緩衝區是保存客戶端輸入的命令信息,所以用sds的結構進行存儲,它的大小會根據內容動態的縮小或者擴大,但是最大大小如果超過1GB,服務端就會關閉這個客戶端。
每個客戶端都會有兩個輸出緩衝區,一個緩衝區大小是固定的,一個緩衝區大小是可變的。
固定大小緩衝區,通過buf數組和bufpos,兩個屬性組合,buf數組的大小是固定的,bufpos則記錄了buf數組目前已經使用的字節數量。固定大小緩衝區主要用來保存長度較小的回覆。
當固定大小緩衝區空間使用殆盡或者回復消息過大,則會開始啓用可變長大小的輸出緩衝區,它的數據結構是通過鏈表來連接一個或者多個的字符串對象,具體結構如下:
4、身份驗證
身份驗證的數據結構是:
typedef struct redisClient{
int authenticated;//身份驗證
}
如果該字段的值爲0表示客戶端未通過身份驗證,如果該值爲1表示客戶端通過身份驗證。
5、時間
ctime: 記錄了創建客戶端的時間,這個時間可以用來計算客戶端和服務端已經連接了多少秒
lastinteraction:記錄客戶端和服務端最後一次進行互動的時間,可以用來計算客戶端空轉時長
obuf_soft_limit_reached_time:記錄輸出緩衝區第一次到達軟性限制的時間。
3、客戶端創建與關閉
1、普通客戶端
通過網絡與服務器連接的普通客戶端,在客戶端使用connect函數連接到服務器的時候,服務器就會調用連接事件處理器爲客戶端創建相應的客戶端狀態,將它添加到clients鏈表的末尾。
客戶端被服務端關閉有很多種情況,具體查看原書。
服務器會採用兩種模式來限制客戶端緩衝區大小:
- 硬性限制:如果緩衝區大小超出硬性限制的大小,服務端會主動關閉客戶端
- 軟性限制:如果客戶端沒有超出硬性限制,但是在配置的軟性限制時長中,持續超出軟性限制大小,則服務端會自動關閉客戶端,否則不關閉
具體的設置可查看原書。
2、Lua腳本的僞客戶端
服務器會在初始化時,創建負責執行Lua腳本的中包含Redis命令的僞客戶端,將這個僞客戶端關聯到服務器狀態結構中的lua_client屬性中。
lua_client僞客戶端在服務器運行的整個生命週期都會一直存在,只有服務器被關閉的時候,這個客戶端纔會關閉。
3、AOF的僞客戶端
服務器在載入AOF文件的時候,會創建用於執行AOF文件的Redis命令僞客戶端,並在載入完成之後,關閉這個僞客戶端。