Redis 最全解讀
—?1?—
優(yōu)秀的性能,數(shù)據(jù)是存儲在內(nèi)存中,讀寫速度非???,可支持并發(fā)10W QPS
單線程但進程,是線程安全的,采用IO 多路復用制
可作為分布式鎖
支持五種數(shù)據(jù)類型
支持數(shù)據(jù)持久化到磁盤
可以作為消息中間件使用,支持消息發(fā)布及訂閱
下表是我列舉的五種數(shù)據(jù)類型的特性及其使用場景

數(shù)據(jù)緩存是Redis最重要的一個場景,為緩存而生,在springboot中,一般有兩種使用方式:
直接通過RedisTemplate使用
通過Spring Cache集成Redis(也就是注解的方式)
(1) 數(shù)據(jù)一致性
在分布式環(huán)境下,緩存和數(shù)據(jù)庫很容易出現(xiàn)數(shù)據(jù)一致性問題,如果項目對緩存的要求是強一致性,那就不要使用緩存。
我們只能在項目中使用策略降低緩存與數(shù)據(jù)庫一致性的概率,是無法保障兩者的強一致性,一般策略包括緩存更新機制,更新數(shù)據(jù)庫后及時更新緩存、緩存失敗時增加重試機制
(2) 緩存雪崩
在了解雪崩潰之前,我們先了解什么是緩存雪崩現(xiàn)象,假設A系統(tǒng)每秒需要處理5000個請求,但數(shù)據(jù)庫每秒只能處理4000個請求,某一天,緩存機器出現(xiàn)了宕機,掛了,這時候所有的請求一下子全部落在數(shù)據(jù)庫上,數(shù)據(jù)庫肯定扛不住,報警掛掉了,這時候如果沒有采取緩存設施,數(shù)據(jù)庫又急著用,重新重啟數(shù)據(jù)庫,剛重啟完成(有可能沒啟動完),請求又來,數(shù)據(jù)庫立馬掛掉。這就是雪崩事件,是Redis緩存中最致命問題之一(有一個是穿透)。大家可以看看下圖

出現(xiàn)雪崩事件后不要急不要慌,我們可以在事故前中后三個方面來思考解決方案
事故前:redis高可用方案,主從+哨兵,集群方案,避免全盤崩潰
事故中:較少數(shù)據(jù)庫的壓力,本地Ehcache緩存+限流及降級,避免超過數(shù)據(jù)庫承受壓力
事故后:做redis持久化,一旦Redis重啟,可從磁盤中快速恢復數(shù)據(jù)
我們來看看改造后的數(shù)據(jù)流程,假設用戶A發(fā)送一個請求,系統(tǒng)先請求本地Ehcache是否有數(shù)據(jù),如果沒有再去Redis請求數(shù)據(jù),如果沒有再去數(shù)據(jù)庫請求數(shù)據(jù),獲取到數(shù)據(jù)后同步到Ehcache和redis
限流組件的作用:可以設置每秒請求數(shù)次,有多少通過請求,剩余的未通過的可以走降級處理,返回一些默認的值,或者友情提示等默認操作。具體流程可以看看下圖:

這樣做的好處是:
數(shù)據(jù)庫安全:在限流組件可用的情況下,數(shù)據(jù)庫不會掛掉,限流根據(jù)確保了每秒多少請求能通過。
部分請求可以被處理:數(shù)據(jù)庫沒掛,就意味著至少2/5的請求可以被處理掉
高峰時期部分請求無法處理到,需要用戶多次點擊,因為只有2/5的請求被處理,剩下的請求,用戶刷不出來界面,需要多點擊幾次
redis設置的緩存失效時間不是設置成同一個時間,可根據(jù)功能、業(yè)務、請求接口靈活設置緩存時間:setRedis(key, value, time+Math.random()*10000);
(3) 緩存穿透
緩存穿透是指緩存和數(shù)據(jù)庫中都沒有的數(shù)據(jù),用戶(黑客)不斷發(fā)起請求,導致請求直接查詢數(shù)據(jù)庫,這種惡意行為攻擊場景的會直接導致數(shù)據(jù)庫掛掉,數(shù)據(jù)流程如下圖所示

處理這種情況相對比較簡單點,這種情況是繞過redis或本地緩存直接到達數(shù)據(jù)庫,可以采取以下方案:
在請求接口層可以做一些校驗,比如用戶簽權、參數(shù)校驗,不合法的請求直接return,
還可以針對有效id做認證或直接攔截,不符合的id直接過濾或采用統(tǒng)一key保存到redis,下次不合法的id請求時,直接到緩存中獲取數(shù)據(jù)
采用redis的高級接口Bloom Filter,利用高效的數(shù)據(jù)結構和算法快速判斷出你這個 Key 是否在數(shù)據(jù)庫中存在,不存在你 return 就好了,存在你就去查 DB 刷新 KV 再 return
(4) 緩存擊穿
上面講的穿透是針對大面積數(shù)據(jù)請求,那么擊穿是針對一點(一個key)來來導致redis異常,但某個key是非常熱點,請求非常頻繁,處于集中式訪問現(xiàn)象,當這個key失效(過期)時,大量的請求就會擊穿了緩存,直接請求數(shù)據(jù)庫,就像在屏障中鑿開了一個洞。
不同場景下緩存擊穿解決方案
數(shù)據(jù)基本不變:熱點數(shù)據(jù)value基本不更新時,可以設置成永不過期
數(shù)據(jù)更新不頻繁:緩存刷新流程耗時較少時,可采用redis、zookeeper等分布式中間件的分布式互斥鎖或者本地互斥鎖保證少量的請求能請求到數(shù)據(jù)庫并重新更新緩存,其他的流程等鎖釋放后才可以訪問新緩存
數(shù)據(jù)更新頻繁:采用定時線程,在緩存過期前主動重新構建緩存或延長過期時間,保證所有的請求能一直訪問緩存
Redis官方介紹可以達到10W+的QPS,這個數(shù)據(jù)不比MEMCache差,而且Redis 是單進程單線程的模型,完全基于內(nèi)存的操作,CPU不是Redis的瓶頸,Redis的瓶頸是內(nèi)存及網(wǎng)絡帶寬,有以下特點:
使用類似于HashMap的原理,HashMap的查詢及操作的時間復雜度是O(1),且絕大多數(shù)請求是純碎的內(nèi)存操作,數(shù)據(jù)存在內(nèi)存中
數(shù)據(jù)結構簡單,對數(shù)據(jù)操作也簡單,基于KV
不錯死鎖現(xiàn)象采用單線程操作,避免了不必要的上下文切換及競爭條件,不存在CPU切換現(xiàn)象,也就不存在考慮各種鎖的問題
使用非阻塞IO,多路復用IO模型
volatile為前綴的策略都是從已過期的數(shù)據(jù)集中進行淘汰。
allkeys為前綴的策略都是面向所有key進行淘汰。
LRU(least recently used)最近最少用到的。
LFU(Least Frequently Used)最不常用的。
它們的觸發(fā)條件都是Redis使用的內(nèi)存達到閾值時。

Redis 持久化策略有兩種:
RDB:快照形式是直接把內(nèi)存中的數(shù)據(jù)保存到一個 dump 的文件中,定時保存,保存策略。
AOF:把所有的對 Redis 的服務器進行修改的命令都存到一個文件里,命令的集合。Redis 默認是快照 RDB 的持久化方式。
如果非常關心你的數(shù)據(jù),但仍然可以承受數(shù)分鐘內(nèi)的數(shù)據(jù)丟失,那么可以額只使用 RDB 持久。
AOF 將 Redis 執(zhí)行的每一條命令追加到磁盤中,處理巨大的寫入會降低Redis的性能,不知道你是否可以接受。
數(shù)據(jù)庫備份和災難恢復:定時生成 RDB 快照非常便于進行數(shù)據(jù)庫備份,并且 RDB 恢復數(shù)據(jù)集的速度也要比 AOF 恢復的速度快。
當然了,Redis 支持同時開啟 RDB 和 AOF,系統(tǒng)重啟后,Redis 會優(yōu)先使用 AOF 來恢復數(shù)據(jù),這樣丟失的數(shù)據(jù)會最少。
從節(jié)點執(zhí)行 slaveof[masterIP][masterPort],保存主節(jié)點信息。
從節(jié)點中的定時任務發(fā)現(xiàn)主節(jié)點信息,建立和主節(jié)點的 Socket 連接。
從節(jié)點發(fā)送 Ping 信號,主節(jié)點返回 Pong,兩邊能互相通信。
連接建立后,主節(jié)點將所有數(shù)據(jù)發(fā)送給從節(jié)點(數(shù)據(jù)同步)。
主節(jié)點把當前的數(shù)據(jù)同步給從節(jié)點后,便完成了復制的建立過程。接下來,主節(jié)點就會持續(xù)的把寫命令發(fā)送給從節(jié)點,保證主從數(shù)據(jù)一致性。
我們先說說主從復制會存在問題:
一旦主節(jié)點宕機,從節(jié)點晉升為主節(jié)點,同時需要修改應用方的主節(jié)點地址,還需要命令所有從節(jié)點去復制新的主節(jié)點,整個過程需要人工干預。
主節(jié)點的寫能力受到單機的限制。
主節(jié)點的存儲能力受到單機的限制。
原生復制的弊端在早期的版本中也會比較突出,比如:Redis 復制中斷后,從節(jié)點會發(fā)起 psync。
此時如果同步不成功,則會進行全量同步,主庫執(zhí)行全量備份的同時,可能會造成毫秒或秒級的卡頓。
哨兵的架構模式如下:

該系統(tǒng)可以執(zhí)行以下四個任務:
監(jiān)控:不斷檢查主服務器和從服務器是否正常運行。
通知:當被監(jiān)控的某個 Redis 服務器出現(xiàn)問題,Sentinel 通過 API 腳本向管理員或者其他應用程序發(fā)出通知。
自動故障轉移:當主節(jié)點不能正常工作時,Sentinel 會開始一次自動的故障轉移操作,它會將與失效主節(jié)點是主從關系的其中一個從節(jié)點升級為新的主節(jié)點,并且將其他的從節(jié)點指向新的主節(jié)點,這樣人工干預就可以免了。
配置提供者:在 Redis Sentinel 模式下,客戶端應用在初始化時連接的是 Sentinel 節(jié)點集合,從中獲取主節(jié)點的信息。
作者:MicroStone123
來源:https://www.jianshu.com/p/0a1c9fc23c01


