Redis緩衝區溢位及解決方案

邴越發表於2023-04-12

緩衝區(buffer),是記憶體空間的一部分。也就是說,在記憶體空間中預留了一定的儲存空間,這些儲存空間用來緩衝輸入或輸出的資料,這部分預留的空間就叫做緩衝區。

一、Redis緩衝區溢位影響

在Redis中,主要有三個場景用到了緩衝區的概念。

  • 在客戶端和伺服器端之間進行通訊時,用來暫存客戶端傳送的命令資料,或者是伺服器端返回給客戶端的資料結果
  • 在主從節點間進行資料同步時,Redis使用緩衝區來暫存主節點接收的寫命令和資料
  • 在Redis進行AOF持久化的時候Redis為了避免頻繁寫磁碟同樣用到了緩衝區的概念

 

緩衝區概念最初是作業系統為了緩和 CPU 與 I/O 裝置速度不匹配的矛盾,提高 CPU 和 I/O 裝置的並行性而引入的。

 

對於高速裝置與低速裝置的不匹配,勢必會讓高速裝置花時間等待低速裝置。有了緩衝區的概念就可以很好的解決這個問題。緩衝區也是生產者消費者模式的重要體現。

 

 

 

1、緩衝區溢位導致網路連線關閉

 

如果 qubf-free 耗盡,就會引起客戶端輸入緩衝區溢位,Redis 的處理方法就是把客戶端連線關閉,導致的結果就是業務程式無法進行資料存取。

2、緩衝區溢位導致命令資料丟失或者崩潰

 

通常情況下,會有很多的客戶端連線,當客戶端連線佔用的記憶體總量,超過了 Redis 的 maxmemory 配置時,就會觸發 Redis 進行資料淘汰,影響業務程式的訪問效能。

 

甚至多個客戶端會導致 Redis 記憶體佔用過大,也會導致記憶體溢位問題,進而引起 Redis 崩潰。

 

二、客戶端緩衝區

 

客戶端緩衝區又有兩個,輸入緩衝區和輸出緩衝區,都是為了解決客戶端和伺服器端的請求傳送和處理速度不匹配所設定的。

 

 

 

 

 

輸入緩衝區暫存的是客戶端發來的命令,其常見的溢位原因有兩個:

  1. 寫入了BigKey,如一次性寫入了百萬級別的雜湊或集合資料,超過了緩衝區的大小
  2. 服務端處理請求的速度過慢導致阻塞,無法及時處理請求,使得客戶端傳送的請求在緩衝區內越積越多。

輸出緩衝區暫存的是 Redis 主執行緒要返回給客戶端的資料。

 

這個資料,既有簡單且大小固定的 OK 響應(例如,執行 SET 命令)或報錯資訊,也有大小不固定的、包含具體資料的執行結果(例如,執行 HGET 命令)

 

輸出緩衝區常見的溢位原因有三種:

  1. 返回BigKey的大量結果
  2. 執行了某些不合理的命令
  3. 緩衝區大小設定不合理

 

從輸入和輸出緩衝區常見導致溢位的原因來看,BigKey是最可能導致溢位的原因,因此我們應該儘量避免使用BigKey。

 

對於輸入緩衝區,因為沒有辦法改變其大小(預設每個客戶端1G),我們只能透過控制命令的傳送和處理速度入手,儘量避免阻塞。

 

對於輸出緩衝區則要避免一些返回大量結果的命令的使用如KEYS,MONITOR等,同時可以透過調整輸出緩衝區的大小來避免溢位。

 

三、複製緩衝區

 

複製緩衝區是用於Redis主從節點之間複製時使用的。由於主從節點間的資料複製包括全量複製和增量複製兩種。因此複製緩衝區也分為複製緩衝區和複製積壓緩衝區兩種。

 

1、複製緩衝區

在全量複製過程中,主節點在向從節點傳輸 RDB 檔案的同時,會繼續接收客戶端傳送的寫命令請求。這些寫命令就會先儲存在複製緩衝區中,等 RDB 檔案傳輸完成後,再傳送給從節點去執行。主節點上會為每個從節點都維護一個複製緩衝區,來保證主從節點間的資料同步。

 

 

