13 客戶端

Redis服務器是典型的一對多服務器程序:一個服務器可以與多個客戶端建立網(wǎng)絡連接,每個客戶端可以向服務器發(fā)送命令請求父阻,而服務器則接受并處理客戶端發(fā)送的命令請求,并向客戶端返回命令回復。
通過使用由I/O多路復用技術實現(xiàn)的文件事件處理器扯再,Redis服務器使用單線程單進程的方式來處理命令請求离熏,并與多個客戶端進行網(wǎng)絡通信佳谦。
對于每個與服務器進行連接的客戶端,服務器都為這些客戶端建立了相應的redis.h/redisClient結構(客戶端狀態(tài))滋戳,這個結構保存了客戶端當前的狀態(tài)信息钻蔑,以及執(zhí)行相關功能時需要用到的數(shù)據(jù)結構,其中包括

  • 客戶端的套接字描述符
  • 客戶端的名字
  • 客戶端的標志值
  • 指向客戶端正在使用的數(shù)據(jù)庫的指針奸鸯,以及該數(shù)據(jù)庫的號碼
  • 客戶端當前要執(zhí)行的命令咪笑、命令的參數(shù)、命令參數(shù)的個數(shù)娄涩,以及指向命令實現(xiàn)函數(shù)的指針窗怒。
  • 客戶端的輸入緩沖區(qū)和輸出緩沖區(qū)。
  • 客戶端的復制狀態(tài)信息蓄拣,以及進行復制所需要的數(shù)據(jù)結構扬虚。
  • 客戶端執(zhí)行BRPOPBLPOP等列表命令時使用的數(shù)據(jù)結構球恤。
  • 客戶端的事務狀態(tài)辜昵,以及執(zhí)行WATCH命令時用到的數(shù)據(jù)結構。
  • 客戶端執(zhí)行發(fā)布與訂閱功能時用到數(shù)據(jù)結構咽斧。
  • 客戶端的身份驗證標志堪置。
  • 客戶端的創(chuàng)建時間贷洲,客戶端和服務器最后一次通信時間,以及客戶端的輸出緩沖區(qū)大小超出軟性限制(soft limit)的時間

Redis服務器狀態(tài)結構clients屬性是一個鏈表晋柱,這個鏈表保存了所有域服務器連接的客戶端的狀態(tài)結構优构,對客戶端執(zhí)行批量操作,或者查找某個指定的客戶端雁竞,都可以通過遍歷clients鏈表來完成钦椭。

13.1 客戶端屬性

客戶端狀態(tài)包含的屬性可以分為兩類

  • 一類是比較通用的屬性,這些屬性很少與特定功能相關碑诉,無論客戶端執(zhí)行的是什么工作彪腔,他們都要用到這些屬性。
  • 另外一類是和特定功能相關的屬性进栽,比如操作數(shù)據(jù)庫時需要用到的db屬性和dictid屬性德挣,執(zhí)行事務時需要用到的mstate屬性,以及執(zhí)行WATCH命令時需要用到的watched_keys屬性等等快毛。

13.1.1 套接字描述符

客戶端狀態(tài)的fd屬性記錄了客戶端正在使用套接字描述符:

typedef struct redisClient{

    // ...

    int fd;

    // ...
}redisClient;

根據(jù)客戶端類型的不同格嗅,fd屬性的值可以是-1或者是大于-1的整數(shù)

  • 偽客戶端(fake client)的fd屬性的值為-1:偽客戶端處理的命令請求來源于AOF文件或者Lua腳本,而不是網(wǎng)絡唠帝,所以這種客戶端不需要套接字連接屯掖,自然也不需要記錄套接字描述符。目前Redis服務器會在兩個地方用到為客戶端襟衰,一個用于載入AOF文件并還原數(shù)據(jù)庫狀態(tài)贴铜,而另一個則用于執(zhí)行Lua腳本中包含的Redis命令。
  • 普通客戶端的fd屬性的值為大于-1的整數(shù):普通客戶端使用套接字來與服務器進行通信瀑晒,所以服務器會用fd屬性來記錄客戶端套接字的描述符绍坝。因為合法的套接字描述符不能是-1,所以普通客戶端的套接字描述符的值必然是大于-1的整數(shù)苔悦。

