Redis學習筆記(十) 客戶端

Redis服務器是典型的一對多服務器程序:一個服務器能夠與多個客戶端創建網絡鏈接,每一個客戶端能夠向服務器發送命令請求,而服務器則接收並處理客戶端發送的命令請求,並向客戶端返回命令回覆。redis

經過使用由I/O多路複用技術實現的文件事件處理器,Redis服務器使用單線程單進程的方式處理命令請求,並於多個客戶端進行網絡通訊。數組

每一個與服務器進行鏈接的客戶端,服務端都爲這些客戶端創建相應的redisClient結構(客戶端狀態),保存客戶端當前的狀態信息,以及執行相關功能時須要用到的數據結構。安全

Redis服務器狀態結構的clients屬性是一個鏈表,這個鏈表保存了全部與服務器鏈接的客戶端的狀態結構,對客戶端執行批量操做,或者查找某個指定的客戶端,均可以經過遍歷clients鏈完成。服務器

struct redisServer{
//一個鏈表,保存了全部客戶端狀態
list *clients;
}

一、客戶端狀態的fd屬性記錄了客戶端正在使用的套接字描述符網絡

typedef struct redisClient{
int fd;
} redisClient;

根據客戶端的類型不一樣fd的屬性值能夠是-1,或者是大於-1的整數:僞客戶端fd屬性爲-1;普通客戶端的fd屬性值爲大於-1的整數。數據結構

二、默認狀況下一個鏈接到服務器的客戶端是沒有名稱的, 可使用Client setname 命令爲客戶端設置一個名稱。函數

三、客戶端的標誌屬性flags記錄了客戶端角色(role),以及客戶端狀態學習

typedef struct redisClient{
int flag;
} redisClient;

在主從服務器進行復制操做時,主服務器會成爲從服務器的客戶端,而從服務器也會成爲主服務器的客戶端。lua

 

REDIS_MASTER 客戶端是一個主服務器spa

REDIS_BLOCKED 客戶端正在被列表命令阻塞

REDIS_MULTI | REDIS_DIRTY_CAS 客戶端正在執行事務,但事務的安全性已經被破壞

REDIS_SLAVE | REDOS_PRE_PSYNC 客戶端是一個從服務器,而且版本低於REDIS2.8

REDIS_LUA_CLIENT | REDIS_FORCE_AOF | REDIS_FORCE_REPL 這是專門執行Lua腳本包含的redis命令的僞客戶端 ,它強制服務器將當前執行的命令寫入到AOF文件,並複製給從服務器。

四、客戶端狀態的輸入緩衝區用戶保存客戶端發送的命令請求:

typedef struct redisClient {
sds querybuf;
} redisClient;

五、在服務器將客戶端發送的命令請求保存在客戶端狀態的querybuf屬性後,服務器將對命令請求的內容進行分析,並將得出的命令參數以及命令參數的個數分別保存到客戶端狀態的argv屬性和argc屬性

typedef struct redisClient{
robj **argv;
int argc;
} redisClient;

argv屬性是一個數組,數組的每一個項都是一個字符串隊形,其中avgv[0]是要執行的命令,其以後的其餘項都是傳給命令的參數。

六、當服務器從協議內容中分析並得出argv屬性和argc屬性的值以後,服務器將根據項argv[0]的值,在命令表中查找命令所對應的實現函數。

命令表是一個字典表,字典的鍵是一個SDS結構,保存了命令的名字,字典值是命令的名字,字典值是命令所對應的redisCommand結構,這個結構保存了命令的實現函數、命令的標誌、命令應該給定的參數個數、命令的總執行次數和總耗時長等統計信息。

當程序在命令表中成功找到argv[0]所對應的redisCommand結構時,它會將客戶端狀態的cmd指針指向這個結構:

typedef struct redisClient{
struct redisCommand *cmd;
} redisClient;

