Redis效能篇(四)Redis記憶體碎片

大雜草發表於2021-01-13

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

這一講學習Redis的記憶體空間儲存效率問題,探索一下,為什麼資料已經刪除了,但記憶體卻閒置著沒有用,以及相應的解決方案。

什麼是記憶體碎片

我們用高鐵車廂說明,假設一個車廂的座位總共有60個,現在已經賣 了57張票,需要三張連在一起的票,但發現買不到了,只好換一趟車。我們可以把這些分散的空座位叫作“車廂座位碎片”。

記憶體碎片類似上面高鐵座位的例子。雖然作業系統的剩餘空間總量足夠,但申請一塊連續地址空間N位元組時,剩餘記憶體空間中沒有大小為N位元組的連續空間,那麼這些剩餘空間就是記憶體碎片

記憶體碎片是如何形成的?

記憶體碎片形成有內因和外因。

內因:記憶體分配器的分配策略

記憶體分配器的分配策略決定作業系統無法做到“按需分配”。記憶體分配器必須分配一塊固定大小的連續記憶體空間。

以jemalloc為例,是按照一系列固定的大小劃分記憶體空間,例如8位元組、16位元組、32位元組、...、2KB、4KB等。當程式申請的記憶體最接近某個固定值時,jemalloc就會給它分配相應大小的空間。

外因:鍵值對大小不一樣和刪改操作

一是,前面講到,記憶體分配器只能按照固定大小分配記憶體,所以,分配的記憶體空間一般都會比申請的空間大一些,不會完全一致,這本身就千萬一定的碎片,降低記憶體空間儲存效率。

二是,這些鍵值被修改和刪除,會導致空間的擴容和釋放。

大量記憶體碎片的存在,會造成Redis的記憶體實際利用率變低。那如何解決這些記憶體碎片呢?在此之前,我們先來學習如何判斷是否有記憶體碎片。

如何判斷是否有記憶體碎片?

Redis提供INFO命令,用來查詢記憶體使用的詳細資訊,命令如下:

INFO memory
# Memory
used_memory:1073741736
used_memory_human:1024.00M
used_memory_rss:1997159792
used_memory_rss_human:1.86G
…
mem_fragmentation_ratio:1.86
  • mem_fragmentation_ratio,表示Redis當前的記憶體碎片率;
  • used_memory_rss,表示作業系統實際分配給Redis的實體記憶體空間,裡面包含了碎片;
  • used_memory,表示Redis為了儲存資料實際申請使用的空間。

如何使用這個指標?

  • mem_fragmentation_ratio 大於1但小於1.5。這種情況是合理的。
  • mem_fragmentation_ratio 大於 1.5 。這表明記憶體碎片率已經超過了50%。一般情況下,這個時候,我們就需要採取一些措施來降低記憶體碎片率了。

下面介紹如何清理記憶體碎片了。

如何清理記憶體碎片?

一個“簡單粗暴”的方法是重啟Redis例項。但是這個方法會帶來兩個後果:

  • 如果Redis中的資料沒有持久化,資料會丟失;
  • 即使Redis資料持久化了,還需要通過AOF或者RDB來恢復,恢復時長取決於AOF或RDB的大小。並且如果只有一個Redis例項,恢復階段無法提供服務。

那有沒有更好的方法呢?有的,從4.0-RC3版本以後,Redis自身提供了一種記憶體碎片自動清理的方法。

記憶體碎片自動清理

記憶體碎片清理,簡單來說,就是“搬家讓位,合併空間”。

當有資料把一塊連續的記憶體空間分割成好幾塊不連續的空間時,作業系統會把資料拷貝到另外,而原來不連續的記憶體空間就變成連續的記憶體空間了。

但是碎片清理是有代價的。作業系統需要把多份資料拷貝到新位置,把原有空間釋放出來,這會帶來時間開銷。另外在資料拷貝時,會阻塞Redis,降低效能。

如何緩解這個問題?

Redis專門為自動記憶體碎片清理機制提供引數設定。可以通過設定引數,來控制碎片清理的開始和結束時機,以及佔用的CPU比例,從而減少碎片清理對Redis請求處理的效能影響。

首先,開啟自動記憶體碎片清理:

config set activedefrag yes

然後,設定觸發記憶體清理的條件:

  • active-defrag-ignore-bytes 100mb:表示記憶體碎片的位元組數達到100MB時,開始清理;
  • active-defrag-threshold-lower 10:表示記憶體碎片空間佔作業系統分配給Redis的總空間比例達到10%時,開始清理。

最後,控制清理操作佔用CPU時間比例的上、下限:

  • active-defrag-cycle-min 25: 表示自動清理過程所用CPU時間的比例不低於25%,保證清理能正常開展;
  • active-defrag-cycle-max 75:表示自動清理過程所用CPU時間的比例不高於75%,一旦超過,就停止清理,從而避免在清理時,大量的記憶體拷貝阻塞Redis,導致響應延遲升高。

總結

  • info memory命令是一個好工具,可以幫助你檢視碎片率的情況;
  • 碎片率閾值是一個好經驗,可以幫忙你有效地判斷是否要進行碎片清理了;
  • 記憶體碎片自動清理是一個好方法,可以避免因為碎片導致Redis的記憶體實際利用率降低,提升成本收益率。
  • 如果你在實踐過程中遇到Redis效能變慢,記得通過日誌看下是否正在進行碎片清理。如果Redis的確正在清理碎片,那麼,建議你調小active-defrag-cycle-max的值,以減輕對正常請求處理的影響。

參考資料

相關文章