13.1.2 名字

在默認情況下轩褐,一個連接到服務器的客戶端是沒有名字的。
使用CLIENT setname命令可以為客戶端設置一個名字间坐,然給客戶端的身份變得更為清晰灾挨。
客戶端的名字記錄在客戶端狀態(tài)的name屬性里面:

typedef struct redisClient{

    // ...

    robj *name;

    // ...
}redisClient;

如果客戶端沒有為自己設置名字,那么響應客戶端狀態(tài)的name屬性指向NULL指針竹宋;相反的劳澄,如果客戶端為自己設置了名字,那么name屬性將指向一個字符串對象蜈七,而該對象就保存著客戶端的名字秒拔。

13.1.3 標志

客戶端的標志屬性flags記錄了客戶端的角色(role),以及客戶端目前所處的狀態(tài):

typedef struct redisClient{

    // ...

    int flags;

    // ...
}redisClient;

flags屬性的值可以是單個標志:

flags=<flag>

也可以是多個標志的二進制或

flags=<flag1>|<flag2>|...

13.1.4 輸入緩存區(qū)

客戶端狀態(tài)的輸入緩沖區(qū)用于保存客戶端發(fā)送的命令請求:

typedef struct redisClient{

    // ...

    sds querybuf;

    // ...
}redisClient;

輸入緩沖區(qū)的大小會根據(jù)輸入內容動態(tài)地縮小或者擴大飒硅,但它的最大大小不能超過1GB砂缩,否者服務器將關閉這個客戶端作谚。

13.1.5 命令與命令參數(shù)

在服務器將客戶端發(fā)送吃的命令請求保存到客戶端狀態(tài)querybuf屬性之后,服務器將對命令請求的內容進行分析庵芭,并將得出的命令參數(shù)以及命令參數(shù)的個數(shù)分別保存到客戶端狀態(tài)argv屬性和argc屬性:

typedef struct redisClient{

    // ...

    robj **argv;

    int argc;

    // ...
}redisClient;

argv屬性是一個數(shù)組妹懒,數(shù)組中的每個項都是一個字符串對象,其中argv[0]是要執(zhí)行的名双吆,而之后的其他項是傳給命令的參數(shù)眨唬。
argc屬性則負責記錄argv數(shù)組的長度。

13.1.6 命令的實現(xiàn)函數(shù)

當服務器從協(xié)議內容中分析并得出argv屬性和argc屬性的值之后好乐,服務器將根據(jù)項argv[0]的值匾竿,在命令表中查找命令所對應的命令實現(xiàn)函數(shù)。
當程序在命令中成功找到argv[0]所對應的redisCommand結構時蔚万,它會將客戶端狀態(tài)的cmd指向這個結構:

typedef struct redisClient{

    // ...

    struct redisCommand *cmd;

    // ...
}redisClient;

之后岭妖,服務器就可以使用cmd屬性所指向的redisCommand結構,以及argv反璃,argc屬性中所保存的命令參數(shù)信息昵慌,調用命令實現(xiàn)函數(shù),執(zhí)行客戶端指定的命令版扩。

13.1.7 輸出緩沖區(qū)

執(zhí)行命令所得到命令回復會被保存在客戶端狀態(tài)的輸出緩沖區(qū)里面废离,每個客戶端都有兩個輸出緩沖區(qū)可用侄泽,一個緩沖區(qū)的大小是規(guī)定的礁芦,另一個緩沖區(qū)的大小是可變的:

  • 固定大小的緩沖區(qū)用于保存那些長度比較小的回復,比如OK悼尾、簡短的字符串值柿扣、整數(shù)值、錯誤回復等等闺魏。
  • 可變大小的緩沖區(qū)用于保存那些長度比較大的回復未状。

客戶端的固定大小緩沖區(qū)bufbufpos兩個屬性組成:

typedef struct redisClient{

    // ...

    char buf[REDIS_REPLY_CHUNK_BYTES];

    int bufpos;

    // ...
}redisClient;

