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

JMCui發表於2020-11-04

一、慢查詢

因為 Redis 是單執行緒的,大量的慢查詢可能會導致 redis-server 阻塞,可以通過 slowlog get n 獲取慢日誌,檢視詳情情況。

二、bigkey 大物件

bigkey 大物件可能會導致的問題包括:

  • 記憶體空間不均勻(平衡),例如在 Redis Cluster 中,bigkey 會造成節點的記憶體空間使用不均勻。
  • 超時阻塞:由於Redis 單執行緒的特性,操作 bigkey 比較耗時,也就意味著阻塞 Redis 的可能性增大。
  • 網路阻塞:每次獲取 bigkey 產生的網路流量較大,假設一個 bigkey 為 1MB,每次訪問量為 1000,那麼每秒產生 1000MB 的流量,對於普通的千兆網路卡(按照位元組算是128MB/s)的伺服器簡直是滅頂之災。

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

  1. 根據程式號查詢記憶體交換資訊

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 引數可以檢視到當前阻塞的命令。

七、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秒取樣一次

相關文章