天天看點

深入Redis用戶端(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的文本事件處理器

用戶端的名字、套接字、标志和時間屬性

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

名字:在預設情況下,連接配接到 Redis 伺服器的用戶端是沒有名字(name屬性, 如上)的

給它設定名字

127.0.0.1:6379> client setname "local_client"

OK

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 屬性将會指向一個字元串對象,這個對象中儲存了用戶端的名字

套接字:

用戶端套接字由用戶端狀态的 fd 屬性記錄

當 fd 屬性值為-1 時,表示這個用戶端是僞用戶端。僞用戶端的請求指令不是來源于網絡的,而是來源于 Lua 腳本或 AOF 檔案(後續詳細介紹)的,是以僞用戶端不需要套接字連接配接,它也沒有套接字描述符。當我們執行的 Lua 腳本中含有 Redis 指令,或者使用 AOF 檔案來還原資料庫狀态時,就會用到僞用戶端。

當 fd 屬性值是大于-1 的整數時,表示這個用戶端是普通用戶端。普通用戶端采用相關套接字來實作與伺服器的通信,是以伺服器會利用 fd 屬性來記錄用戶端套接字的描述符。

标志屬性

用戶端的标志屬性 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 指令。

時間屬性

● 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 和一個或多個字元串對象組成可變大小的輸出緩沖區。通過使用連結清單來連接配接多個字元串對象,伺服器可以為用戶端儲存一個非常長的指令傳回值,而不會受到大小的限制。如圖所示為可變大小的輸出緩沖區。

伺服器采用軟性限制(Soft Limit)和硬性限制(Hard Limit)兩種模式來限制用戶端緩沖區的大小。

軟性限制:如果軟性限制所設定的大小小于輸出緩沖區的大小,且輸出緩沖區的大小不大于硬性限制所設定的大小,那麼伺服器會使用用戶端狀态結構的 obuf_soft_limit_reached_time 屬性來記錄用戶端達到軟性限制的起始時間。之後伺服器會繼續監視用戶端,如果這個緩沖區的大小一直超出軟性限制,并且持續時間超過伺服器設定的時長,那麼伺服器将會關閉這個用戶端。相反地,如果輸出緩沖區的大小在指定時間範圍之内沒有超過軟性限制,那麼這個用戶端不會被關閉,并且 obuf_soft_limit_reached_time 屬性的值也會被設定為 0。

當輸出緩沖區的大小超過了硬性限制的大小時,這個用戶端會被立即關閉。

設定軟性限制和硬性限制

我們可以使用 client-output-buffer-limit 選項來為普通用戶端、從伺服器用戶端或執行消息訂閱釋出功能的用戶端設定軟性限制和硬性限制

用戶端的 authenticated 屬性

authenticated 屬性是用戶端身份驗證屬性,用于記錄用戶端是否通過了身份驗證。這個屬性的值為 0 和 1,預設值為 0。

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

用戶端的 argv 和 argc 屬性

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

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

當用戶端向伺服器發送指令時,伺服器會将接收到的指令儲存到用戶端狀态的 querybuf 屬性中。儲存之後,伺服器會分析這個指令的内容,并将分析得出的指令參數及指令參數的個數分别儲存到 argv 和 argc 屬性中

關閉用戶端

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

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

● 當用戶端程序被殺死時,用戶端将會斷開與伺服器的連接配接,進而用戶端被關閉。

● 當用戶端向伺服器發送的指令是錯誤協定格式時,用戶端會被關閉。

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

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

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

原文位址

https://www.cnblogs.com/undefined22/p/12580818.html