Redis緩存失效策略思考
掃描二維碼
隨時隨地手機看文章
1 刪除過期數(shù)據(jù)
我們設(shè)置Redis元素時可以指定過期時間,那么Redis如何刪除這些超時元素?Redis采用了兩種策略:定期刪除和惰性刪除。
(1) 定期刪除
Redis每隔一段時間就檢查哪些KEY已經(jīng)過期,如果過期就刪除。但是我們來設(shè)想一個問題:如果Redis存儲KEY非常多,僅僅超時檢查這項工作就會非常耗費資源并嚴(yán)重影響服務(wù)能力。為了解決這個問題Redis并不是檢查全量KEY而只是檢查部分,同時引入了惰性刪除策略。
(2) 惰性刪除
假設(shè)當(dāng)KEY1已經(jīng)過期,但是由于沒有被檢查到而未被刪除。那么當(dāng)程序訪問KEY1時,Redis會檢查KEY1是否過期,如果過期則刪除并不返回該值,這就是惰性刪除策略。結(jié)合定期刪除和惰性刪除兩種策略,就可以保證過期數(shù)據(jù)可以被刪除。
2 內(nèi)存淘汰
當(dāng)內(nèi)存不足時Redis會選擇一些緩存元素進行刪除,那么哪些元素會被刪除?常見內(nèi)存淘汰策略如下:
no-enviction禁止驅(qū)逐數(shù)據(jù),新寫入操作會報錯 volatile-lru從已設(shè)置過期時間的數(shù)據(jù)集選擇最近最少使用的數(shù)據(jù)淘汰 volatile-ttl從已設(shè)置過期時間的數(shù)據(jù)集選擇將要過期的數(shù)據(jù)淘汰 volatile-random從已設(shè)置過期時間的數(shù)據(jù)集選擇任意的數(shù)據(jù)淘汰 allkeys-lru從數(shù)據(jù)集選擇最近最少使用的數(shù)據(jù)淘汰 allkeys-random從數(shù)據(jù)集選擇任意的數(shù)據(jù)淘汰
LRU(Least Recently Used)最近最少使用是比較常用的策略,我們使用JAVA代碼實現(xiàn)一個簡單LRU策略,代碼原理并不復(fù)雜:使用一個鏈表存儲元素,表頭存儲最近訪問的元素,這樣存儲的結(jié)果是表尾存儲最早訪問的元素,表頭存儲最近訪問的元素,當(dāng)超出鏈表容量時刪除表尾元素即可。
/** * 元素對象 * * @author 微信公眾號「IT徐胖子」 * */public class CacheElement { private String key; private Object value; public CacheElement(String key, Object value) { this.key = key; this.value = value; } public String getKey() { return key; } public Object getValue() { return value; } @Override public String toString() { return "Element [key=" + key + ", value=" + value + "]"; }} /** * LRU緩存策略 * * @author 微信公眾號「IT徐胖子」 * */public class LRUCache { private int capacity; private LinkedListcache; public LRUCache(int capacity) { this.capacity = capacity; this.cache = new LinkedList<>(); } /** * 獲取緩存元素 * * 找到元素后將元素從原位置刪除并插入到鏈表頭部(最近) */ public CacheElement get(String key) { Iteratoriterator = cache.iterator(); while (iterator.hasNext()) { CacheElement element = iterator.next(); if (element.getKey().equals(key)) { iterator.remove(); System.out.println("獲取到元素=" + element); put(element.getKey(), element.getValue()); return element; } } return null; } /** * 存儲緩存元素 * * 新元素插入到鏈表頭部(最近) */ public boolean put(String key, Object value) { Iteratoriterator = cache.iterator(); while (iterator.hasNext()) { CacheElement element = iterator.next(); if (element.getKey().equals(key)) { iterator.remove(); break; } } if (capacity == cache.size()) { CacheElement deleteElement = cache.removeLast(); System.out.println("容量已滿刪除尾部元素=" + deleteElement); } CacheElement element = new CacheElement(key, value); cache.addFirst(element); System.out.println("插入頭部元素=" + element); return Boolean.TRUE; } @Override public String toString() { return "LRUCache [capacity=" + capacity + ", cache=" + cache + "]"; }} /** * LRU測試實例 * * @author 微信公眾號「IT徐胖子」 * */public class TestCache { public static void main(String[] args) { System.out.println("==================存儲緩存元素=================="); LRUCache cache = new LRUCache(2); CacheElement element0 = new CacheElement("k0", "v0"); CacheElement element1 = new CacheElement("k1", "v1"); CacheElement element2 = new CacheElement("k2", "v2"); cache.put(element0.getKey(), element0.getValue()); cache.put(element1.getKey(), element1.getValue()); cache.put(element2.getKey(), element2.getValue()); System.out.println("==================獲取緩存元素=================="); System.out.println("獲取元素之前緩存對象=" + cache); cache.get("k1"); System.out.println("獲取元素之后緩存對象=" + cache); }} ==================存儲緩存元素==================插入頭部元素=Element [key=k0, value=v0]插入頭部元素=Element [key=k1, value=v1]容量已滿刪除尾部元素=Element [key=k0, value=v0]插入頭部元素=Element [key=k2, value=v2] ==================獲取緩存元素==================獲取元素之前緩存對象=LRUCache [capacity=2, cache=[Element [key=k2, value=v2], Element [key=k1, value=v1]]]獲取到元素=Element [key=k1, value=v1]插入頭部元素=Element [key=k1, value=v1]獲取元素之后緩存對象=LRUCache [capacity=2, cache=[Element [key=k1, value=v1], Element [key=k2, value=v2]]]
3 文章總結(jié)
本文分析了Redis緩存失效策略:刪除過期數(shù)據(jù)和內(nèi)存淘汰,并且使用JAVA代碼模擬了LRU策略實現(xiàn)。
這里我們可以做一個展開:Redis分布式鎖是否可靠。因為Redis存在內(nèi)存淘汰機制,那么作為分布式鎖的KEY概率上會被淘汰,從而導(dǎo)致分布式鎖失效。所以僅僅有分布式鎖是不夠的,我們還需要其它方法,例如設(shè)置數(shù)據(jù)庫層唯一索引,防止重復(fù)數(shù)據(jù)產(chǎn)生。
特別推薦一個分享架構(gòu)+算法的優(yōu)質(zhì)內(nèi)容,還沒關(guān)注的小伙伴,可以長按關(guān)注一下:
![]()
![]()
長按訂閱更多精彩▼
![]()
如有收獲,點個在看,誠摯感謝
免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺僅提供信息存儲服務(wù)。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!