1. 程式人生 > 其它 >客戶端 - 《Redis設計與實現》讀書筆記

客戶端 - 《Redis設計與實現》讀書筆記

對於每個與伺服器進行連線的客戶端,伺服器都為這些客戶端建立了相應的src/server.h/client結構(客戶端狀態),這個結構儲存了客戶端當前的狀態資訊,以及執行相關功能時需要用的資料結構

建立客戶端

  • 普通客戶端

    • 建立普通客戶端
      通過網路連線與伺服器進行連線的普通客戶端,那在客戶端使用connect函式連線到伺服器時,伺服器就會呼叫連線應答處理器為客戶端建立相應的客戶端狀態,並將新增到伺服器狀態結構clients連結串列的末尾

      原始碼:c = createClient(conn) => src/networking.c/createClient

    • 導致關閉普通客戶端的原因

      • 客戶端程序退出或者被殺死
      • 傳送了不符合協議格式的命令請求
      • 使用client kill 命令關閉
      • 觸發了timeout配置
      • 客戶端傳送的命令請求大小超過了輸入緩衝區的限制大小(預設為1GB)
      • 服務端傳送的命令回覆大小超過了輸出緩衝區的硬性限制大小或者軟性限制大小
  • Lua指令碼的偽客戶端
    伺服器會在初始化時建立負責執行Lua指令碼中包含的Redis命令的偽客戶端,並將這個偽客戶端關聯在伺服器狀態結構的lua_client屬性

    lua_client偽客戶端在伺服器執行的整個生命週期中會一直存在,只有伺服器被關閉,lua_client偽客戶端才會被關閉

    原始碼:server.lua_client = createClient(NULL) => src/networking.c/createClient

  • AOF檔案的偽客戶端
    伺服器會在載入AOF檔案時,會建立用於執行AOF檔案包含的Redis命令的偽客戶端並載入完成之後,關閉這個偽客戶端

    原始碼:src/aof.c/createAOFClient

客戶端狀態結構

// 客戶端狀態結構
// 客戶端的屬性包含通用屬性 和 特定功能相關的屬性
typedef struct client {
    // 客戶端增量唯一ID
    uint64_t id;            
    // 客戶端連線
    connection *conn;
    // RESP協議版本。可以是2或3
    int resp;               
    // 當前客戶端目標資料庫指標:記錄客戶端當前正在使用的資料庫
    redisDb *db;            
    // 客戶端的名字
    robj *name;             
    // 輸入緩衝區:儲存客戶端傳送的命令請求,不能超過1GB
    sds querybuf;           
    // 已讀取到輸入緩衝區的位置
    size_t qb_pos;          
    // 如果此客戶端被標記為主伺服器,則此輸入緩衝區表示我們從主伺服器接收的複製流中尚未應用的部分
    sds pending_querybuf;   
    // querybuf大小的近期峰值(100ms或以上)
    size_t querybuf_peak;   
    // 命令引數的個數:argv陣列的長度
    int argc;               
    // 命令引數
    robj **argv;            
    // 引數被重寫,原始命令的引數個數
    int original_argc;      
    // 引數被重寫,原始命令的引數
    robj **original_argv;   
    // argv列表中物件的長度總和
    size_t argv_len_sum;    
    // 對應的命令結構
    struct redisCommand *cmd, *lastcmd;  
    // 可變大小的輸出緩衝區:用於儲存長度較大的回覆,比如一個非常長的字串值,一個由很多項組成的列表,一個包含了很多元素的集合等等,
    // reply屬性大小受到client-output-buffer-limit配置的限制
    list *reply;            
    // 建立客戶端的時間:用來計算客戶端與伺服器已經連線了多少秒
    time_t ctime;           
    // 客戶端與伺服器最後一次進行互動的時間(可以是客戶端向伺服器傳送命令請求的時間,也可以是伺服器向客戶端傳送命令回覆的時間)
    // lastinteraction屬性可以用來計算客戶端的空轉時間
    time_t lastinteraction; 
    // 輸出緩衝區第一次到達軟性限制的時間,用於對輸出緩衝區大小超出軟性限制,何時關閉客戶端的引數
    time_t obuf_soft_limit_reached_time;
    // 客戶端的角色標誌和目前所處的狀態,可以是單個標誌,也可以是多個標誌的二進位制或
    uint64_t flags;         
    // 記錄客戶端是否通過了身份驗證:0-未通過 1-已通過(預設值為0)
    // authenticated屬性僅在伺服器 啟用 了身份驗證功能時使用,如果伺服器沒有啟用身份驗證功能的話,那麼即使authenticated屬性的值為0,伺服器也不會拒絕執行客戶端傳送的命令請求
    // 當authenticated屬性的值為0時,除了AUTH命令以外,客戶端傳送的所有其他命令都會被伺服器拒絕執行
    int authenticated;      
    // 固定大小的輸出緩衝區:用於儲存長度較小的回覆,比如ok、簡短的字串值、整數值、錯誤回覆等
    int bufpos; // 記錄了buf陣列目前已使用的位元組數量
    char buf[PROTO_REPLY_CHUNK_BYTES]; // 回覆資料位元組陣列,預設大小為16kb
} client;

索引

Redis 服務端程式實現原理

隻言片語任我說,提筆句句無需忖。落筆不知寄何人,唯有邀友共斟酌。