深入Redis客戶端(redis客戶端屬性、redis緩衝區)

深入Redis客戶端(redis客戶端屬性、redis緩衝區、關閉redis客戶端)

Redis 數據庫採用 I/O 多路複用技術實現文件事件處理器,服務器採用單線程單進程的方式來處理多個客戶端發送過來的命令請求,它同時與多個客戶端建立網絡通信。服務器會為與它相連接的客戶端創建相應的 redis.h/redisClient 結構,在這個結構中保存了當前客戶端的相關屬性及執行相關功能時的數據結構。


I/O 多路複用:linux有五類io模型 1.阻塞 2.非阻塞 3.io多路複用 4.事件驅動 5.異步

阻塞:一次網絡io時,C端發出請求,S端收到。當C端發出一個請求,進行io時,就不能進行其他操作了,需要同步的等待結果的返回。

io多路複用:有多個C端同時發送請求,這些IO操作會被selector(epoll,kqueue)給暫時掛起,入內存隊列。此時S端可以自己選擇什麼時候讀取、處理這些io,也就是說S端可以同時hold住多個io。


redis的文本事件處理器

深入Redis客戶端(redis客戶端屬性、redis緩衝區)


客戶端的名字、套接字、標誌和時間屬性

<code>127.0.0.1:6379> client list
id=2 addr=127.0.0.1:53555 fd=9 name= age=6 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 events=r cmd=client/<code>
  1. 名字:在默認情況下,連接到 Redis 服務器的客戶端是沒有名字(name屬性, 如上)的 給它設置名字 127.0.0.1:6379> client setname "local_client" OK 127.0.0.1:6379> client list id=2 addr=127.0.0.1:53555 fd=9 name=local_client age=110 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 events=r cmd=client如果沒有為客戶端設置名字,那麼這個客戶端的 name 屬性將會指向 NULL 指針;而如果為這個客戶端設置了名字,那麼這個客戶端的 name 屬性將會指向一個字符串對象,這個對象中保存了客戶端的名字
  2. 套接字:

客戶端套接字由客戶端狀態的 fd 屬性記錄

當 fd 屬性值為-1 時,表示這個客戶端是偽客戶端。偽客戶端的請求命令不是來源於網絡的,而是來源於 Lua 腳本或 AOF 文件(後續詳細介紹)的,所以偽客戶端不需要套接字連接,它也沒有套接字描述符。當我們執行的 Lua 腳本中含有 Redis 命令,或者使用 AOF 文件來還原數據庫狀態時,就會用到偽客戶端。

