客戶端的連接的建立
redis通過在TCP端口上進(jìn)行監(jiān)聽,或者Unix socket(如果啟用)的方式來接受客戶端的連接。當(dāng)一個新的客戶端連接被接受執(zhí)行以下操作:
- 當(dāng)Redis使用非阻塞I/O復(fù)用,客戶端socket設(shè)置為非阻塞狀態(tài)。
- socket TCP_NODELAY屬性被設(shè)置確保在連接中我們不會延遲。
- 一個 可讀的文件事件被創(chuàng)建,因而當(dāng)新的數(shù)據(jù)可以被訪問時,Reids可以更快接收客戶端在socket上的查詢
當(dāng)客戶端初始化后,Redis檢查我們是否還在它可以同時處理的客戶端的數(shù)量限制范圍內(nèi)(這個是使用 maxclients 配置指令配置的,請參閱本文檔的下一節(jié)獲取更多的信息。
如果它因為當(dāng)前已經(jīng)接受了最大數(shù)量的客戶端,無法接受當(dāng)前的客戶端,Redis將嘗試發(fā)送一個錯誤給客戶端以便讓其意識到這種情況,并且立即關(guān)閉連接。即使連接被Redis立即關(guān)閉,錯誤信息也會返回給客戶端,因為新的socket輸出緩沖區(qū)一般情況下都足夠放下錯誤信息,因而客戶端內(nèi)核將處理連接錯誤。
客戶端按照什么順序被處理
該順序是由客戶端socket文件描述符的數(shù)字大小及核心報告客戶端事件的順序決定的,因此順序可以看成不確定的。 不過Redis給客戶端提供服務(wù)時會做以下兩件事:
- 每次它從客戶端socket讀取新東西的時候它只執(zhí)行一次 read() 系統(tǒng)調(diào)用,以確保當(dāng)我們有多臺客戶端連接時,并且有一些要求高客戶端以非常快的速率發(fā)送查詢時,其它客戶端不會因此而受到懲罰和經(jīng)歷一個糟糕的延時。(譯者注:意思就是不讀取完整個socket的消息,而是每個socket輪流讀一次)
- 當(dāng)系統(tǒng)調(diào)用執(zhí)行完,當(dāng)前緩沖中的命令不管有多少都會被順序處理。
最大數(shù)量的客戶端
在Redis 2.4中,同時處理的最大客戶端數(shù)量的限制是硬編碼的。
在Redis 2.6中這個限制是動態(tài)的:默認(rèn)情況下為10000個客戶端,除非在redis.conf中配置了maxclients配置項。
Redis通過檢查內(nèi)核中我們可以打開的最多的文件描述符數(shù)量,(soft limit被檢查),如果限制小于最大連接客戶端連接數(shù),則加上32(這是Redis儲備給內(nèi)部使用的文件描述符數(shù)量), 接著這個最大連接客戶端的數(shù)量將被Redis修改為系統(tǒng)要求的值,以便符合在當(dāng)前操作系統(tǒng)限制下的真正能夠處理的客戶端數(shù)量
當(dāng)配置的最大客戶端數(shù)目不起作用時,則日志將在啟動時顯示,如下面這個例子:
$ ./redis-server --maxclients 100000 [41422] 23 Jan 11:28:33.179 # Unable to set the max number of files limit to 100032 (Invalid argument), setting the max clients configuration to 10112.
當(dāng)Redis配置處理客戶的具體數(shù)量時,確認(rèn)操作系統(tǒng)中每個進(jìn)程文件描述符的限制也相應(yīng)地設(shè)置成最大值是個好主意。 在linux下這些限制可以在當(dāng)前的會話設(shè)置,用下面的命令在系統(tǒng)范圍內(nèi)進(jìn)行設(shè)置:
- ulimit -Sn 100000 # 這個將只在硬限制足夠大的情況下生效。
- sysctl -w fs.file-max=100000
輸出緩沖限制
Redis需要為每個客戶端處理可變長度的輸出,因為簡單的命令也可能產(chǎn)生一個需要傳送給客戶端的巨大的數(shù)據(jù)量。
也可能只是客戶端以較快的速度發(fā)送多個的命令產(chǎn)生的更多的輸出,當(dāng)客戶端處理新消息的速度比服務(wù)端發(fā)給給它的速度還慢時,特別是Pub/Sub客戶端更是如此。
這兩個原因?qū)?dǎo)致客戶端輸出緩沖增長及內(nèi)存消耗增多。因為這個原因在默認(rèn)情況下Redis為不同類型的客戶端設(shè)置了輸出緩沖限制。當(dāng)限制到達(dá)后客戶端的連接將被關(guān)閉,同時事件日志記錄在Redis的日志文件中。
Redis使用兩種類型的限制:
- 硬限制是個固定的限制,當(dāng)大小達(dá)到它Redis會以最快的速度關(guān)閉掉客戶端的連接。
- 軟限制依賴于時間,例如每10秒32兆字節(jié)意味著加入客戶端擁有比32兆字節(jié)還大的輸出緩沖,持續(xù)的在10秒內(nèi)超過的話連接將被關(guān)閉。
- 不同類型的客戶端有著不同的默認(rèn)限制:
- 普通客戶端有著默認(rèn)為0的限制,這意味著沒有限制,因為大部分的普通客戶端使用阻塞實現(xiàn)發(fā)送單個命令,并且在發(fā)送下一個命令前等待答復(fù)以完全讀取,因此去關(guān)閉普通客戶端的連接始終是沒必要的。
- Pub/Sub客戶端有默認(rèn)的32兆字節(jié)的硬限制及每60秒8兆字節(jié)的軟限制。
- 從機(jī)有默認(rèn)的256兆字節(jié)的硬限制及每60秒64兆字節(jié)的軟限制。
- 可以在運行時改變這些限制,使用CONFIG SET命令或者修改redis.conf以永久地改變它。見redis.conf中更多的關(guān)于如何設(shè)置限制的介紹。
搜索緩沖硬限制
每一個客戶端也受到搜索緩沖限制。這是個不可配置的硬限制,當(dāng)客戶端搜索緩沖(這是個我們用來積累客戶端的命令的緩沖)達(dá)到1GB的時候它將關(guān)閉連接,這只是個極限限制,用來避免當(dāng)客戶端或者服務(wù)端軟件出錯導(dǎo)致服務(wù)器崩潰的情況。
客戶端超時
最近版本的Reids在默認(rèn)情況下不會在客戶端空閑很久后關(guān)閉連接;連接將永久保留。 不過假如你不喜歡這種行為,你可以設(shè)置一個超時時間,這樣當(dāng)客戶端空閑超過設(shè)置的幾秒后,客戶端連接就會被關(guān)閉。
你可以在redis.conf中配置這個限制或者簡單的使用CONFIG SET timeout 。 記住這個超時時間只適用于多個客戶端并且它不支持Pub/Sub客戶端, Pub/Sub連接是推送類型的連接,因而客戶端空閑是正常的。
即使在默認(rèn)情況下連接是不受超時時間限制的,但是有兩種情況設(shè)置超時是有意義的:
- 關(guān)鍵任務(wù)應(yīng)用,客戶端軟件可能因為Redis連接飽和而造成出錯,造成服務(wù)中斷。
- 如果一個客戶端出錯使得服務(wù)器因為空閑連接而飽和,使得無法與服務(wù)器交互,此時可以作為一個檢錯機(jī)制去連接服務(wù)器。
超時并非非常準(zhǔn)確:Redis避免設(shè)置計時器或者運行O(N) 算法去輪詢檢測客戶端是否超時, 所以檢查是漸近的一部分一部分完成的。這意味著有可能當(dāng)超時時間設(shè)置為10秒,客戶端的連接將在稍晚的時候被關(guān)閉,例如當(dāng)很多客戶端在同一時間連接的話,可能12秒才被關(guān)閉。
客戶端命令
Redis客戶端命令允許檢查所有連接的客戶端的狀態(tài)、關(guān)掉指定的客戶端的連接、設(shè)置連接的名稱。假如你使用一定規(guī)模的Redis的話這是個很強(qiáng)大的排錯工具
CLIENT LIST命令用來獲得連接的客戶端列表及它們的狀態(tài):
redis 127.0.0.1:6379> client list addr=127.0.0.1:52555 fd=5 name= age=855 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 addr=127.0.0.1:52787 fd=6 name= age=6 idle=5 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0