Redis:22---客户端API:client、monitor)
?
一、client list
client list命令能列出與Redis服務(wù)端相連的所有客戶(hù)端連接信息。例如下面代碼是在一個(gè)Redis實(shí)例上執(zhí)行client list的結(jié)果,其中每一行代表一個(gè)客戶(hù)端信息:
?
下面將選擇幾個(gè)重要的屬性進(jìn)行說(shuō)明,其余通過(guò)表格的形式進(jìn)行展示
①標(biāo)識(shí):id、addr、fd、name
這四個(gè)屬性屬于客戶(hù)端的標(biāo)識(shí):
id:客戶(hù)端連接的唯一標(biāo)識(shí),這個(gè)id是隨著Redis的連接自增的,重啟 Redis后會(huì)重置為0
addr:客戶(hù)端連接的ip和端口
fd:socket的文件描述符,與lsof命令結(jié)果中的fd是同一個(gè),如果fd=-1代表當(dāng)前客戶(hù)端不是外部客戶(hù)端,而是Redis內(nèi)部的偽裝客戶(hù)端
name:客戶(hù)端的名字,后面的client setName和client getName兩個(gè)命令會(huì)對(duì)其進(jìn)行說(shuō)明
②輸入緩沖區(qū):qbuf、qbuf-free
Redis為每個(gè)客戶(hù)端分配了輸入緩沖區(qū),它的作用是:將客戶(hù)端發(fā)送的命令臨時(shí)保存,同時(shí)Redis從會(huì)輸入緩沖區(qū)拉取命令并執(zhí)行,輸入緩沖區(qū)為客 戶(hù)端發(fā)送命令到Redis執(zhí)行命令提供了緩沖功能,如下圖所示
client list中qbuf和qbuf-free:
這兩個(gè)屬性分別代表這個(gè)緩沖區(qū)的總?cè)萘亢褪S嗳萘?/p>
Redis沒(méi)有提供相應(yīng)的配置來(lái)規(guī)定每個(gè)緩沖區(qū)的大小,輸入緩沖區(qū)會(huì)根據(jù)輸入內(nèi)容大小的不同動(dòng)態(tài)調(diào)整,只是要求每個(gè)客戶(hù)端緩沖區(qū)的大小不能超過(guò)1G,超過(guò)后客戶(hù)端將被關(guān)閉
下面是Redis源碼中對(duì)于輸入緩沖區(qū)的硬編碼:
輸入緩沖使用不當(dāng)會(huì)產(chǎn)生兩個(gè)問(wèn)題:
一旦某個(gè)客戶(hù)端的輸入緩沖區(qū)超過(guò)1G,客戶(hù)端將會(huì)被關(guān)閉
輸入緩沖區(qū)不受maxmemory控制,假設(shè)一個(gè)Redis實(shí)例設(shè)置了maxmemory為4G,已經(jīng)存儲(chǔ)了2G數(shù)據(jù),但是如果此時(shí)輸入緩沖區(qū)使用了3G,已經(jīng)超過(guò)maxmemory限制,可能會(huì)產(chǎn)生數(shù)據(jù)丟失、鍵值淘汰、OOM等情況(如下圖所示)
上圖的執(zhí)行效果如下:
上面已經(jīng)看到,輸入緩沖區(qū)使用不當(dāng)造成的危害非常大,那么造成輸入緩沖區(qū)過(guò)大的原因有哪些?
輸入緩沖區(qū)過(guò)大主要是因?yàn)镽edis的處理速度跟不上輸入緩沖區(qū)的輸入速度,并且每次進(jìn)入輸入緩沖區(qū)的命令包含了大量 bigkey,從而造成了輸入緩沖區(qū)過(guò)大的情況
還有一種情況就是Redis發(fā)生了阻塞,短期內(nèi)不能處理命令,造成客戶(hù)端輸入的命令積壓在了輸入緩沖區(qū), 造成了輸入緩沖區(qū)過(guò)大
那么如何快速發(fā)現(xiàn)和監(jiān)控呢?監(jiān)控輸入緩沖區(qū)異常的方法有兩種:
通過(guò)定期執(zhí)行client list命令,收集qbuf和qbuf-free找到異常的連接記錄 并分析,最終找到可能出問(wèn)題的客戶(hù)端。
通過(guò)info命令的info clients模塊,找到最大的輸入緩沖區(qū),例如下面命令中的其中client_recent_max_input_buffer代表最大的輸入緩沖區(qū),例如可以設(shè)置超過(guò)10M就進(jìn)行報(bào)警
上面兩種方法各有自己的優(yōu)劣勢(shì),下圖對(duì)兩種方法進(jìn)行了對(duì)比:
運(yùn)維提示:輸入緩沖區(qū)問(wèn)題出現(xiàn)概率比較低,但是也要做好防范,在開(kāi)發(fā)中要減少bigkey、減少Redis阻塞、合理的監(jiān)控報(bào)警
③輸出緩沖區(qū):obl、oll、omem
Redis為每個(gè)客戶(hù)端分配了輸出緩沖區(qū),它的作用是:保存命令執(zhí)行的結(jié) 果返回給客戶(hù)端,為Redis和客戶(hù)端交互返回結(jié)果提供緩沖
與輸入緩沖區(qū)不同的是:
輸出緩沖區(qū)的容量可以通過(guò)參數(shù)client-outputbuffer-limit來(lái)進(jìn)行設(shè)置
并且輸出緩沖區(qū)做得更加細(xì)致,按照客戶(hù)端的不同分為三種:普通客戶(hù)端、發(fā)布訂閱客戶(hù)端、slave客戶(hù)端。如下圖所示
client-output-buffer-limit格式如下。參數(shù)意義為:
<class>:客戶(hù)端類(lèi)型,分為三種。a)normal:普通客戶(hù)端;b) slave:slave客戶(hù)端,用于復(fù)制;c)pubsub:發(fā)布訂閱客戶(hù)端
<hard limit>:如果客戶(hù)端使用的輸出緩沖區(qū)大于該值,客戶(hù)端會(huì)被立即關(guān)閉
<soft limit>和<soft seconds>:如果客戶(hù)端使用的輸出緩沖區(qū)超過(guò)了并且持續(xù)了秒,客戶(hù)端會(huì)被立即關(guān)閉
Redis的默認(rèn)配置是:
和輸入緩沖區(qū)相同的是,輸出緩沖區(qū)也不會(huì)受到maxmemory的限制,如果使用不當(dāng)同樣會(huì)造成maxmemory用滿產(chǎn)生的數(shù)據(jù)丟失、鍵值淘汰、OOM等情況
實(shí)際上輸出緩沖區(qū)由兩部分組成:
固定緩沖區(qū)(16KB):返回比較小的執(zhí)行結(jié)果
動(dòng)態(tài)緩沖區(qū):返回比較大的結(jié)果。例如大的字符串、hgetall、smembers命令的結(jié)果等,通過(guò)Redis源碼中redis.h的redisClient結(jié)構(gòu)體(Redis3.2版本變?yōu)镃lient)可以看到兩個(gè)緩沖區(qū)的實(shí)現(xiàn)細(xì)節(jié):
固定緩沖區(qū)使用的是字節(jié)數(shù)組,動(dòng)態(tài)緩沖區(qū)使用的是列表。當(dāng)固定緩沖區(qū)存滿后會(huì)將Redis新的返回結(jié)果存放在動(dòng)態(tài)緩沖區(qū)的隊(duì)列中,隊(duì)列中的每個(gè)對(duì)象就是每個(gè)返回結(jié)果,如下圖所示:
obl、oll、omem:
client list中的obl代表固定緩沖區(qū)的長(zhǎng)度,oll代表動(dòng)態(tài)緩沖區(qū)列表的長(zhǎng)度,omem代表使用的字節(jié)數(shù)
例如下面代表當(dāng)前客戶(hù)端的固定緩沖區(qū)的長(zhǎng)度為0,動(dòng)態(tài)緩沖區(qū)有4869個(gè)對(duì)象,兩個(gè)部分共使用了133081288字節(jié)=126M 內(nèi)存:
監(jiān)控輸出緩沖區(qū)的方法依然有兩種:
①通過(guò)定期執(zhí)行client list命令,收集obl、oll、omem找到異常的連接記錄 并分析,最終找到可能出問(wèn)題的客戶(hù)端
②通過(guò)info命令的info clients模塊,找到輸出緩沖區(qū)列表最大對(duì)象數(shù),例如(其中,client_longest_output_list代表輸出緩沖區(qū)列表最大對(duì)象數(shù)):
這兩種統(tǒng)計(jì)方法的優(yōu)劣勢(shì)和輸入緩沖區(qū)是一樣的,這里就不再贅述了
相比于輸入緩沖區(qū),輸出緩沖區(qū)出現(xiàn)異常的概率相對(duì)會(huì)比較大,那么如何預(yù)防呢?方法如下:
進(jìn)行上述監(jiān)控,設(shè)置閥值,超過(guò)閥值及時(shí)處理
適當(dāng)增大slave的輸出緩沖區(qū)的,如果master節(jié)點(diǎn)寫(xiě)入較大,slave客戶(hù) 端的輸出緩沖區(qū)可能會(huì)比較大,一旦slave客戶(hù)端連接因?yàn)檩敵鼍彌_區(qū)溢出 被kill,會(huì)造成復(fù)制重連
限制容易讓輸出緩沖區(qū)增大的命令,例如,高并發(fā)下的monitor命令就 是一個(gè)危險(xiǎn)的命令
及時(shí)監(jiān)控內(nèi)存,一旦發(fā)現(xiàn)內(nèi)存抖動(dòng)頻繁,可能就是輸出緩沖區(qū)過(guò)大
限制普通客戶(hù)端輸出緩沖區(qū)的,把錯(cuò)誤扼殺在搖籃中,例如可以進(jìn)行如下設(shè)置:
④客戶(hù)端的存活狀態(tài)(age、idle)
client list中的age和idle分別代表:當(dāng)前客戶(hù)端已經(jīng)連接的時(shí)間、最近一次的空閑時(shí)間:
例如下面這條記錄代表當(dāng)期客戶(hù)端連接Redis的時(shí)間為304秒,其中空閑了0秒:
例如下面這條記錄代表當(dāng)期客戶(hù)端連接Redis的時(shí)間為8888581秒,其中空閑了8888581秒。實(shí)際上這種就屬于不太正常的情況,當(dāng)age等于idle時(shí), 說(shuō)明連接一直處于空閑狀態(tài)
演示案例
為了更加直觀地描述age和idle,下面用一個(gè)例子進(jìn)行說(shuō)明:
下面對(duì)代碼中的每一步進(jìn)行分析,用client list命令來(lái)觀察age和idle參數(shù)的相應(yīng)變化(備注:為了與redis-cli的客戶(hù)端區(qū)分,本次測(cè)試客戶(hù)端IP地址:10.7.40.98)
1)在執(zhí)行代碼之前,client list只有一個(gè)客戶(hù)端,也就是當(dāng)前的rediscli,下面為了節(jié)省篇幅忽略掉這個(gè)客戶(hù)端。
2)使用Jedis生成了一個(gè)新的連接,并執(zhí)行g(shù)et操作,可以看到IP地址為 10.7.40.98的客戶(hù)端,最后執(zhí)行的命令是get,age和idle分別是1秒和0秒
3)休息10秒,此時(shí)Jedis客戶(hù)端并沒(méi)有關(guān)閉,所以age和idle一直在遞 增:
4)執(zhí)行新的操作ping,發(fā)現(xiàn)執(zhí)行后age依然在增加,而idle從0計(jì)算,也 就是不再閑置
5)休息5秒,觀察age和idle增加:
6)關(guān)閉Jedis,Jedis連接已經(jīng)消失:
⑤客戶(hù)端類(lèi)型(flag)
client list中的flag是用于標(biāo)識(shí)當(dāng)前客戶(hù)端的類(lèi)型
例如flag=S代表當(dāng)前客 戶(hù)端是slave客戶(hù)端、flag=N代表當(dāng)前是普通客戶(hù)端,flag=O代表當(dāng)前客戶(hù)端 正在執(zhí)行monitor命令。下圖列出了11種客戶(hù)端類(lèi)型:
序號(hào) 客戶(hù)端類(lèi)型 說(shuō)明 l N 普通客戶(hù)端 2 M 當(dāng)前客戶(hù)端是master節(jié)點(diǎn) 3 s 當(dāng)前客戶(hù)端是slave節(jié)點(diǎn) 4 o 當(dāng)前客戶(hù)端正在執(zhí)行monitor命令 5 x 當(dāng)前客戶(hù)端正在執(zhí)行事務(wù) 6 b 當(dāng)前客戶(hù)端正在等得阻塞事件 7 i 當(dāng)前客戶(hù)端正在等待VM IO,但是此狀態(tài)目前已經(jīng)廢棄不用 8 d 一個(gè)受監(jiān)視的鍵已被修改,EXEC命令將失敷 9 u 客戶(hù)端未被阻察 10 c 回復(fù)完整輸出后,關(guān)閉連接 11 A 盡可能快地關(guān)閉連接?
二、client setName和client getName
client setName xxclient setName
client setName用于給客戶(hù)端設(shè)置名字,這樣比較容易標(biāo)識(shí)出客戶(hù)端的來(lái)源。例如將當(dāng)前客戶(hù)端命名為test_client,可以執(zhí)行如下操作:
此時(shí)再執(zhí)行client list命令,就可以看到當(dāng)前客戶(hù)端的name屬性為test_client:
client getName
client getName如果想直接查看當(dāng)前客戶(hù)端的name,可以使用client getName命令
第一次進(jìn)入客戶(hù)端時(shí),客戶(hù)端是沒(méi)有名字的,因此名字為空
更改名字之后,就可以看到更改后的名字了。例如:
client getName和setName命令可以做為標(biāo)識(shí)客戶(hù)端來(lái)源的一種方式,但是通常來(lái)講,在Redis只有一個(gè)應(yīng)用方使用的情況下,IP和端口作為標(biāo)識(shí)會(huì)更加清晰。當(dāng)多個(gè)應(yīng)用方共同使用一個(gè)Redis,那么此時(shí)client setName可以作為標(biāo)識(shí)客戶(hù)端的一個(gè)依據(jù)
三、client kill
client kill ip:port此命令用于殺掉指定IP地址和端口的客戶(hù)端
由于一些原因(例如設(shè)置timeout=0時(shí)產(chǎn)生的長(zhǎng)時(shí)間idle的客戶(hù)端),需要手動(dòng)殺掉客戶(hù)端連接時(shí),可以使用client kill命令
演示案例
例如左側(cè)為一個(gè)客戶(hù)端(127.0.0.1:34658),右側(cè)為一個(gè)客戶(hù)端(127.0.0.1:34660)
如果想殺掉127.0.0.1:34656的客戶(hù)端,可以執(zhí)行:
執(zhí)行命令后,client list結(jié)果只剩下了127.0.0.1:34658自己這個(gè)客戶(hù)端:
四、client pause
client pause timeout(毫秒)client pause命令用于阻塞客戶(hù)端timeout毫秒數(shù),在此期間客戶(hù)端連接將被阻塞。如下圖所示:
演示案例
例如在一個(gè)客戶(hù)端執(zhí)行下面的命令,在之后的10000毫秒內(nèi)的其他客戶(hù)端連接都會(huì)被阻塞
過(guò)一會(huì)后在另一個(gè)客戶(hù)端執(zhí)行ping命令,發(fā)現(xiàn)整個(gè)ping命令執(zhí)行了2.40秒(手動(dòng)執(zhí)行redis-cli,只為了演示,不代表真實(shí)執(zhí)行時(shí)間):
該命令可以在如下場(chǎng)景起到作用:
client pause只對(duì)普通和發(fā)布訂閱客戶(hù)端有效,對(duì)于主從復(fù)制(從節(jié)點(diǎn)內(nèi)部偽裝了一個(gè)客戶(hù)端)是無(wú)效的,也就是此期間主從復(fù)制是正常進(jìn)行的, 所以此命令可以用來(lái)讓主從復(fù)制保持一致
client pause可以用一種可控的方式將客戶(hù)端連接從一個(gè)Redis節(jié)點(diǎn)切換到另一個(gè)Redis節(jié)點(diǎn)
需要注意的是在生產(chǎn)環(huán)境中,暫停客戶(hù)端成本非常高
五、monitor
monitor命令用于監(jiān)控Redis正在執(zhí)行的命令?
演示案例
如下圖所示:
我們打開(kāi)了兩個(gè)redis-cli,右側(cè)先執(zhí)行monitor命令,左側(cè)再執(zhí)行其他命令
可以看到monitor命令能夠監(jiān)聽(tīng)其他客戶(hù)端正在執(zhí)行的命令,并記錄了詳細(xì)的時(shí)間戳
注意事項(xiàng):monitor的作用很明顯,如果開(kāi)發(fā)和運(yùn)維人員想監(jiān)聽(tīng)Redis正在執(zhí)行的命令,就可以用monitor命令,但事實(shí)并非如此美好,每個(gè)客戶(hù)端都有自己的輸出緩沖區(qū),既然monitor能監(jiān)聽(tīng)到所有的命令,一旦Redis的并發(fā)量過(guò)大, monitor客戶(hù)端的輸出緩沖會(huì)暴漲,可能瞬間會(huì)占用大量?jī)?nèi)存。
總結(jié)
以上是生活随笔為你收集整理的Redis:22---客户端API:client、monitor)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: C++(STL):16---deque之
- 下一篇: 使用Linux auto Makefil