1. 程式人生 > >Redis學習五(Redis 阻塞的原因及其排查方向).

Redis學習五(Redis 阻塞的原因及其排查方向).

## 一、慢查詢 因為 Redis 是單執行緒的,大量的慢查詢可能會導致 redis-server 阻塞,可以通過 slowlog get n 獲取慢日誌,檢視詳情情況。 ## 二、bigkey 大物件 bigkey 大物件可能會導致的問題包括: - 記憶體空間不均勻(平衡),例如在 Redis Cluster 中,bigkey 會造成節點的記憶體空間使用不均勻。 - 超時阻塞:由於Redis 單執行緒的特性,操作 bigkey 比較耗時,也就意味著阻塞 Redis 的可能性增大。 - 網路阻塞:每次獲取 bigkey 產生的網路流量較大,假設一個 bigkey 為 1MB,每次訪問量為 1000,那麼每秒產生 1000MB 的流量,對於普通的千兆網絡卡(按照位元組算是128MB/s)的伺服器簡直是滅頂之災。 ![](https://img2020.cnblogs.com/blog/1153954/202011/1153954-20201104142958472-624834492.png) bigkey 的存在並不是完全致命的,如果這個 bigkey 存在但是幾乎不被訪問,那麼只有記憶體空間不均勻的問題存在,相對於另外兩個問題沒有那麼重要緊急,但是如果 bigkey 是一個熱點key(頻繁訪問),那麼其帶來的危害不可想象,所以在實際開發和運維時一定要密切關注 bigkey 的存在。 可以通過 redis-cli -h {ip} -p {port} bigkeys 發現大物件。 ## 三、swap 因為 Redis 的資料放在記憶體中,所以存放資料量的多少取決於記憶體的多少。 如果一個 Redis 例項的記憶體使用率超過可用最大記憶體(used_memory > 可用最大記憶體),那麼作業系統開始進行記憶體和 swap 空間交換,把記憶體中舊的或不再使用的內容寫入硬碟上(硬碟上的這塊空間叫 Swap 分割槽),以便騰出新的實體記憶體給新頁使用。 在硬碟上進行讀寫操作要比記憶體上慢了近5個數量級 —— 記憶體是 0.1μs 單位、硬碟是 10ms。如果 Redis 程序上發生記憶體交換,那麼 Redis 和 依賴 Redis 上資料的應用會受到嚴重的效能影響。 檢視 used_memory 指標可知道 Redis 正在使用的記憶體情況,識別 Redis 記憶體交換的檢查方法: 1. 識別 redis 程序號 > redis-cli info server | grep process_id 2. 根據程序號查詢記憶體交換資訊 > cat /proc/{process_id}/smaps | grep Swap 如果交換量都是 0KB 或者個別 4KB,是正常現象。 預防記憶體交換: 1. 保證機器充足的可用記憶體; 2. 確保所有 redis 示例設定最大可用記憶體(maxmemory),防止極端情況下 redis 記憶體不可控的增長; 3. 降低系統使用 swap 優先順序,如 echo 10>/proc/sys/vm/swappiness。 ## 四、fork 子程序 在 RDB 生成和 AOF 重寫時,會 fork 一個子程序完成持久化工作,當 fork 操作執行太過耗時也會造成阻塞,阻塞原因是該操作會複製父程序的空間記憶體表,即 fork 操作耗時跟記憶體量(資料集)關係較大。 fork 操作是重量級操作,會複製父程序的空間記憶體表(理論上需要複製與父程序同樣的記憶體,但是 linux 有寫時複製機制,父子程序貢獻相同的實體記憶體頁,實際會小很多,10G 大概只需要 20MB)。 fork 耗時應該在 20ms/GB;應該嚴格控制每個例項可使用的最大記憶體 10GB 以內(複製空間記憶體表);降低 fork 操作執行頻率,適當放寬 AOF 重寫觸發時機。 使用 info stats 命令獲取 lastest_fork_usec 指標,表示 redis 最近一次 fork 操作耗時。 ## 五、AOF 刷盤阻塞 開啟 AOF,檔案刷盤一般每秒一次,硬碟壓力過大時,fsync 需要等待寫入完成。 檢視 redis 日誌或 info persistence 統計中的 aof_delayed_fsync 指標。 ## 六、Redis 輸入緩衝區可能導致的阻塞 輸入緩衝區:redis 為每個客戶端分配了輸入緩衝區,其會將客戶端傳送命令臨時儲存,然後取出來執行。 qbuf 表示總容量(0 表示沒有分配查詢緩衝區),qbuf-free 表示剩餘容量(0 表示沒有剩餘空間);大小不能超過 1G,當大小超過 1G 時會將客戶端自動關閉,輸入緩衝區不受 maxmemory 限制。 當大量的 key 進入輸入緩衝區且無法被消費時,即可造成 redis 阻塞;通過 client list 命令可定位發生阻塞的客戶端;通過 info clients 命令的 blocked_clients 引數可以檢視到當前阻塞的命令。 ![](https://img2020.cnblogs.com/blog/1153954/202011/1153954-20201104103236870-356331761.png) ![](https://img2020.cnblogs.com/blog/1153954/202011/1153954-20201104103217330-2146704053.png) ## 七、Redis 輸出緩衝區可能導致的阻塞 輸出緩衝區(client output buffer):是 redis-server 端實現的一個讀取緩衝區,redis-server 在接收到客戶端的請求後,把獲取結果寫入到 client buffer 中,而不是直接傳送給客戶端。從而可以繼續處理客戶端的其他請求,這樣非同步處理方式使 redis-server 不會因為網路原因阻塞其他請求的處理。 redis client buffer 的配置引數為 "client-output-buffer-limit",預設值為: ``` 127.0.0.1:6379> CONFIG GET "*output*" 1) "client-output-buffer-limit" 2) "normal 0 0 0 slave 0 0 0 pubsub 0 0 0" ``` - class :客戶端種類,normal、slave、pubsub - normal:普通的客戶端 - slave: 從庫的複製客戶端 - pub/sub: 釋出與訂閱的客戶端 - hard limit: 緩衝區大小的硬性限制。 - soft limit: 緩衝去大小的軟性限制。 - soft seconds: 緩衝區大小達到了(超過)soft limit 值的持續時間。 client-output-buffer-limit 引數限制分配的緩衝區的大小,防止記憶體無節制的分配。引數的預設值都為 0,意思是不做任何限制。 redis server 觸發保護機制主要有兩種情況: 1) client buffer 的大小達到了 soft limit 並持續了 soft seconds 時間,將立即斷開和客戶端的連線。 2) client buffer 的大小達到了 hard limit,server 也會立即斷開和客戶端的連線。 ## 八、網路問題 ### 1. 連線拒絕 - 網路閃斷:一般在網路割接或頻寬耗盡的情況; - redis 連線拒絕:連線數大於 maxclients 時拒絕新的連線進入,可以關注 info stats 的 rejected_connections 指標; - 連線溢位: - 程序限制:程序可開啟最大檔案數控制 —— ulimit -n,通常 1024,大量連線的 redis 需要增大該值; - backlog 佇列溢位:系統對於特定埠 tcp 連線使用 backlog 佇列儲存,redis 預設 511,系統 backlog 預設 128,線上可使用 cron 定時執行 netstat -s | grep overflowed 統計; ### 2. 網路延遲 測量機器之間的網路延遲 > redis-cli -h {ip} -p {port} –latency redis-cli -h {ip} -p {port} –latency-history 預設15秒完成一行統計,-i控制取樣時間 redis-cli -h {ip} -p {port} –latency-dist 統計圖展示,每1秒採