buf是一個大小為REDIS_REPLY_CHUNK_BYTES字節(jié)的字節(jié)數(shù)組,而bufpos屬性則記錄了buf數(shù)組目前已使用的字節(jié)數(shù)量析桥。
REDIS_REPLY_CHUNK_BYTES常量目前的默認值為16*1024司草,為16KB
buf數(shù)組的空間已經(jīng)用完,或者回復太大沒有辦法放進buf數(shù)組里面時泡仗,服務器就會開始使用可變大小緩沖區(qū)埋虹。
可變大小緩沖區(qū)由reply鏈表和一個或多個字符串對象組成:

typedef struct redisClient{

    // ...

    list *reply;

    // ...
}redisClient;

通過使用鏈表來連接多個字符串對象,服務器可以為客戶端保存一個非常長的命令回復娩怎。

13.1.8 身份驗證

客戶端狀態(tài)的authenticated屬性用于記錄客戶端是否通過了身份驗證:

typedef struct redisClient{

    // ...

    int authenticated;

    // ...
}redisClient;

如果authentication的值為0搔课,那么表示客戶端未通過身份驗證;如果authentication的值為1截亦,那么小時客戶端已經(jīng)通過了身份驗證爬泥。
當客戶端authentication屬性的值為0時柬讨,除了AUTH命令之外,客戶端發(fā)送的所有其他命令都會被服務器拒絕執(zhí)行袍啡。
當客戶端通過AUTH命令成功進行身份驗證之后踩官,客戶端狀態(tài)authentication屬性的值就會從0變成1如孝,可以正常發(fā)送命令請求
authentication屬性僅在服務器啟用了身份驗證功能時使用赞季。如果服務器沒有啟用身份驗證功能的話剂跟,那么authentication屬性的值為0哀军,服務器也不會拒絕執(zhí)行客戶端發(fā)送的命令請求阿逃。

13.1.9 時間

typedef struct redisClient{

    // ...

    time_t ctime;

    time_t lastinteraction;

    time_t obuf_soft_limit_reached_time;

    // ...
}redisClient;

ctime屬性記錄了創(chuàng)建客戶端的時間熏挎,這個時間可以用來計算客戶端與服務器已經(jīng)連接了多少秒
lastinteraction屬性記錄了客戶端與服務器最后一次進行互動的時間骚腥。
obuf_soft_limit_reached_time屬性記錄輸出緩存區(qū)第一次到達軟限制的時間懊悯。

13.2 客戶端的創(chuàng)建與關閉

服務器使用不同的方式來創(chuàng)建和關閉不同類型的客戶端窗悯。

13.2.1 創(chuàng)建普通客戶端

如果客戶端通過網(wǎng)絡連接與服務器進行連接的普通用戶客戶端区匣,那么在客戶端使用connect函數(shù)連接到服務器時,服務器就會調用連接事件處理器蒋院,為客戶端創(chuàng)建相應的客戶端狀態(tài)亏钩,并將這個新的客戶端狀態(tài)添加到服務器狀態(tài)結構clients鏈表的末尾。

13.2.2 關閉普通客戶端

一個普通客戶端可以因為多種原因而被關閉:

  • 客戶端進程退出或者被殺死
  • 客戶端發(fā)送不符合協(xié)議格式的命令請求
  • 客戶端成為了CLIENT KILL命令的目標
  • 設置了timeout配置選項欺旧,同時客戶端的空轉時間超過這個值姑丑。
  • 客戶端輸入緩沖區(qū)超過限制大小
  • 客戶端輸出緩沖區(qū)超過限制大小

服務器使用兩種模式來限制客戶端輸出緩沖區(qū)大小:

  • 硬性限制:超過硬性限制辞友,立即關閉
  • 軟性限制:超過軟性限制栅哀,沒有超過硬性限制。使用obuf_soft_limit_reached_time記錄時間称龙,如果一直超過限制留拾,并且持續(xù)時間超過服務器設定的市場,那么服務器關閉客戶端鲫尊;相反痴柔,在規(guī)定的時間內,沒有超過軟性限制疫向,那么客戶端不會被關閉咳蔚,同時obuf_soft_limit_reached_time會被清零。