對於複製緩衝區,如果主庫傳輸 RDB 檔案以及從庫載入 RDB 檔案耗時長,同時主庫接收的寫命令操作較多,就會導致複製緩衝區被寫滿而溢位。

 

想要避免複製緩衝區溢位,一方面我們可以控制主節點儲存的資料量大小,這樣可以讓RDB檔案的傳輸以及從庫載入時間變快,以避免複製緩衝區累積過多命令。

 

也可以根據主節點的資料量大小、主節點的寫負載壓力和主節點本身的記憶體大小來更合理的設定複製緩衝區的大小來避免溢位,此外,由於主節點會為每一個從節點設定一個複製緩衝區,如果叢集中的從節點數非常多的話,主節點的記憶體開銷就會非常大,因此我們應該儘量避免一個主節點有過多的從節點。

 

2、複製積壓緩衝區

 

增量複製時,主節點和從節點進行常規同步時,會把寫命令也暫存在複製積壓緩衝區中。如果從節點和主節點間發生了網路斷連,等從節點再次連線後,可以從複製積壓緩衝區中同步尚未複製的命令操作。

 

 

 

 

需要注意的是複製積壓緩衝區是一個大小有限的環形緩衝區。

 

當主節點把複製積壓緩衝區寫滿後,會覆蓋緩衝區中的舊命令資料。此時會造成主從節點的資料不一致。

 

針對這個問題,一般的應對的方法是調大複製積壓緩衝區的大小,這個大小的計算方式一般可以使用

緩衝區大小=(主庫寫入命令速度 * 操作大小 - 主從庫間網路傳輸命令速度 * 操作大小)* 2

如果如果併發請求量非常大,調整緩衝區大小的方式還不能解決,那麼可以考慮使用切片叢集的方式解決

 

四、AOF緩衝區

 

AOF緩衝區是Redis在AOF持久化的所設定的緩衝區,AOF緩衝區也有兩種AOF緩衝區和AOF重寫緩衝區。

 

1、AOF緩衝區

我們都知道,即使是固態硬碟,它的讀寫速度也是與記憶體的讀寫速度相差很多的。AOF緩衝區就主要是Redis用來解決主程式執行命令速度與磁碟寫入速度不同步所設定的,透過AOF緩衝區可以有效地避免頻繁對硬碟進行讀寫,進而提升效能。Redis在AOF持久化的時候,會先把命令寫入到AOF緩衝區,然後透過回寫策略來寫入硬碟AOF檔案。

 

 

 

AOF緩衝區的溢位可能與磁碟寫入速度有關係,也可能與AOF回寫策略有關係,當大量命令積壓在AOF緩衝區,超過其設定閾值之後,就會導致緩衝區溢位,想要避免這個問題,我們可以透過調整回寫策略,或者調整AOF緩衝區大小的方式來解決。

 

2、AOF重寫緩衝區

AOF重寫緩衝區是Redis在子程式進行AOF重寫的時候,父程式接受了新的命令,此時會把命令寫入AOF重寫緩衝區,等到子程式重寫完成後,把AOF重寫緩衝區命令追加到新的AOF檔案中。

 

 

 

 AOF重寫緩衝區的溢位與AOF重寫期間主程式所處理的命令數有關係,當AOF重寫期間Redis主程式處理了大量的命令,這些命令都會寫入AOF重寫緩衝區,當超過設定閾值之後,就會導致溢位。

避免AOF重寫緩衝區的溢位我們也可以透過調整AOF重寫緩衝區的大小來解決。

 

五、總結

這篇文章總結了緩衝區的概念,分析了Redis的三個緩衝區,以及可能造成其溢位的原因和解決辦法。

對於緩衝區溢位其實主要有兩種原因,一是緩衝區大小不夠,二是消費者處理的速度太慢,而生產者生產的太快,導致大量內容積壓在緩衝區,進而導致溢位。

而解決方案就可以透過調整緩衝區的大小,或者調整生產者與消費者之間生產與處理訊息的速度,使其處於一個相對平衡的狀態。

相關文章