作業系統的剩餘空間總量足夠,但申請一塊N位元組連續位址的空間時,剩餘記憶體空間中沒有大小為N位元組的連續空間,那麼這些剩餘記憶體空間中,小於N位元組的連續記憶體空間就是記憶體碎片。
記憶體碎片形成有內部原因和外部原因:
內部原因:記憶體分配器的分配策略決定作業系統無法做到「按需分配」。
Redis使用libc、jemalloc、tcmalloc多種記憶體分配器來分配內存,預設使用jemalloc。
記憶體分配器是按照固定大小來分配記憶體空間,而不是完全按照應用程式申請的記憶體大小來分配。
以jemalloc為例,是依照一系列固定的大小劃分記憶體空間,例如8位元組、16位元組、32位元組、...、2KB、4KB等。 Jemalloc會分配與程式申請記憶體最接近的固定大小的空間。
外部原因:鍵值對大小不一樣,且鍵值對可以被修改和刪除。
Redis申請記憶體空間分配時,對於大小不一的記憶體空間需求,記憶體分配器依照固定大小分配記憶體空間,分配的記憶體空間一般都會比申請的記憶體空間大一些,這會產生一定的記憶體碎片。
鍵值對會被修改和刪除,會導致空間的擴容和釋放。
DAS透過Redis提供的INFO命令,查詢記憶體使用的詳細信息,命令如下:
INFO memory # Memory used_memory:350458970752 used_memory_human:326.39G used_memory_rss:349066919936 used_memory_rss_human:325.09G … mem_fragmentation_ratio:1.00
used_memory:表示Redis為了保存數據實際申請使用的記憶體空間。
used_memory_rss:表示作業系統實際分配給Redis的實體記憶體空間,其中包含了記憶體空間碎片。
mem_fragmentation_ratio指當前Redis的記憶體碎片率。計算公式:mem_fragmentation_ratio=used_memory_rss/used_memory
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時,開始清理;
以上是怎麼清理Redis記憶體碎片的詳細內容。更多資訊請關注PHP中文網其他相關文章!