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