本文檔提供有關Redis如何處理來自用戶端的資訊,從網絡層來看包含以下幾點:連接配接、逾時、緩沖區以及一些其它類似的主題。 這篇文檔所包含的資訊 僅僅适用于Redis的2.6或者更高版本。
Redis通過在TCP端口上進行監聽,或者Unix socket(如果啟用)的方式來接受用戶端的連接配接。當一個新的用戶端連接配接被接受執行以下操作:
當Redis使用非阻塞I/O複用,用戶端socket設定為非阻塞狀态。
socket TCP_NODELAY屬性被設定確定在連接配接中我們不會延遲。
一個 可讀的檔案事件被建立,因而當新的資料可以被通路時,Reids可以更快接收用戶端在socket上的查詢
當用戶端初始化後,Redis檢查我們是否還在它可以同時處理的用戶端的數量限制範圍内(這個是使用 maxclients 配置指令配置的,請參閱本文檔的下一節擷取更多的資訊。
如果它因為目前已經接受了最大數量的用戶端,無法接受目前的用戶端,Redis将嘗試發送一個錯誤給用戶端以便讓其意識到這種情況,并且立即關閉連接配接。即使連接配接被Redis立即關閉,錯誤資訊也會傳回給用戶端,因為新的socket輸出緩沖區一般情況下都足夠放下錯誤資訊,因而用戶端核心将處理連接配接錯誤。
該順序是由用戶端socket檔案描述符的數字大小及核心報告用戶端事件的順序決定的,是以順序可以看成不确定的。 不過Redis給用戶端提供服務時會做以下兩件事:
每次它從用戶端socket讀取新東西的時候它隻執行一次 read() 系統調用,以確定當我們有多台用戶端連接配接時,并且有一些要求高用戶端以非常快的速率發送查詢時,其它用戶端不會是以而受到懲罰和經曆一個糟糕的延時。(譯者注:意思就是不讀取完整個socket的消息,而是每個socket輪流讀一次)
當系統調用執行完,目前緩沖中的指令不管有多少都會被順序處理。
在Redis 2.4中,同時處理的最大用戶端數量的限制是寫死的。
在Redis 2.6中這個限制是動态的:預設情況下為10000個用戶端,除非在redis.conf中配置了maxclients配置項。
Redis通過檢查核心中我們可以打開的最多的檔案描述符數量,(soft limit被檢查),如果限制小于最大連接配接用戶端連接配接數,則加上32(這是Redis儲備給内部使用的檔案描述符數量), 接着這個最大連接配接用戶端的數量将被Redis修改為系統要求的值,以便符合在目前作業系統限制下的真正能夠處理的用戶端數量
當配置的最大用戶端數目不起作用時,則日志将在啟動時顯示,如下面這個例子:
當Redis配置處理客戶的具體數量時,确認作業系統中每個程序檔案描述符的限制也相應地設定成最大值是個好主意。 在Linux下這些限制可以在目前的會話設定,用下面的指令在系統範圍内進行設定:
ulimit -Sn 100000 # 這個将隻在硬限制足夠大的情況下生效。
sysctl -w fs.file-max=100000
Redis需要為每個用戶端處理可變長度的輸出,因為簡單的指令也可能産生一個需要傳送給用戶端的巨大的資料量。
也可能隻是用戶端以較快的速度發送多個的指令産生的更多的輸出,當用戶端處理新消息的速度比服務端發給給它的速度還慢時,特别是Pub/Sub用戶端更是如此。
這兩個原因将導緻用戶端輸出緩沖增長及記憶體消耗增多。因為這個原因在預設情況下Redis為不同類型的用戶端設定了輸出緩沖限制。當限制到達後用戶端的連接配接将被關閉,同時事件日志記錄在Redis的日志檔案中。
Redis使用兩種類型的限制:
硬限制是個固定的限制,當大小達到它Redis會以最快的速度關閉掉用戶端的連接配接。
軟限制依賴于時間,例如每10秒32兆位元組意味着加入用戶端擁有比32兆位元組還大的輸出緩沖,持續的在10秒内超過的話連接配接将被關閉。
不同類型的用戶端有着不同的預設限制:
普通用戶端有着預設為0的限制,這意味着沒有限制,因為大部分的普通用戶端使用阻塞實作發送單個指令,并且在發送下一個指令前等待答複以完全讀取,是以去關閉普通用戶端的連接配接始終是沒必要的。
Pub/Sub用戶端有預設的32兆位元組的硬限制及每60秒8兆位元組的軟限制。
從機有預設的256兆位元組的硬限制及每60秒64兆位元組的軟限制。
可以在運作時改變這些限制,使用CONFIG SET指令或者修改redis.conf以永久地改變它。見redis.conf中更多的關于如何設定限制的介紹。
每一個用戶端也受到搜尋緩沖限制。這是個不可配置的硬限制,當用戶端搜尋緩沖(這是個我們用來積累用戶端的指令的緩沖)達到1GB的時候它将關閉連接配接,這隻是個極限限制,用來避免當用戶端或者服務端軟體出錯導緻伺服器崩潰的情況。
最近版本的Reids在預設情況下不會在用戶端空閑很久後關閉連接配接;連接配接将永久保留。 不過假如你不喜歡這種行為,你可以設定一個逾時時間,這樣當用戶端空閑超過設定的幾秒後,用戶端連接配接就會被關閉。
你可以在redis.conf中配置這個限制或者簡單的使用CONFIG SET timeout 。 記住這個逾時時間隻适用于多個用戶端并且它不支援Pub/Sub用戶端, Pub/Sub連接配接是推送類型的連接配接,因而用戶端空閑是正常的。
即使在預設情況下連接配接是不受逾時時間限制的,但是有兩種情況設定逾時是有意義的:
關鍵任務應用,用戶端軟體可能因為Redis連接配接飽和而造成出錯,造成服務中斷。
如果一個用戶端出錯使得伺服器因為空閑連接配接而飽和,使得無法與伺服器互動,此時可以作為一個檢錯機制去連接配接伺服器。
逾時并非非常準确:Redis避免設定計時器或者運作O(N) 算法去輪詢檢測用戶端是否逾時, 是以檢查是漸近的一部分一部分完成的。這意味着有可能當逾時時間設定為10秒,用戶端的連接配接将在稍晚的時候被關閉,例如當很多用戶端在同一時間連接配接的話,可能12秒才被關閉。
Redis用戶端指令允許檢查所有連接配接的用戶端的狀态、關掉指定的用戶端的連接配接、設定連接配接的名稱。假如你使用一定規模的Redis的話這是個很強大的排錯工具
CLIENT LIST指令用來獲得連接配接的用戶端清單及它們的狀态:
在上面的示例中兩台用戶端都連接配接到了Redis伺服器。一部分有趣的字段的含義如下表所示:
addr:用戶端位址,也就是用戶端用來連接配接Redis伺服器的IP和遠端端口号
fd:用戶端socket檔案描述符數目。
name:用戶端名稱,由CLIENT SETNAME指令設定。
age:連接配接已經存在了多少秒。
idle:連接配接已經空閑了幾秒。
flags:用戶端的類型(N代表普通用戶端, 檢視字段完整清單)。
omem:用戶端輸出緩沖占用的記憶體量。
cmd:最後執行的指令。
參考CLIENT LIST文檔,檢視完整的字段清單及它們的說明。
當你有了用戶端的清單, 你可以很簡單的使用CLIENT KILL指令帶上用戶端IP作為參數來關掉連接配接。
指令CLIENT SETNAME和CLIENT GETNAME可以用于設定和取得連接配接的名稱。
本文作者:陳群
本文來自雲栖社群合作夥伴rediscn,了解相關資訊可以關注redis.cn網站。