當 fd 屬性值是大於-1 的整數時,表示這個客戶端是普通客戶端。普通客戶端採用相關套接字來實現與服務器的通信,因此服務器會利用 fd 屬性來記錄客戶端套接字的描述符。

  1. 標誌屬性 客戶端的標誌屬性 flags 用來記錄客戶端的角色(Role)及客戶端目前所處的狀態。 flags 屬性的取值可以是單個標誌,也可以是多個二進制或的組合標誌,具體如下。 單個標誌:flags=<flag> 組合標誌:flags=<flag1>|<flag2>|<flag3>|… 標誌使用常量來表示。Redis 所具有的所有標誌都定義在 redis.h 文件中。 記錄客戶端角色的標誌有如下幾個。 ● 在利用 Redis 主從服務器實現複製時,主從服務器會相互成為對方的客戶端,也就是從服務器是主服務器的客戶端,同時主服務器也是從服務器的客戶端。Redis 使用REDIS_MASTER 標誌來表示這個客戶端是主服務器,而使用 REDIS_SLAVE 標誌來表示另一個客戶端是從服務器。 ● Redis 使用 REDIS_LUA_CLIENT 標誌來表示該客戶端是一個專門用於處理 Lua 腳本的偽客戶端,它主要用於執行 Lua 腳本中包含的 Redis 命令。 ● Redis 使用 REDIS_PRE_PSYNC 標誌來表示該客戶端是一個低於 Redis 2.8 版本的從服務器,此時,對應的主服務器不能使用 PSYNC 命令實現與從服務器的數據同步。只有當 REDIS_SLAVE 標誌處於打開狀態時,才能使用 REDIS_PRE_PSYNC 標誌。 記錄客戶端當前狀態的標誌有如下幾個。 ● REDIS_ASKING 標誌表示客戶端向運行在集群模式下的服務器節點發送了 ASKING 命令。 ●
    REDIS_CLOSE_ASAP 標誌表示客戶端的輸出緩衝區過大,超出了服務器所允許的範圍。當服務器在下一次執行 serverCron 函數時,會關閉這個輸出緩衝區過大的客戶端,以此來保證服務器的穩定性不受這個客戶端影響。在關閉的時候,存儲在這個緩衝區中的數據也會被刪除,並且不會給客戶端返回任何信息。 ● REDIS_CLOSE_AFTER_REPLY 標誌表示客戶端給服務器發送的命令請求中有錯誤的協議內容,或者用戶在客戶端中執行了 CLIENT kill 命令。此時服務器會將客戶端輸出緩衝區中存儲的所有數據內容發送給客戶端,然後關閉這個客戶端。 ● REDIS_DIRTY_CAS 標誌表示事務使用 WATCH 命令監視的數據庫鍵已經被修改。 ● REDIS_DIRTY_EXEC 標誌表示事務在命令入隊時出現錯誤。 REDIS_DIRTY_CAS 和 REDIS_DIRTY_EXEC 標誌的出現都表示 Redis 事務的安全性已被破壞。只要這兩個標誌中的任何一個被打開,EXEC 命令都會執行失敗。而只有在客戶端打開了 REDIS_MULTI 標誌的情況下,才能使用這兩個標誌。 ● REDIS_MULTI 標誌表示客戶端正處於執行事務的狀態中。 ● REDIS_MONITOR 標誌表示客戶端正處於執行 MONITOR 命令的狀態中。 ● REDIS_FORCE_AOF 標誌表示讓服務器將當前正在執行的命令強制寫入 AOF 文件中。在執行 PUBSUB 命令時,會使客戶端打開 REDIS_FORCE_AOF 標誌。 ●
    REDIS_FORCE_REPL 標誌表示強制讓主服務器將當前正在執行的命令複製給所有與它連接的從服務器。當執行 SCRIPT LOAD 命令時,會使客戶端同時開啟 REDIS_FORCE_AOF 和 REDIS_FORCE_REPL 標誌。如果要實現主從服務器可以正確地載入 SCRIPT LOAD 命令指定的腳本,那麼服務器必須使用 REDIS_FORCE_REPL 標誌,讓主服務器強制將 SCRIPT LOAD 命令分發給相應的從服務器。 ● REDIS_UNIX_SOCKET 標誌表示服務器連接客戶端使用的是 UNIX 套接字。 ● REDIS_BLOCKED 標誌表示客戶端正處於被 BRPOP、BLPOP 等命令阻塞的狀態中。 ● REDIS_UNBLOCKED 標誌表示客戶端不再阻塞,它從 REDIS_BLOCKED 標誌的阻塞狀態中脫離出來。只有在 REDIS_BLOCKED 標誌被打開的情況下,才能使用 REDIS_UNBLOCKED 標誌。 ● REDIS_MASTER_FORCE_REPLY 標誌:在主從服務器進行命令交互的過程中,從服務器需要向主服務器發送 REPLICATION ACK 命令。但是,在發送此命令之前,從服務器必須開啟主服務器對應的客戶端的 REDIS_MASTER_FORCE_REPLY 標誌;否則主服務器會拒絕執行從服務器發送的 REPLCATION ACK 命令。
  2. 時間屬性 ● ctime 屬性:該屬性記錄了客戶端被創建的時間。利用這個時間可以計算出這個客戶端與服務器相連接的時間,單位為秒。在執行 CLIENT list 命令後,返回的 age 域記錄了連接秒數 ● lastinteraction 屬性:該屬性記錄了客戶端與服務器最後一次交互的時間。交互就是兩者之間互相發送命令請求與返回結果。利用 lastinteraction 屬性可以計算出客戶端的空轉時間,也就是在進行最後一次交互之前過去了多少時間,單位為秒。CLIENT list 命令返回的 idle 域記錄了這個時間。當 idle 的值為 0 時,表示空轉時間為 0 秒。 ● obuf_soft_limit_reached_time 屬性:該屬性記錄了客戶端輸出緩衝區第一次達到軟性限制的時間

redis客戶端的緩衝區

一些概念

● 輸入緩衝區:用於保存客戶端發送的命令請求。輸入緩衝區的大小是動態變化的,它會根據輸入的內容動態縮小或增大。1GB 是輸入緩衝區的最大大小。如果輸入緩衝區的大小超過了 1GB,那麼這個客戶端將會被關閉。

● 輸出緩衝區:用於保存執行客戶端請求命令返回的結果或返回值。每個客戶端都有兩個輸出緩衝區,一個輸出緩衝區的大小是固定的,另一個輸出緩衝區的大小是可變的。

