對於redis來說,什麼是最重要的?
毋庸置疑,是記憶體。
一、reids 記憶體分析
redis記憶體使用情況:info memory
示例:
可以看到,當前節點記憶體碎片率為226893824/209522728≈1.08,使用的記憶體分配器是jemalloc。
used_memory_rss 通常情況下是大於 used_memory 的,因為記憶體碎片的存在。
但是當作業系統把redis記憶體swap到硬碟時,memory_fragmentation_ratio 會小於1。redis使用硬碟作為記憶體,因為硬碟的速度,redis效能會受到極大的影響。
二、redis 記憶體使用
之前的文章 關於redis,你需要了解的幾點!中我們簡單介紹過redis的記憶體使用分佈:自身記憶體,鍵值物件佔用、緩衝區記憶體佔用及記憶體碎片佔用。
redis 空程式自身消耗非常的少,可以忽略不計,優化記憶體可以不考慮此處的因素。
1、物件記憶體
物件記憶體,也即真實儲存的資料所佔用的記憶體。
redis k-v結構儲存,物件佔用可以簡單的理解為 k-size + v-size。
redis的鍵統一都為字串型別,值包含多種型別:string、list、hash、set、zset五種基本型別及基於string的Bitmaps和HyperLogLog型別等。
在實際的應用中,一定要做好kv的構建形式及記憶體使用預期,可以參考 關於redis,你需要了解的幾點! 中關於不同值型別不同形式下的內部儲存實現介紹。
2、緩衝記憶體
緩衝記憶體包括三部分:客戶端快取、複製積壓快取及AOF緩衝區。
1)客戶端快取:接入redis伺服器的TCP連線輸入輸出緩衝記憶體佔用,TCP輸入緩衝佔用是不受控制的,最大允許空間為1G。輸出緩衝佔用可以通過client-output-buffer-limit引數配置。
redis 客戶端主要分為從客戶端、訂閱客戶端和普通客戶端。
從客戶端連線佔用:也就是我們所說的slave,主節點會為每一個從節點建立一條連線用於命令複製,緩衝配置為:client-output-buffer-limit slave 256mb 64mb 60。
主從之間的間絡延遲及掛載的從節點數量是影響記憶體佔用的主要因素。因此在涉及需要異地部署主從時要特別注意,另外,也要避免主節點上掛載過多的從節點(<=2);
訂閱客戶端記憶體佔用:釋出訂閱功能連線客戶端使用單獨的緩衝區,預設配置:client-output-buffer-limit pubsub 32mb 8mb 60。
當消費慢於生產時會造成緩衝區積壓,因此需要特別注意消費者角色配比及生產、消費速度的監控。
普通客戶端記憶體佔用:除了上述之外的其它客戶端,如我們通常的應用連線,預設配置:client-output-buffer-limit normal 1000。
可以看到,普通客戶端沒有配置緩衝區限制,通常一般的客戶端記憶體消耗也可以忽略不計。
但是當redis伺服器響應較慢時,容易造成大量的慢連線,主要表現為連線數的突增,如果不能及時處理,此時會嚴重影響redis服務節點的服務及恢復。
關於此,在實際應用中需要注意幾點:
-> maxclients最大連線數配置必不可少。
-> 合理預估單次運算元據量(寫或讀)及網路時延ttl。
-> 禁止線上大吞吐量命令操作,如keys等。
高併發應用情景下,redis記憶體使用需要有實時的監控預警機制,
2)複製積壓緩衝區
v2.8之後提供的一個可重用的固定大小緩衝區,用以實現向從節點的部分複製功能,避免全量複製。配置單數:repl-backlog-size,預設1M。單個主節點配置一個複製積壓緩衝區。
3)AOF緩衝區
AOF重寫期間增量的寫入命令儲存,此部分快取佔用大小取決於AOF重寫時間及增量。
3、記憶體碎片記憶體佔用
關於redis,你需要了解的幾點!簡單介紹過redis的記憶體分配方式。
三、redis 子程式記憶體消耗
子程式即redis執行持久化(RDB/AOF)時fork的子任務程式。
1、關於linux系統的寫時複製機制:
父子程式會共享相同的實體記憶體頁,父程式處理寫請求時會對需要修改的頁複製一份副本進行修改,子程式讀取的記憶體則為fork時的父程式記憶體快照,因此,子程式的記憶體消耗由期間的寫操作增量決定。
2、關於linux的透明大頁機制THP(Transparent Huge Page):
THP機制會降低fork子程式的速度;寫時複製記憶體頁由4KB增大至2M。高併發情境下,寫時複製記憶體佔用消耗影響會很大,因此需要選擇性關閉。
3、關於linux配置:
一般需要配置linux系統 vm.overcommit_memory=1,以允許系統可以分配所有的實體記憶體。防止fork任務因記憶體而失敗。
四、redis 記憶體管理
redis的記憶體管理主要分為兩方面:記憶體上限控制及記憶體回收管理。
1、記憶體上限:maxmemory
目的:快取應用記憶體回收機制觸發 + 防止實體記憶體用盡(redis 預設無限使用伺服器記憶體) + 服務節點記憶體隔離(單伺服器上部署多個redis服務節點)
在進行記憶體分配及限制時要充分考慮記憶體碎片佔用影響。
動態調整,擴充套件redis服務節點可用記憶體:config set maxmemory {}。
2、記憶體回收
回收時機:鍵過期、記憶體佔用達到上限
1)過期鍵刪除:
redis 鍵過期時間儲存在內部的過期字典中,redis採用惰性刪除機制+定時任務刪除機制。
惰性刪除:即讀時刪除,讀取帶有超時屬性的鍵時,如果鍵已過期,則刪除然後返回空值。這種方式存在問題是,觸發時機,加入過期鍵長時間未被讀取,那麼它將會一直存在記憶體中,造成記憶體洩漏。
定時任務刪除:redis內部維護了一個定時任務(預設每秒10次,可配置),通過自適應法進行刪除。
刪除邏輯如下:
】
需要說明的一點是,快慢模式執行的刪除邏輯相同,這是超時時間不同。
2)記憶體溢位控制
當記憶體達到maxmemory,會觸發記憶體回收策略,具體策略依據maxmemory-policy來執行。
noevication:預設不回收,達到記憶體上限,則不再接受寫操作,並返回錯誤。
volatile-lru:根據LRU演算法刪除設定了過期時間的鍵,如果沒有則不執行回收。
allkeys-lru:根據LRU演算法刪除鍵,針對所有鍵。
allkeys-random:隨機刪除鍵。
volatitle-random:速記刪除設定了過期時間的鍵。
volatilte-ttl:根據鍵ttl,刪除最近過期的鍵,同樣如果沒有設定過期的鍵,則不執行刪除。
動態配置:config set maxmemory-policy {}
在設定了maxmemory情況下,每次的redis操作都會檢查執行記憶體回收,因此對於線上環境,要確保所這隻的maxmemory>used_memory。
另外,可以通過動態配置maxmemory來主動觸發記憶體回收。