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的值,以減輕對正常請求處理的影響。