➢ 固定輸出緩衝區:用於保存那些長度比較小的返回值,比如常見的 OK、<nil> 或者一些短字符串、整數值及錯誤值等。

➢ 可變輸出緩衝區:用於保存那些長度比較大的返回值,比如一個長度比較大的字符串、大列表、大集合等。

buf 和 bufpos 屬性組成了客戶端固定大小的緩衝區。

buf 屬性是一個字節數組,數組大小為 REDIS_REPLY_CHUNK_BYTES 字節。REDIS_REPLY_CHUNK_BYTES 常量的默認值為 16×1024,即 buf 數組的默認大小為 16KB。

bufpos 屬性記錄了 buf 數組到目前為止已經使用的字節數量。

當 buf 數組已經存滿或者回復因為太大而沒有辦法存入 buf 數組時,服務器就會使用可變大小的緩衝區。

鏈表 reply 和一個或多個字符串對象組成可變大小的輸出緩衝區。通過使用鏈表來連接多個字符串對象,服務器可以為客戶端保存一個非常長的命令返回值,而不會受到大小的限制。如圖所示為可變大小的輸出緩衝區。

深入Redis客戶端(redis客戶端屬性、redis緩衝區)

服務器採用軟性限制(Soft Limit)和硬性限制(Hard Limit)兩種模式來限制客戶端緩衝區的大小。

  1. 軟性限制:如果軟性限制所設置的大小小於輸出緩衝區的大小,且輸出緩衝區的大小不大於硬性限制所設置的大小,那麼服務器會使用客戶端狀態結構的 obuf_soft_limit_reached_time 屬性來記錄客戶端達到軟性限制的起始時間。之後服務器會繼續監視客戶端,如果這個緩衝區的大小一直超出軟性限制,並且持續時間超過服務器設定的時長,那麼服務器將會關閉這個客戶端。相反地,如果輸出緩衝區的大小在指定時間範圍之內沒有超過軟性限制,那麼這個客戶端不會被關閉,並且 obuf_soft_limit_reached_time 屬性的值也會被設置為 0。
  2. 當輸出緩衝區的大小超過了硬性限制的大小時,這個客戶端會被立即關閉。
  3. 設置軟性限制和硬性限制 我們可以使用 client-output-buffer-limit 選項來為普通客戶端、從服務器客戶端或執行消息訂閱發佈功能的客戶端設置軟性限制和硬性限制
深入Redis客戶端(redis客戶端屬性、redis緩衝區)


客戶端的 authenticated 屬性

authenticated 屬性是客戶端身份驗證屬性,用於記錄客戶端是否通過了身份驗證。這個屬性的值為 0 和 1,默認值為 0。

當 authenticated 屬性值為 0 時,服務器除執行 AUTH 命令之外,將會拒絕執行客戶端發送過來的其他所有命令。


客戶端的 argv 和 argc 屬性

argv 屬性:這是一個數組,數組中的每個元素都是一個字符串對象,其中 argv[0]是要執行的命令,而之後的其他元素是傳給這個命令的參數。

argc 屬性:用於記錄 argv 屬性的數組長度。

當客戶端向服務器發送命令時,服務器會將接收到的命令保存到客戶端狀態的 querybuf 屬性中。保存之後,服務器會分析這個命令的內容,並將分析得出的命令參數及命令參數的個數分別保存到 argv 和 argc 屬性中

深入Redis客戶端(redis客戶端屬性、redis緩衝區)


關閉客戶端

普通客戶端被關閉的幾種方式:

● 當客戶端執行了 CLIENT kill 命令時,客戶端會被關閉。

● 當客戶端進程被殺死時,客戶端將會斷開與服務器的連接,從而客戶端被關閉。

● 當客戶端向服務器發送的命令是錯誤協議格式時,客戶端會被關閉。

● 當客戶端發送的命令請求的大小超過了輸入緩衝區的限制大小時,客戶端會被關閉。

● 當發送給客戶端的命令執行後返回結果的大小超過了輸出緩衝區的限制大小時,客戶端也會被關閉。

● 當為服務器設置了 timeout 參數值,同時客戶端的空轉時間又超過了 timeout 參數值時,客戶端將會被關閉。而如果這個客戶端是主服務器,而從服務器被 BLPOP、BRPOP 等相關命令阻塞,或者從服務器正在執行與訂閱發佈相關的命令,此時就算客戶端的空轉時間超過了 timeout 參數值,這個客戶端也不會被關閉。


分享到:


相關文章: