1. 程式人生 > >Redis快取策略的個人看法.

Redis快取策略的個人看法.

我曾經用Java程式碼模擬了Redis的儲存和讀取,那只是一個功能的簡單實現,並沒有什麼技術含量可言.Redis在如今的網際網路應用當中算是起到了一箇中流砥柱的作用吧,我姑且這麼認知,畢竟在扛併發和快取方面使用範圍比較廣,而且叢集部署健壯性也是OK的.對於大廠而言可能已經很小兒科,但是對於小型企業而言還是有點幫助的.最近如果有時間準備去看看Memcache,雖然這東西最大儲存單槽1MB,Redis是1GB,But Redis是單程序單執行緒的對於多核CPU而言最多也就佔據單個核心而Memcache則不然,多核CPU對其更加有利..但是我沒用過Memcache,慚愧啊.希望有時間能模擬一個環境進行壓測,獲取壓力曲線這種第一手資料,再來更加詳細總結一下吧.

優勢和使用的原因
網際網路專案,類似電商、社交、網約車之類的都會面臨高併發的一個問題.在解決併發安全問題的基礎上必須考慮的就是一個性能問題,這直接影響到使用者體驗和服務提供的能力上限.通常那些熱度比較高的熱點會被使用者大量訪問,比如某國產手機做了個爆款,類似小米之類的一上線釋出,會引發很多米粉的關注,PV就這樣上去了..一種不假思索的解決方案就是使用快取.而Redis這種基於記憶體的NoSQL在執行效率上遠勝於MySQL,Oracle之類的基於硬碟的傳統關係型資料.而且因為是記憶體級的所以還能避免直接操作傳統資料庫帶來的鏈路層延時帶來的時間浪費,真是快哉秒哉.

理想很豐滿,現實很骨感.


就算是引入了快取,依然能會存在一些出人意料的情況,而正是這些極端情況帶來的風險還是切實威脅著生產環境的.比如快取雪崩,快取穿透,快取擊穿.

快取雪崩:
就和滾雪球一樣,雪球越滾越大最後雪崩.比如某些資料沒有被成功載入入快取當中,或者某一時間點大量快取同時失效,此時如果又有大量的請求進來進行查詢而快取之中沒有對應的副本去響應請求,必然的結果就是去查詢資料庫,直接導致資料庫伺服器壓力過大響應緩慢,或者乾脆直接宕機.
如圖:快取雪崩
解決之道:最簡單的辦法就是讓key的失效時間不連續,比如expire設定為1分鐘失效,可以在後面增加1-20秒的隨機數,一定程度上能夠解決大面積失效的問題.但是萬一命很背

,隨機數全是一樣的,比如都是1秒,仍然會導致雪崩,這個時候就需要在程式碼中使用到上鎖,或者通過Queue來保證快取通過單執行緒寫入,避免這種情況..這裡感謝原阿里P7大佬的點撥,謝謝.

快取穿透:
當查詢一個不存在的資料時,快取肯定是不會被命中的,而正因為快取不被命中,所以需要去資料庫中查詢並且寫入快取.快取中沒有的資料就去資料庫查詢,如果查詢到了就寫入快取同時返回結果給使用者,等待下次訪問直接走快取,但是如果查詢失敗了必然是不會寫入快取中的,那麼如果人家頻繁操或者說併發量大的情況下(也可能是攻擊),DB依然容易宕機.
如圖:
快取穿透
解決之道:在愛品寶跨境商城當中採用的是一種比較原始但是可靠的土方法(我的餿主意),如果一個查詢結果為空,照樣快取這個空結果,但是過期時間設定得比較短就30秒.減少資料庫伺服器壓力,把壓力轉嫁給Redis叢集.還有StackOverFlow上的一個老外給出的方法是使用一個BloomFilter,但是很慚愧,這個我並沒有過深研究,有時間我會補全 //TODO 研究BloomFilter並且熟悉其原理

快取擊穿:
某一時刻有一個key快要過期了,此時一波洪峰正在路上,key過期以後自然是不存在了的,此時洪峰到了,高併發帶來的就是一頓騷操作,所有的人都查詢了資料庫,並且都往快取中寫..想想也是很可怕的.
如圖:
快取擊穿
解決之道:使用互斥鎖,在快取失效的時候,查詢快取必然是不命中,先通過Redis的SETNX(Set if not exits)設定一個代表互斥鎖的key,例如mutex_lock_key: ,並且給其設定一個較長一點的過期時間(防止查詢時間過長其他執行緒又進來搗亂),一旦這個互斥鎖設定成功,再查詢資料庫,然後寫入快取,否則就重新走以上步驟..
其他好的辦法暫時也沒想到..//TODO