最近查看了一下redis運行狀況,發現公司測試服務器的redis內存不太夠用,但是實際占用內存的數據量其實不大,以前也沒有這種情況,之前在cache層新增了一個防刷積分任務的邏輯才會這樣,搜索一下原因,發現原來是產生了大量的內存碎片。
首先,查看redis的內存狀態,要用info memory指令

ps:(這個是我flushdb后的結果,反面教材來的。。。)
圖中幾個參數的意義:
1、used_memory:
已經使用了的內存大小,包括redis進程內部開銷和你的cache的數據所占用的內存,單位byte。
2、used_memory_human:
用戶數據所占用的內存,就是你緩存的數據的大小。
3、used_memory_rss:(rss for Resident Set Size)
表示redis物理內存的大小,即向OS申請了多少內存使用與used_memory的區別在后面解釋。
4、used_memory_peak:
redis內存使用的峰值。
5、used_memory_peak_human:
用戶cache數據的峰值大小。
6、used_memory_lua:
執行lua腳本所占用的內存。
7、mem_fragmentation_ratio:
內存碎片率,計算公式:

ratio指數>1表明有內存碎片,越大表明越多,<1表明正在使用虛擬內存,虛擬內存其實就是硬盤,性能比內存低得多,這是應該增強機器的內存以提高性能。一般來說,mem_fragmentation_ratio的數值在1 ~ 1.5之間是比較健康的。
8、mem_allocator:
在編譯時指定的Redis使用的內存分配器,可以是libc、jemalloc、tcmalloc,默認是jemalloc。jemalloc在64位系統中,將內存空間划分為小、大、巨大三個范圍;每個范圍內又划分了許多小的內存塊單位;存儲數據的時候,會選擇大小最合適的內存塊進行存儲。
jemalloc划分的內存單元如下圖所示:

(圖侵刪)
----------------------------------------------------- 分割線 ------------------------------------------------
產生原因
可以這樣認為,redis產生內存碎片有兩個原因,
A:redis自身的內存分配器。
B:修改cache的值,且修改后的value與原來value的大小差異較大。
進程需要用內存的話,會先通過OS向device申請,然后才能夠使用。一般進程在不需要使用的時候,會釋放掉這部分內存並返回給device。但是redis作者可能為了更高的性能,所以在redis中實現了自己的內存分配器來管理內存,不會馬上返還內存,不用每次都向OS申請了,從而實現高性能。
但是,在內存分配器的那張圖片我們知道,redis的每個k-v對初始化的內存大小是最適合的,當這個value改變的並且原來內存大小不適用的時候,就需要重新分配內存了。(但是value存比原來小不知道會不會產生碎片)。重新分配之后,就會有一部分內存redis無法正常回收,一直占用着。
----------------------------------------------------- 分割線 ------------------------------------------------
知道了原因就可以解決問題了,網上找到了兩個解決方案:
1、重啟redis服務,簡單粗暴。
2、redis4.0以上可以使用新增指令來手動回收內存碎片,配置監控使用性能更佳,具體大家可以自己去查。
這里提個問題,如果是單機redis,想要不停服務重啟redis,大家有什么好的想法?