《Redis开发与运维》----- 客户端
文章目錄
- 一、客戶端通信協(xié)議
- 二、客戶端管理
- 2.1 客戶端API
- 1. client list
- 2.client setName和client getName
- 3.client kill ip:port
- 4.client pause timeout(毫秒)
- 5.monitor用于監(jiān)控Redis正在執(zhí)行的命令
- 2.2 客戶端相關(guān)配置
- 2.3 客戶端統(tǒng)計
- 三、客戶端常見異常
- 3.1 無法從連接池獲取到連接
- 3.2 客戶端讀寫超時,SocketTimeoutException: Read timed out
- 3.3 客戶端連接超時,SocketTimeoutException: connect timed out
- 3.4 客戶端緩沖區(qū)異常
- 3.5 Lua腳本正在執(zhí)行
- 3.6 Redis正在加載持久化文件
- 3.7 Redis使用的內(nèi)存超過maxmemory配置
- 3.8 客戶端連接數(shù)過大
- 四、客戶端案例分析
- 4.1 Redis主節(jié)點內(nèi)存陡增
- 4.2 客戶端周期性超時
一、客戶端通信協(xié)議
客戶端與服務端之間的通訊協(xié)議是建立在TCP協(xié)議之上的。Redis制定了RESP(REdis Serialization Protocol, Redis序列化協(xié)議) 實現(xiàn)客戶端與服務端的正常交互。
二、客戶端管理
2.1 客戶端API
1. client list
-
id:客戶端連接唯一標識
-
addr: 連接的IP和端口
-
fd:socket的文件描述符
-
name:客戶端的名字
-
age:客戶端已經(jīng)連接的時間
-
idle:客戶端最近一次的空閑時間,當age等于idle時,說明連接一直處于空閑狀態(tài)
-
輸入緩沖區(qū)(將客戶端發(fā)送的命令臨時保存): qbuf(總?cè)萘?#xff09;、 qbuf-free(剩余容量)
-
輸入緩沖使用不當會產(chǎn)生兩個問題:
1、一旦某個客戶端的輸入緩沖區(qū)超過1G, 客戶端將會被關(guān)閉。
2、輸入緩沖區(qū)不受maxmemory控制,一旦超過maxmemory限制, 可能會產(chǎn)生數(shù)據(jù)丟失、 鍵值淘汰、 OOM等情況 -
輸出緩沖區(qū)(保存命令執(zhí)行的結(jié)果返回給客戶端):obl(固定緩沖區(qū)長度)、 oll(動態(tài)緩沖區(qū)長度)、 omem(使用的字節(jié)數(shù))
-
輸出緩沖區(qū)由兩部分組成: 固定緩沖區(qū)(16KB) 和動態(tài)緩沖區(qū), 其中固定緩沖區(qū)返回比較小的執(zhí)行結(jié)果, 而動態(tài)緩沖區(qū)返回比較大的結(jié)果。輸出緩沖區(qū)的容量可以通過參數(shù)client-outputbuffer-limit來進行設(shè)置,輸出緩沖區(qū)也不會受到maxmemory的限制
-
輸出緩沖區(qū)出現(xiàn)異常的概率相對會比較大,如何預防?
1、進行監(jiān)控, 設(shè)置閥值, 超過閥值及時處理
2、限制普通客戶端輸出緩沖區(qū)的, 把錯誤扼殺在搖籃中
3、適當增大slave的輸出緩沖區(qū)的,master節(jié)點寫入較大, slave客戶端的輸出緩沖區(qū)可能會比較大,一旦slave客戶端連接因為輸出緩沖區(qū)溢出被kill, 會造成復制重連
4、限制容易讓輸出緩沖區(qū)增大的命令, 例如,高并發(fā)下的monitor命令就是一個危險的命令。
5、及時監(jiān)控內(nèi)存, 一旦發(fā)現(xiàn)內(nèi)存抖動頻繁, 可能就是輸出緩沖區(qū)過大。 -
監(jiān)控輸入、輸出緩沖區(qū)異常的方法有兩種:
1、通過定期執(zhí)行client list命令,收集異常的連接記錄并分析,最終找到可能出問題的客戶端。該命令能精準定位客戶端,但是執(zhí)行速度較慢,頻繁指定可能阻塞redis
2、通過info命令的info clients模塊,該命令定位不精準,但執(zhí)行速度快。
2.client setName和client getName
client setName用于給客戶端設(shè)置名字, 這樣比較容易標識出客戶端的來源。
3.client kill ip:port
此命令用于殺掉指定IP地址和端口的客戶端。
4.client pause timeout(毫秒)
client pause命令用于阻塞客戶端timeout毫秒數(shù),在此期間客戶端連接將被阻塞。生產(chǎn)環(huán)境中,暫停客戶端成本非常高。
該命令可以在如下場景起到作用:
- 1、client pause只對普通和發(fā)布訂閱客戶端有效,對于主從復制(從節(jié)點內(nèi)部偽裝了一個客戶端)是無效的,也就是此期間主從復制是正常進行的,此命令可以用來讓主從復制保持一致
- 2、client pause可以用一種可控的方式將客戶端連接從一個Redis節(jié)點切換到另一個Redis節(jié)點。
5.monitor用于監(jiān)控Redis正在執(zhí)行的命令
每個客戶端都有自己的輸出緩沖區(qū), 既然monitor能監(jiān)聽到所有的命令, 一旦Redis的并發(fā)量過大,monitor客戶端的輸出緩沖會暴漲, 可能瞬間會占用大量內(nèi)存
2.2 客戶端相關(guān)配置
- timeout:檢測客戶端空閑連接的超時時間
- maxclients:客戶端最大連接數(shù)
- tcp-keepalive:檢測TCP連接活性的周期,默認0,即不檢測
- tcp-backlog:TCP三次握手后,會將接受的連接放入隊列中,tcp-backlog就是隊列的大小
2.3 客戶端統(tǒng)計
- info clients
connected_clients:代表當前Redis節(jié)點的客戶端連接數(shù),需要重點監(jiān)控,一旦超過maxclients,新的客戶端連接將被拒絕。
client_longest_output_list: 當前所有輸出緩沖區(qū)中隊列對象個數(shù)的最大值。
client_biggest_input_buf: 當前所有輸入緩沖區(qū)中占用的最大容量。
blocked_clients:正在執(zhí)行阻塞命令(例如blpop、 brpop、brpoplpush)的客戶端個數(shù)。
- info stats
total_connections_received: Redis自啟動以來處理的客戶端連接數(shù)總數(shù)
rejected_connections: Redis自啟動以來拒絕的客戶端連接數(shù), 需要重點監(jiān)控
三、客戶端常見異常
3.1 無法從連接池獲取到連接
JedisPool中的Jedis對象個數(shù)是有限的, 默認是8個。如果連接池中沒有空閑Jedis對象,新的請求就需要進行等待(例如設(shè)置了maxWaitMillis>0)
在maxWaitMillis時間內(nèi)仍然無法獲取到Jedis對象就會拋出異常:JedisConnectionException: Could not get a resource from the pool
如果設(shè)置了blockWhenExhausted=false, 那么調(diào)用者發(fā)現(xiàn)池子中沒有資源時, 會立即拋出異常不進行等待
造成沒有資源的原因非常多:
客戶端: 高并發(fā)下連接池設(shè)置過小, 出現(xiàn)供不應求
客戶端: 沒有正確使用連接池, 比如沒有進行釋放
客戶端: 存在慢查詢操作, 這些慢查詢持有的Jedis對象歸還速度會比較慢,造成池子滿了
服務端: 客戶端是正常的, 但是Redis服務端由于一些原因造成了客戶端命令執(zhí)行過程的阻塞
3.2 客戶端讀寫超時,SocketTimeoutException: Read timed out
造成該異常的原因也有以下幾種:
·讀寫超時間設(shè)置得過短。
·命令本身就比較慢。
·客戶端與服務端網(wǎng)絡不正常。
·Redis自身發(fā)生阻塞。
3.3 客戶端連接超時,SocketTimeoutException: connect timed out
造成該異常的原因也有以下幾種:
連接超時設(shè)置得過短, 可以通過下面代碼進行設(shè)置:jedis.getClient().setConnectionTimeout(time);
Redis發(fā)生阻塞, 造成tcp-backlog已滿, 造成新的連接失敗。
客戶端與服務端網(wǎng)絡不正常。
3.4 客戶端緩沖區(qū)異常
造成這個異常的原因可能有如下幾種:
輸出緩沖區(qū)滿。
長時間閑置連接被服務端主動斷開
不正常并發(fā)讀寫: Jedis對象同時被多個線程并發(fā)操作, 可能會出現(xiàn)上述異常
3.5 Lua腳本正在執(zhí)行
如果Redis當前正在執(zhí)行Lua腳本, 并且超過了lua-time-limit, 此時Jedis調(diào)用Redis時, 會收到下面的異常。
JedisDataException: BUSY Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE.
3.6 Redis正在加載持久化文件
Jedis調(diào)用Redis時, 如果Redis正在加載持久化文件, 那么會收到下面的異常:
JedisDataException: LOADING Redis is loading the dataset in memory
3.7 Redis使用的內(nèi)存超過maxmemory配置
Jedis執(zhí)行寫操作時, 如果Redis的使用內(nèi)存大于maxmemory的設(shè)置, 會收到下面的異常, 此時應該調(diào)整maxmemory并找到造成內(nèi)存增長的原因
JedisDataException: OOM command not allowed when used memory > ‘maxmemory’.
3.8 客戶端連接數(shù)過大
如果客戶端連接數(shù)超過了maxclients, 新申請的連接就會出現(xiàn)如下異常:JedisDataException: ERR max number of clients reached
一般來說可以從兩個方面進行著手解決:
但是無論從哪個方面進行處理, 故障的快速恢復極為重要, 當然更為重要的是找到問題的所在, 否則一段時間后客戶端連接數(shù)依然會超過maxclients。
四、客戶端案例分析
4.1 Redis主節(jié)點內(nèi)存陡增
- 服務端現(xiàn)象: Redis主節(jié)點內(nèi)存陡增, 幾乎用滿maxmemory, 而從節(jié)點內(nèi)存并沒有變化
- 客戶端現(xiàn)象: 客戶端產(chǎn)生了OOM異常, 也就是Redis主節(jié)點使用的內(nèi)存已經(jīng)超過了maxmemory的設(shè)置, 無法寫入新的數(shù)據(jù)
- 分析原因:
1、確實有大量寫入, 但是主從復制出現(xiàn)問題: 查詢了Redis復制的相關(guān)信息, 復制是正常的, 主從數(shù)據(jù)基本一致。主從的鍵個數(shù)基本一致,使用dbsize命令
2、其他原因造成主節(jié)點內(nèi)存使用過大: 排查是否由客戶端緩沖區(qū)造成主節(jié)點內(nèi)存陡增, 使用info clients命令發(fā)現(xiàn)客戶端輸出緩沖區(qū)不正常:client_longest_output_list:225698,通過client list命令找到omem不正常的連接, 一般來說大部分客戶端的omem為0,redis-cli client list | grep -v "omem=0"
3、最后發(fā)現(xiàn)是因為有客戶端在執(zhí)行monitor命令造成的
4.2 客戶端周期性超時
- 客戶端現(xiàn)象: 客戶端出現(xiàn)大量超時, 經(jīng)過分析發(fā)現(xiàn)超時是周期性出現(xiàn)的
- 服務端現(xiàn)象: 服務端并沒有明顯的異常, 只是有一些慢查詢操作
- 原因分析:
1、網(wǎng)絡原因: 服務端和客戶端之間的網(wǎng)絡出現(xiàn)周期性問題, 經(jīng)過觀察網(wǎng)絡是正常的
2、客戶端: 由于是周期性出現(xiàn)問題, 就和慢查詢?nèi)罩镜臍v史記錄對應了一下時間, 發(fā)現(xiàn)只要慢查詢出現(xiàn), 客戶端就會產(chǎn)生大量連接超時, 兩個時間點基本一致。
3、最終找到問題是慢查詢操作造成的, 通過執(zhí)行hlen發(fā)現(xiàn)有200萬個元素, 這種操作必然會造成Redis阻塞, 另外確認了有定時任務代碼每5分鐘執(zhí)行一次hgetall操作
總結(jié)
以上是生活随笔為你收集整理的《Redis开发与运维》----- 客户端的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Redis开发与运维教程
- 下一篇: Redis开发与运维