一文讀懂 Redis
一、redis 簡介
Redis 是 C 語言開發的一個開源高性能鍵值對的_內存數據庫_,可以用來做數據庫、緩存、消息中間件等場景,是一種 NoSQL(not-only sql, 非關係型數據庫) 的數據庫
二、Redis 特點
-
優秀的性能,數據是存儲在內存中,讀寫速度非常快,可支持併發 10W QPS
-
單線程但進程,是線程安全的,採用 IO 多路複用制
-
可作爲分佈式鎖
-
支持五種數據類型
-
支持數據持久化到磁盤
-
可以作爲消息中間件使用,支持消息發佈及訂閱
二、數據類型
下表是我列舉的五種數據類型的特性及其使用場景
三、緩存
數據緩存是 Redis 最重要的一個場景,爲緩存而生,在 springboot 中,一般有兩種使用方式:
-
直接通過 RedisTemplate 使用
-
通過 Spring Cache 集成 Redis(也就是註解的方式)
四、使用緩存遇到的問題
(1) 數據一致性
在分佈式環境下,緩存和數據庫很容易出現數據一致性問題,如果項目對緩存的要求是強一致性,那就不要使用緩存。
我們只能在項目中使用策略降低緩存與數據庫一致性的概率,是無法保障兩者的強一致性,一般策略包括緩存更新機制,更新數據庫後及時更新緩存、緩存失敗時增加重試機制
(2) 緩存雪崩
在瞭解雪崩潰之前,我們先了解什麼是緩存雪崩現象,假設 A 系統每秒需要處理 5000 個請求,但數據庫每秒只能處理 4000 個請求,某一天,緩存機器出現了宕機,掛了,這時候所有的請求一下子全部落在數據庫上,數據庫肯定扛不住,報警掛掉了,這時候如果沒有采取緩存設施,數據庫又急着用,重新重啓數據庫,剛重啓完成 (有可能沒啓動完),請求又來,數據庫立馬掛掉。這就是雪崩事件,是 Redis 緩存中最致命問題之一 (有一個是穿透)。大家可以看看下圖
出現雪崩事件後不要急不要慌,我們可以在事故前中後三個方面來思考解決方案
-
事故前:redis 高可用方案,主從 + 哨兵,集羣方案,避免全盤崩潰
-
事故中:較少數據庫的壓力,本地 Ehcache 緩存 + 限流及降級,避免超過數據庫承受壓力
-
事故後:做 redis 持久化,一旦 Redis 重啓,可從磁盤中快速恢復數據
我們來看看改造後的數據流程,假設用戶 A 發送一個請求,系統先請求本地 Ehcache 是否有數據,如果沒有再去 Redis 請求數據,如果沒有再去數據庫請求數據,獲取到數據後同步到 Ehcache 和 redis
限流組件的作用:可以設置每秒請求數次,有多少通過請求,剩餘的未通過的可以走降級處理,返回一些默認的值,或者友情提示等默認操作。具體流程可以看看下圖:
這樣做的好處是:
-
數據庫安全:在限流組件可用的情況下,數據庫不會掛掉,限流根據確保了每秒多少請求能通過。
-
部分請求可以被處理:數據庫沒掛,就意味着至少 2/5 的請求可以被處理掉
-
高峯時期部分請求無法處理到,需要用戶多次點擊,因爲只有 2/5 的請求被處理,剩下的請求,用戶刷不出來界面,需要多點擊幾次
-
redis 設置的緩存失效時間不是設置成同一個時間,可根據功能、業務、請求接口靈活設置緩存時間:setRedis(key, value, time+Math.random()*10000);
(3) 緩存穿透
緩存穿透是指緩存和數據庫中都沒有的數據,用戶 (黑客) 不斷髮起請求,導致請求直接查詢數據庫,這種惡意行爲攻擊場景的會直接導致數據庫掛掉,數據流程如下圖所示
image
處理這種情況相對比較簡單點,這種情況是繞過 redis 或本地緩存直接到達數據庫,可以採取以下方案:
-
在請求接口層可以做一些校驗,比如用戶籤權、參數校驗,不合法的請求直接 return,
-
還可以針對有效 id 做認證或直接攔截,不符合的 id 直接過濾或採用統一 key 保存到 redis,下次不合法的 id 請求時,直接到緩存中獲取數據
-
採用 redis 的高級接口 Bloom Filter,利用高效的數據結構和算法快速判斷出你這個 Key 是否在數據庫中存在,不存在你 return 就好了,存在你就去查 DB 刷新 KV 再 return
(4) 緩存擊穿
上面講的穿透是針對大面積數據請求,那麼擊穿是針對一點 (一個 key) 來來導致 redis 異常,但某個 key 是非常熱點,請求非常頻繁,處於集中式訪問現象,當這個 key 失效 (過期) 時,大量的請求就會擊穿了緩存,直接請求數據庫,就像在屏障中鑿開了一個洞。
不同場景下緩存擊穿解決方案
-
數據基本不變:熱點數據 value 基本不更新時,可以設置成永不過期
-
數據更新不頻繁:緩存刷新流程耗時較少時,可採用 redis、zookeeper 等分佈式中間件的分佈式互斥鎖或者本地互斥鎖保證少量的請求能請求到數據庫並重新更新緩存,其他的流程等鎖釋放後纔可以訪問新緩存
-
數據更新頻繁:採用定時線程,在緩存過期前主動重新構建緩存或延長過期時間,保證所有的請求能一直訪問緩存
五、爲什麼 Redis 會如此快
Redis 官方介紹可以達到 10W + 的 QPS,這個數據不比 MEMCache 差,而且 Redis 是單進程單線程的模型,完全基於內存的操作,CPU 不是 Redis 的瓶頸,Redis 的瓶頸是內存及網絡帶寬,有以下特點:
-
使用類似於 HashMap 的原理,HashMap 的查詢及操作的時間複雜度是 O(1),且絕大多數請求是純碎的內存操作,數據存在內存中
-
數據結構簡單,對數據操作也簡單,基於 KV
-
不錯死鎖現象採用單線程操作,避免了不必要的上下文切換及競爭條件,不存在 CPU 切換現象,也就不存在考慮各種鎖的問題
-
使用非阻塞 IO,多路複用 IO 模型
六、Redis 淘汰策略
-
volatile 爲前綴的策略都是從已過期的數據集中進行淘汰。
-
allkeys 爲前綴的策略都是面向所有 key 進行淘汰。
-
LRU(least recently used)最近最少用到的。
-
LFU(Least Frequently Used)最不常用的。
-
它們的觸發條件都是 Redis 使用的內存達到閾值時。
七、Redis 持久化
Redis 持久化策略有兩種:
-
RDB:快照形式是直接把內存中的數據保存到一個 dump 的文件中,定時保存,保存策略。
-
AOF:把所有的對 Redis 的服務器進行修改的命令都存到一個文件裏,命令的集合。Redis 默認是快照 RDB 的持久化方式。
如果非常關心你的數據,但仍然可以承受數分鐘內的數據丟失,那麼可以額只使用 RDB 持久。
AOF 將 Redis 執行的每一條命令追加到磁盤中,處理巨大的寫入會降低 Redis 的性能,不知道你是否可以接受。
數據庫備份和災難恢復:定時生成 RDB 快照非常便於進行數據庫備份,並且 RDB 恢復數據集的速度也要比 AOF 恢復的速度快。
當然了,Redis 支持同時開啓 RDB 和 AOF,系統重啓後,Redis 會優先使用 AOF 來恢復數據,這樣丟失的數據會最少。
八、Redis 主從複製
-
從節點執行 slaveof[masterIP][masterPort],保存主節點信息。
-
從節點中的定時任務發現主節點信息,建立和主節點的 Socket 連接。
-
從節點發送 Ping 信號,主節點返回 Pong,兩邊能互相通信。
-
連接建立後,主節點將所有數據發送給從節點(數據同步)。
-
主節點把當前的數據同步給從節點後,便完成了複製的建立過程。接下來,主節點就會持續的把寫命令發送給從節點,保證主從數據一致性。
九、Redis 哨兵模式
我們先說說主從複製會存在問題:
-
一旦主節點宕機,從節點晉升爲主節點,同時需要修改應用方的主節點地址,還需要命令所有從節點去複製新的主節點,整個過程需要人工干預。
-
主節點的寫能力受到單機的限制。
-
主節點的存儲能力受到單機的限制。
-
原生複製的弊端在早期的版本中也會比較突出,比如:Redis 複製中斷後,從節點會發起 psync。
-
此時如果同步不成功,則會進行全量同步,主庫執行全量備份的同時,可能會造成毫秒或秒級的卡頓。
哨兵的架構模式如下:
該系統可以執行以下四個任務:
-
監控:不斷檢查主服務器和從服務器是否正常運行。
-
通知:當被監控的某個 Redis 服務器出現問題,Sentinel 通過 API 腳本向管理員或者其他應用程序發出通知。
-
自動故障轉移:當主節點不能正常工作時,Sentinel 會開始一次自動的故障轉移操作,它會將與失效主節點是主從關係的其中一個從節點升級爲新的主節點,並且將其他的從節點指向新的主節點,這樣人工干預就可以免了。
-
配置提供者:在 Redis Sentinel 模式下,客戶端應用在初始化時連接的是 Sentinel 節點集合,從中獲取主節點的信息。
作者:MicroStone123
來源:https://www.jianshu.com/p/0a1c9fc23c01
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/iXq5YnzU-F1cPlL11YzNJw