以後,服務器就可使用cmd屬性所指向的redisCommand結構,以及argv、argc屬性中保存的命令參數信息,調用命令實現函數,執行客戶端指定的命令。

七、執行命令所得的命令回覆會被保存在客戶端狀態的輸出緩衝區裏面,每一個客戶端有兩個輸出緩衝區能夠用,一個緩衝區的大小是固定的,一個大小是可變的。

固定大小的緩衝區用於保存那些長度比較小的回覆,可變大小的緩衝區用於保存耐餓長度比較大的回覆。

客戶端的固定大小緩衝區由buf和bufpos兩個屬性組成

typedef struct redisClient{
char buf[REDIS_REPLY_CHUNK_BYTES];//REDIS_REPLY_CHUNK_BYTES 默認16 *1024  也就是說固定緩衝區默認 16k
int bufpos;//記錄已使用的字節數量
} redisClient;

八、身份認證

客戶端狀態的authenticated屬性用於記錄客戶端是否經過了身份驗證:

typedef struct redisClient{
int authenticated;
} redisClient;

authenticated屬性僅在服務器啓用了身份驗證功能的時候使用,若是服務器沒有啓用的話,即便爲0也不會拒絕客戶端的命令請求。

九、時間

typedef struct redisClient{
time_t ctime;//建立客戶端的時間 鏈接服務器時長(秒)
time_t lastinteraction;//最後一次與服務器互動時間,計算客戶端空轉時間
//記錄緩衝區第一次到達軟性限制的時間
time_t obuf_soft_limit_reached_time;
} redisClient;

若是客戶端是經過網絡鏈接於服務器進行鏈接的普通客戶端,那麼客戶端使用connect函數鏈接到服務器時,服務器就會調用鏈接事件處理器,爲客戶端建立相應的客戶端狀態,並將這個新的客戶端狀態添加到服務器狀態結構clients鏈表的末尾。

普通客戶端能夠由於多種緣由而被關閉:

客戶端進程退出或者被殺死,那麼客戶端與服務端的網絡鏈接被關閉。

若是客戶端向服務端發送了帶有不符合協議的命令請求,那麼這個客戶端也會被關閉。

若是客戶端成爲了CLIENT KILL命令的目標,那麼它也會被關閉。

若是服務端設置了timeout配置項,那麼客戶端的空轉事件超過timeout現象設置的值時,客戶端被關閉。

若是客戶端發送的命令請求的大小超過了輸入緩衝區的限制大小(默認1G),那麼客戶端會被服務器關閉。

若是要發送給客戶端的命令回覆的大小超過了輸出緩衝區的限制大小,那麼這個客戶端會被服務器關閉。

 

服務器使用兩種模式來限制客戶端輸出緩衝區的大小:

一、硬性限制,若是輸出緩衝區的大小超過了硬性限制所設置的大小,那麼服務器當即關閉客戶端。

二、軟性限制,若是輸出緩衝區的大小超過了軟性限制設置的大小,但沒有超過硬性設置的大小,obuf_soft_limit_reached_time屬性記錄下客戶端達到軟性限制的起始事件,以後服務器會繼續監視客戶端,若是輸出緩衝區的大小一直超出軟性限制,而且持續時間超過服務器設置的時長,那麼服務器將關閉客戶端。

服務端會在初始化時建立負責執行Lua腳本中包含redis命令的僞客戶端,並將這個僞客戶端關聯在服務器狀態結構的lua_client屬性中:

struct redisServer{
redisClient *lua_client;
}

lua_client 僞客戶端在服務器運行的整個聲明週期中會一直存在,只有服務器關閉時,這個客戶端纔會關閉。

服務器在載入AOF文件時,會建立用於執行AOF文件的Redis命令的僞客戶端,並在載入完成以後,關閉僞客戶端。

 


 

天天學一點,總會有收穫。

 

說明:尊重做者知識產權,文中內容參考《Redis設計與實現》,僅在此作學習與你們分享。


相關文章
相關標籤/搜索