Redis作為一個高性能的記憶體NoSQL資料庫,其容量受到最大記憶體限制的限制。
使用者在使用阿裡雲Redis時,除了對性能,穩定性有很高的要求外,對記憶體占用也比較敏感。在使用過程中,有些使用者會覺得自己的線上執行個體記憶體占用比自己預想的要大。
事實上,執行個體中的記憶體除了儲存原始的鍵值對所需的開銷外,還有一些運作時産生的額外記憶體,包括:
垃圾資料和過期Key所占空間
字典漸進式Rehash導緻未及時删除的空間
Redis管理資料,包括底層資料結構開銷,用戶端資訊,讀寫緩沖區等
主從複制,bgsave時的額外開銷
其它
本系列文章主要分析這些在Redis中産生的原因,帶來的影響和規避的方式。
本文主要分析第一項Redis過期政策對記憶體的影響。
為了防止一次性清理大量過期Key導緻Redis服務受影響,Redis隻在空閑時清理過期Key。
具體Redis逐出過期Key的時機為:
通路Key時,會判斷Key是否過期,逐出過期Key;
CPU空閑時在定期serverCron任務中,逐出部分過期Key;
每次事件循環執行的時候,逐出部分過期Key;
Redis過期Key清理的機制對清理的頻率和最大時間都有限制,在盡量不影響正常服務的情況下,進行過期Key的清理,以達到長時間服務的性能最優.
Redis會周期性的随機測試一批設定了過期時間的key并進行處理。測試到的已過期的key将被删除。具體的算法如下:
Redis配置項hz定義了serverCron任務的執行周期,預設為10,即CPU空閑時每秒執行10次;
每次過期key清理的時間不超過CPU時間的25%,即若hz=1,則一次清理時間最大為250ms,若hz=10,則一次清理時間最大為25ms;
清理時依次周遊所有的db;
從db中随機取20個key,判斷是否過期,若過期,則逐出;
若有5個以上key過期,則重複步驟4,否則周遊下一個db;
在清理過程中,若達到了25%CPU時間,退出清理過程;
這是一個基于機率的簡單算法,基本的假設是抽出的樣本能夠代表整個key空間,redis持續清理過期的資料直至将要過期的key的百分比降到了25%以下。這也意味着在長期來看任何給定的時刻已經過期但仍占據着記憶體空間的key的量最多為每秒的寫操作量除以4.
由于算法采用的随機取key判斷是否過期的方式,故幾乎不可能清理完所有的過期Key;
代碼分析如下:
在逐出算法中,根據使用者設定的逐出政策,選出待逐出的key,直到目前記憶體小于最大記憶體值為主.
可選逐出政策如下:
volatile-lru:從已設定過期時間的資料集(server.db[i].expires)中挑選最近最少使用 的資料淘汰
volatile-ttl:從已設定過期時間的資料集(server.db[i].expires)中挑選将要過期的數 據淘汰
volatile-random:從已設定過期時間的資料集(server.db[i].expires)中任意選擇資料 淘汰
allkeys-lru:從資料集(server.db[i].dict)中挑選最近最少使用的資料淘汰
allkeys-random:從資料集(server.db[i].dict)中任意選擇資料淘汰
no-enviction(驅逐):禁止驅逐資料
具體代碼如下
不要放垃圾資料,及時清理無用資料
實驗性的資料和下線的業務資料及時删除;
key盡量都設定過期時間
對具有時效性的key設定過期時間,通過redis自身的過期key清理政策來降低過期key對于記憶體的占用,同時也能夠減少業務的麻煩,不需要定期手動清理了.
單Key不要過大
給使用者排查問題時遇到過單個string的value有43M的,也有一個list 100多萬個大成員占了1G多記憶體的。這種key在get的時候網絡傳輸延遲會比較大,需要配置設定的輸出緩沖區也比較大,在定期清理的時候也容易造成比較高的延遲. 最好能通過業務拆分,資料壓縮等方式避免這種過大的key的産生。
不同業務如果公用一個業務的話,最好使用不同的邏輯db分開
從上面的分析可以看出,Redis的過期Key清理政策和強制淘汰政策都會周遊各個db。将key分布在不同的db有助于過期Key的及時清理。另外不同業務使用不同db也有助于問題排查和無用資料的及時下線.