緩存穿透
讀的時候,先讀緩存,緩存沒有的話,就讀數據庫,然后取出數據后放入緩存。
一些惡意的請求會故意查詢不存在的key,請求量很大,就會對后端系統造成很大的壓力。這就叫做緩存穿透。
如何避免
1:對查詢結果為空的情況也進行緩存,緩存時間設置短一點,該key對應的數據insert了之后清理緩存。
2:對不存在的key進行過濾。可以把存在的key放到一個大的Bitmap中,查詢時通過該bitmap過濾。
緩存雪崩
當緩存服務器重啟或者大量緩存集中在某一個時間段失效,這樣在失效的時候,會給后端系統帶來很大壓力。導致系統崩潰。
如何避免
1:在緩存失效后,通過加鎖或者隊列來控制讀數據庫寫緩存的線程數量。比如對某個key只允許一個線程查詢數據和寫緩存,其他線程等待。
2:做二級緩存,A1為原始緩存,A2為拷貝緩存,A1失效時,可以訪問A2,A1緩存失效時間設置為短期,A2設置為長期
3:不同的key,設置不同的過期時間,讓緩存失效的時間點盡量均勻。
redis熱key問題
緩存中的一個Key(比如一個促銷商品),在某個時間點過期的時候,恰好在這個時間點對這個Key有大量的並發請求過來,
這些請求發現緩存過期一般都會從后端數據庫加載數據並回設到緩存,大並發的請求可能會把數據庫壓垮。
解決方案:
對緩存查詢加鎖,如果KEY不存在,就加鎖,然后查DB入緩存,然后解鎖;
其他進程如果發現有鎖就等待,然后等解鎖后返回數據或者進入DB查詢
緩存和數據庫的數據一致性
方式一:
讀請求和寫請求串行化,串到一個內存隊列里去,這樣就可以保證一致性。
串行化之后,就會導致系統的吞吐量會大幅度的降低,用比正常情況下多幾倍的機器去支撐線上的一個請求。
方式二:
讀的時候,先讀緩存,緩存沒有的話,就讀數據庫,然后取出數據后放入緩存。
更新的時候,先更新數據庫,然后再刪除緩存。
redis的過期策略以及內存淘汰機制
redis采用的是定期刪除+惰性刪除策略。
為什么不用定時刪除策略
定時刪除,用一個定時器來負責監視key,過期則自動刪除。雖然內存及時釋放,但是十分消耗CPU資源。
在大並發請求下,CPU要將時間應用在處理請求,而不是刪除key,因此沒有采用這一策略.
定期刪除+惰性刪除是如何工作的呢?
定期刪除,redis默認每個100ms檢查,是否有過期的key,有過期key則刪除。需要說明的是,redis不是每個100ms將所有的key檢查一次,而是隨機抽取進行檢查。因此,如果只采用定期刪除策略,會導致很多key到時間沒有刪除。
惰性刪除也就是說在你獲取某個key的時候,redis會檢查一下,這個key設置了過期時間是否過期?如果過期了就刪除。
采用定期刪除+惰性刪除就沒其他問題了么?
如果定期刪除沒刪除key。然后你也沒即時去請求key,也就是說惰性刪除也沒生效。這樣,redis的內存會越來越高。
那么就應該采用內存淘汰機制。
在redis.conf中有一行配置
maxmemory-policy volatile-lru
該配置就是配內存淘汰策略的
volatile-lru:從已設置過期時間的數據集中挑選最近最少使用的數據淘汰
volatile-ttl:從已設置過期時間的數據集中挑選將要過期的數據淘汰
volatile-random:從已設置過期時間的數據集中任意選擇數據淘汰、
allkeys-lru:從數據集中挑選最近最少使用的數據淘汰
allkeys-random:從數據集中任意選擇數據淘汰
no-enviction(驅逐):禁止驅逐數據,新寫入操作會報錯