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