Redis效能篇(三)Redis關鍵系統配置:如何應對Redis變慢

大雜草發表於2021-01-12

Redis被廣泛使用的一個很重要的原因是它的高效能。因此我們必要要重視所有可能影響Redis效能的因素、機制以及應對方案。影響Redis效能的五大方面的潛在因素,分別是:

在前面的2講中,學習了會導致Redis變慢的潛在阻塞點以及相應的解決方案,即非同步執行緒機制和CPU綁核。除此之外,還有一些因素會導致Redis變慢。

這一講,介紹如何系統性應對Redis變慢這個問題。從問題認定、系統性排查和應對方案這3個方面來講解。

判斷Redis是否變慢?

最直接的方法,檢視Redis的響應延遲。通過絕對值來判斷,比如執行時間突然增長到幾秒。

但是這個方法在不同配置的機器上的誤差比較大。第二個方法是基於當前環境下的Redis基線效能做判斷。

基線效能指一個系統在低壓力、無干擾下的基本效能。

怎麼確定基線效能?從2.8.7版本開始,redis-cli命令提供了-intrinsic-latency選項,可以用來監測和統計測試期間內的最大延遲,這個延遲可以作為Redis的基線效能。其中,測試時長可以用-intrinsic-latency選項的引數來指定。

一般來說,執行時延和基線效能對比,如果執行時延是基線效能的2倍及以上時,就可以認定Redis變慢了。為了避免網路對基線效能的影響,直接在伺服器端執行。

如何應對Redis變慢?

影響Redis的關鍵因素有三個:Redis自身的操作特性、檔案系統和作業系統。

Redis自身操作特性的影響

Redis有兩個操作會對效能造成較大影響,分別是慢查詢命令和過期key操作。

慢查詢命令

慢查詢命令,就是指在Redis中執行速度慢的命令,這會導致Redis延遲增加。

排查:通過Redis日誌、或者是latency monitor工具。

解決方法

  • 用其他高效命令代替。比如不要使用SMEMBERS命令,而是用SSCAN多次迭代返回;
  • 當需要執行排序、交集、並集操作時,可以在客戶端完成,而不要用SORT、SUNION、SINTER這些命令

還有一個比較容易遺漏的慢查詢命令是KEYS命令,它用於返回和輸入模式的所有key。因為KEYS命令需要遍歷儲存的鍵值對,所以操作延時高。KEYS命令一般不被建議用於生產環境中

過期key操作

過期key的自動刪除機制,它是Redis用來回收記憶體空間的常用機制,本身會引起Redis操作阻塞,導致效能變慢。

排查:檢查業務程式碼在使用EXPIREAT命令設定key過期時間時,是否使用了相同的UNIX時間戳。因為這會造成大量key在同一時間過期,導致效能變慢。

解決方法

  • 根據實際業務需求來決定EXPIREAT和EXPIRE的過期時間引數。
  • 如果一批key的確是同時過期,可以在EXPIREAT和EXPIRE的過期時間引數上,加上一個一定大小範圍內的隨機引數

檔案系統的影響

在基礎篇講過,為了保證資料可靠性,Redis會採用AOF日誌或者RDB快照。其中,AOF日誌提供了三種日誌寫回策略:no、everysec、always。這三種寫回策略依賴檔案系統的兩個系統呼叫完成:write和fsync。

  • write只要把日誌記錄寫到核心緩衝區即可;
  • fsync需要把日誌記錄寫回磁碟,時間較長。

image

排查

  • 首先,檢查Redis配置檔案中的appendfsync配置項;
  • 其次,確認業務對資料可靠性的要求是否需要每一秒或每一個操作都記日誌。

解決方法

如果業務應用對延遲非常敏感,但同時允許一定量的資料丟失,把配置項no-appendfsync-on-rewrite設定為yes:

no-appendfsync-on-rewrite yes

如果的確需要高效能,同時也需要高可靠資料保證,考慮採用高速的固態硬碟作為AOF日誌的寫入裝置。

作業系統的影響

swap

一個潛在的瓶頸:作業系統的記憶體swap。

記憶體swap是作業系統裡將記憶體資料在記憶體和磁碟間來回換入和換出的機制,涉及到磁碟的讀寫。

Redis一旦swap被觸發,Redis的請求操作需要等到磁碟資料讀寫完成。並且swap觸發後影響的是Redis主IO執行緒,這會極大地增加Redis的響應時間。

通常觸發swap的原因主要是物理機器記憶體不足

排查

首先,查詢Redis的程式號:

$ redis-cli info | grep process_id process_id: 5332

其次,進入Redis所在機器的/proc目錄下的該程式目錄中:

$ cd /proc/5332

最後,執行下面命令,檢視Redis程式的使用情況:

$cat smaps | egrep '^(Swap|Size)'
Size: 584 kB
Swap: 0 kB
Size: 4 kB
Swap: 4 kB
Size: 4 kB
Swap: 0 kB
Size: 462044 kB
Swap: 462008 kB
Size: 21392 kB
Swap: 0 kB

解決方法:增加機器的記憶體或者使用Redis叢集。

記憶體大頁

還有一個和記憶體相關的因素,即記憶體大頁機制(Transparent Huge Page,THP),也會影響Redis效能。

排查

首先,在Redis例項執行的機器上執行:

cat /sys/kernel/mm/transparent_hugepage/enabled

如果,執行結果是always,表示記憶體大頁機制啟動了;如果是never,表示禁止了。

解決方法:關閉記憶體大頁。

echo never /sys/kernel/mm/transparent_hugepage/enabled

總結

總結一份關於Redis變慢的Checklist:

  1. 獲取Redis例項在當前環境下的基線效能。
  2. 是否用了慢查詢命令?如果是的話,就使用其他命令替代慢查詢命令,或者把聚合計算命令放在客戶端做。
  3. 是否對過期key設定了相同的過期時間?對於批量刪除的key,可以在每個key的過期時間上加一個隨機數,避免同時刪除。
  4. 是否存在bigkey? 對於bigkey的刪除操作,如果你的Redis是4.0及以上的版本,可以直接利用非同步執行緒機制減少主執行緒阻塞;如果是Redis 4.0以前的版本,可以使用SCAN命令迭代刪除;對於bigkey的集合查詢和聚合操作,可以使用SCAN命令在客戶端完成。
  5. Redis AOF配置級別是什麼?業務層面是否的確需要這一可靠性級別?如果我們需要高效能,同時也允許資料丟失,可以將配置項no-appendfsync-on-rewrite設定為yes,避免AOF重寫和fsync競爭磁碟IO資源,導致Redis延遲增加。當然, 如果既需要高效能又需要高可靠性,最好使用高速固態盤作為AOF日誌的寫入盤。
  6. Redis例項的記憶體使用是否過大?發生swap了嗎?如果是的話,就增加機器記憶體,或者是使用Redis叢集,分攤單機Redis的鍵值對數量和記憶體壓力。同時,要避免出現Redis和其他記憶體需求大的應用共享機器的情況。
  7. 在Redis例項的執行環境中,是否啟用了透明大頁機制?如果是的話,直接關閉記憶體大頁機制就行了。
  8. 是否執行了Redis主從叢集?如果是的話,把主庫例項的資料量大小控制在2~4GB,以免主從複製時,從庫因載入大的RDB檔案而阻塞。
  9. 是否使用了多核CPU或NUMA架構的機器執行Redis例項?使用多核CPU時,可以給Redis例項繫結物理核;使用NUMA架構時,注意把Redis例項和網路中斷處理程式執行在同一個CPU Socket上。

參考資料

相關文章