「本文已參與好文召集令活動,點擊查看:後端、大前端雙賽道投稿,2萬元獎池等你挑戰!」前端
你們好,我是颶風java
往期文章索引以下:git
00-Redis 你真的瞭解嗎?
01-Redis 數據類型你知道的不止這些
02-Redis 哈希表的門道
03-Redis 憑什麼這麼快
04-Redis 持久化AOF你真的瞭解嗎?
05-Redis 持久化之RDB 的奧祕github
前面的文章咱們主要聊了一些redis 的基礎知識,一直沒有實戰或者實際中遇到的問題,你們會枯燥無味些,今天我就來聊聊實戰。面試
相信這三個問題,網上已經有不少的夥伴講過了,可是今天我仍是想說下,會多畫圖,讓你們加深印象,這三個問題也高頻的面試題,可是能把這幾個問題說清楚,也是須要技巧的。redis
再說這三個問題的時候,先說下正常的請求流程,看圖說話:算法
上圖的意思大體以下:數據庫
首先會在你的代碼中,多是tomcat 也能夠是你的rpc 服務中,先判斷緩存cache 中是否存在你想要的數據,若是存儲了,那麼直接返回給調用端,若是不存在,那麼就須要查詢數據庫,查詢出結果來,再繼續緩存到cache中,而後返回結果給調用方,下次再來的查詢的時候,也就命中緩存了。後端
定義數組
記得以前在作推薦系統的時候,有些數據是離線算法算出來的,需求是看了這個商品會推薦哪些類似的商品,這個算出來以後會存儲到hbase,同時存儲到redis,因爲都是批量算法出來的,再存儲到redis 的時候,若是過時時間設置相同,那麼就會形成大批量的key ,在同一時刻失效,那麼就會有大批量的請求會被打到後臺的數據庫上,由於數據庫的吞吐量是有限的,頗有可能會把數據庫打垮的,這種狀況就是緩存雪崩,看圖說話:
這個主要是說明一個緩存雪崩出現的場景,尤爲是定時任務在批量設置cache的時候,必定要注意過時時間的設置。
如何預防雪崩
其實也很簡單,就是在你批量設置cache的緩存時間的時候,給設置的緩存時間,設置一個隨機數(如隨機數能夠10分鐘內的數字,隨機數的生成能夠用java的Random生成),這樣,就不會出現大量的key,再同一時刻集體失效了,看圖說話:
若是真的發生了雪崩怎麼辦?
流量不是很大,數據庫能抗住,ok,恭喜你逃過一劫。
流量很大,超過了數據庫所能處理的請求數的極限,數據庫down機了,也恭喜你領了一個P0事故單。
流量很大,若是你的數據庫有限流方案,當達到了限流設置的參數,那麼就會拒絕請求,從而保護了後臺db。這裏對限流多說幾句。
能夠經過設置每秒請求數,來限制大量的請求到達db端,注意這裏的每秒請求數,或者說是併發數,並非數據當前的每秒請求數,能夠設置爲查詢某個key 對應的每秒請求數量,這樣作的目的,是防止大量相同key的請求到達後端數據庫,這樣就能攔截了大部分請求了。
看圖說話:
這樣相同的key,就會被限流了大部分請求,從而保護了數據庫db。
其實限流還分爲本地限流和分佈式限流兩種,後面的文章裏,我會 介紹本地限流和redis 實現的分佈式限流。
定義
好比在某網站在進行雙十一或者在搞秒殺等運營活動的時候,那麼此時網站流量通常都會很大的,某個一個商品由於促銷會成爲爆品,流量超級的大,若是這個商品,在這個時候,因爲某種緣由,在cache內失效了,那麼就瞬間這個key的流量都會涌向數據庫了,那麼db最終挺不住了,down了,後果可想而知啊,正常其餘的數據也查詢不了。
看圖說話:
redis 中的huawei pro 這個key 忽然失效了,多是到期了,多是內存不夠被淘汰了,那麼就會有大流量的請求到達redis ,發現redis 沒有這個key,那麼這些流量,就會轉到DB 上去,查詢對應的huawei pro,此時DB 挺不住了,down了。
如何解決
其實歸根到底仍是不能讓更多的流量到達DB就好了,因此咱們就是要限制到達db的流量就能夠了。
一、限流
和上面說的相似,主要是限制某個key的流量,當這個key ,被擊穿後,限制只有一個流量進入到db,其餘都被拒絕,或者等待重試查詢redis。
限流的圖能夠參考緩存擊穿限流的圖。
這裏也會分本地限流和分佈式限流 。
何爲本地限流,就是在本地單個實例範圍內,限制這個key的流量多少,只對當前實例有效。
何爲分佈式限流呢,就是在分佈式的環境下,多個實例的範圍內,這個key的限制流量的累加是來自多個實例的流量,達到限制,全部的實例都會限制流量到達DB。
二、利用分佈式鎖
這裏簡單說下分佈式鎖的定義,在併發場景下,須要使用鎖對共享資源互斥訪問來保證線程安全;一樣,在分佈式場景下,也須要一種機制來保證對多節點共享資源的互斥訪問,實現機制就是分佈式鎖。
在這裏共享資源就是例子中的huawei pro,也就是在訪問db中的huawei pro 的時候,要保證只有一個線程或者一個流量去訪問,就達到了分佈式鎖的效果。
看圖說話:
去搶鎖:
大量請求在沒有獲取到huawei pro 這個key的值後,準備去db獲取數據,此時獲取db的代碼加了分佈式鎖,那麼每一個請求,也是每一個線程都會去獲取huawei pro 的分佈式鎖(圖中利用redis實現了分佈式鎖,後面我會有單獨一篇文章來介紹分佈式鎖的實現,不限於redis)。
獲取鎖以後:
此時線程A獲取了huawei pro 的分佈式鎖,那麼線程A就會去DB加載數據,而後由線程A將huawei pro 再次設置到cache內,而後返回數據。
其餘的線程就沒有獲取到,一種方式就是直接返回空值給客戶端,還有一種等待50-100ms ,由於查詢db和放入redis 會很快,此時等待,再次查詢的時候,結果可能就有了,若是沒有就直接返回null,固然也能夠重試,固然在大併發的場景下,仍是但願可以快速的返回結果,不能發生太屢次數的重試操做。
三、定時任務更新熱點key
這個就很好理解,說白了,就是一個定時任務定時的去監控某些熱點key的超時時間,是否到期,再進行快到期了的時候延長key在cache中的緩存時間就能夠了。
單個線程輪詢的方式檢查和更新失效時間,看圖:
多線程的方式,注意熱點的key 不能太多,某個線程會開啓不少,若是熱點key不少,能夠採用線程池的方式,看圖:
延遲隊列實現
上面的方式說白了,不管是單個線程仍是多個線程,都是會採用輪詢的方式(每次白白浪費的cpu),來檢查是否key 快到期了,這種方式檢查會存在檢查時間不許確,可能會形成時間的延遲或者不許確,你在等待進行下次檢查的時候,這個key就沒了,那麼此時就已經發了擊穿,這個狀況的發生雖然機率低,但也是有的,那麼咱們怎麼才能避免呢,其實我們能夠利用延遲隊列(環形隊列來實現,這裏我不深刻講這個隊列的原理了,你們能夠自行百度或者google),所謂的延遲隊列就是你往這個隊列發送消息,但願按照你設置的時間來進行消費,時間沒到不會進行消費,時間到了就進行消費,好了,看圖說話吧:
一、程序首次啓動 獲取名單內key的失效時間。
二、依次設置key 延遲消費的時間,注意這個消費時間要比失效時間要早。
三、延遲隊列到期,消費端進行消費key。
四、消費端消費消息,延遲key的失效時間到cache。
五、再次發送key 新的失效時間到延遲隊列,等待下次延遲cache的失效時間。
四、設置key 不失效
這種其實也可能會由於內存不足,key 被淘汰,你們能夠想一想什麼狀況下,key 會被淘汰。
定義
所謂穿透,就是訪問了一個cache不存在,數據庫裏也不存在的key,那麼此時至關於流量直接到達了DB 了,那麼一些流氓就能夠利用這個漏洞,瘋狂的刷你的接口,進而把你的DB打垮,你的業務也就不能正常運行了。
如何解決呢?
一、設置null 或者特殊值
咱們能夠經過設置null 或者特定的值到redis內,且不過時,那麼下次再來的時候,直接從redis 獲取這個null 或者 特殊值就能夠了。
這個方案不能解決根本性的問題,若是這個流量能仿造出大量的無用key,你設置再多的null或者特殊的值都是沒有用的,那麼咱們應該怎麼解決呢?
二、布隆過濾器
布隆過濾器 英文爲 bloomfiler,這裏咱們只是作簡單的介紹,介於篇幅的緣由,後面會有單獨的文章作介紹。
舉個例子,若是咱們數據庫裏存儲着千萬級別的sku 數據,咱們如今的需求是若是庫有這個sku,那麼就查詢redis ,若是redis 沒有就查詢數據庫,而後更新redis,咱們最早想到的就是把sku數據放入到一hashmap內,key 就是sku,由於sku 的數量不少,那麼這個hashmap佔用的內存空間會很大,有可能會撐爆內存,最後得不償失了,那麼怎麼來節省內存,咱們能夠利用一個bit的數組,來存儲這個sku是否存在狀態,0 表明不存在,1 表明存在,咱們能夠利用一個散列函數,算出sku的散列值,而後sku的散列值對bit數組進行取模,找到所在數組的位置,而後設置爲1,當請求來的時候,咱們會算出這個sku 散列值對應的數組位置是否爲1 ,爲1 說明就存在,爲0 說明就不存在。這樣一個簡單的bloomfilter就實現了,bloomfiler 是有錯誤率,能夠考慮增長數組長度和散列函數的數量來提供準確率,具體能夠百度或者google,今天在這裏就不講了。
下面看看利用bloomfiler 來防止緩存穿透的流程,看圖說話:
bloomfiler的初始化 能夠經過一個定時任務來讀取 db,初始化bit數組的大小,默認值都是爲0,表示不存在,而後每條都計算散列值對應的數組位置,而後插入到bit 數組中。
請求流程,看圖:
若是不利用bloomfiler 過濾器,對於一個數據庫里根本不存在的key,其實白白浪費了兩次IO,一次查詢redis,一次查詢DB,有了bloomfiler ,那麼就節省了這兩次無用的IO,減小後端redis 和 DB 資源的浪費。
今天咱們聊了redis緩存 的高頻的面試和實戰中遇到的問題以及解決方案。
解決方案:
解決方案:
解決方案:
今天的分享就到這裏了,碼字畫圖不易,期待你的點贊、關注、轉發,謝謝。
你的點贊、關注 是颶風創做的最大動力。
若有問題 歡迎人才請留言,一塊兒討論和勘誤。
歡迎關注 github
微信添加: zookeeper0