使用client-output-buffer-limit選項可以為普通客戶端搔驼、從服務器客戶端谈火。執(zhí)行發(fā)布與訂閱功能的客戶端分別設置不同的軟性限制和硬性限制

client-output-buffer-limit <class> <hard limit> <soft limit> <soft seconds>

13.2.3 Lua腳本的偽客戶端

服務器會在初始化時創(chuàng)建負責執(zhí)行Lua腳本中包含的Redis命令的偽客戶端,并將這個偽客戶端關聯(lián)在服務器狀態(tài)結構lua_client屬性中:

struct redisServer{

    // ...

    redisClient *lua_client;

    // ...
};

lua_client偽客戶端在服務器運行的整個生命期中會一直存在匙奴,只有服務器被關閉時堆巧,這個客戶端才會被關閉。

13.2.4 AOF文件的偽客戶端

服務器在載入AOF文件時,會創(chuàng)建用于執(zhí)行AOF文件包含的Redis命令的偽客戶端谍肤,并在載入完成之后啦租,關閉這個偽客戶端。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末荒揣,一起剝皮案震驚了整個濱河市篷角,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌系任,老刑警劉巖恳蹲,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異俩滥,居然都是意外死亡嘉蕾,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進店門霜旧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來错忱,“玉大人,你說我怎么就攤上這事挂据∫郧澹” “怎么了?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵崎逃,是天一觀的道長掷倔。 經(jīng)常有香客問我,道長个绍,這世上最難降的妖魔是什么勒葱? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮障贸,結果婚禮上错森,老公的妹妹穿的比我還像新娘。我一直安慰自己篮洁,他們只是感情好,可當我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布殃姓。 她就那樣靜靜地躺著袁波,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蜗侈。 梳的紋絲不亂的頭發(fā)上篷牌,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天,我揣著相機與錄音踏幻,去河邊找鬼枷颊。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的夭苗。 我是一名探鬼主播信卡,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼题造!你這毒婦竟也來了傍菇?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤界赔,失蹤者是張志新(化名)和其女友劉穎丢习,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體淮悼,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡咐低,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了袜腥。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片渊鞋。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖瞧挤,靈堂內的尸體忽然破棺而出锡宋,到底是詐尸還是另有隱情,我是刑警寧澤特恬,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布执俩,位于F島的核電站,受9級特大地震影響癌刽,放射性物質發(fā)生泄漏役首。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一显拜、第九天 我趴在偏房一處隱蔽的房頂上張望衡奥。 院中可真熱鬧,春花似錦远荠、人聲如沸矮固。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽档址。三九已至,卻和暖如春邻梆,著一層夾襖步出監(jiān)牢的瞬間守伸,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工浦妄, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留尼摹,地道東北人见芹。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像蠢涝,于是被迫代替她去往敵國和親玄呛。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,802評論 2 345

推薦閱讀更多精彩內容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理惠赫,服務發(fā)現(xiàn)把鉴,斷路器,智...
    卡卡羅2017閱讀 134,599評論 18 139
  • 1.Redis特性 1)速度快:數(shù)據(jù)存放在內存上儿咱、基于C語言實現(xiàn)庭砍、單線程架構預防多線程競爭問題;2)基于鍵值對的數(shù)...
    Sponge1128閱讀 616評論 0 1
  • 半壁東南五楚雄混埠,劉郎死去霸圖空怠缸。 幾時痛飲黃龍酒,橫攬江流一奠公钳宪。 黃易先生也走了揭北,曌,一路好走吏颖。 浙東雁蕩山...
    蠡舟閱讀 226評論 0 3
  • 文/國境之南 -1- 記得清楚半醉,那年你的生日疚俱。 提前了好久,我開始做準備缩多,想過許多有創(chuàng)意的呆奕,將我們的合照找出來,找...
    國境之南_閱讀 737評論 4 12
  • 有事要回老家衬吆,列車出行必須先到北京梁钾。而18點北京出發(fā)的列車,從保定來比較之后就只有1點40分出發(fā)15點多到的一趟符...
    樂播報閱讀 268評論 0 3