高性能分布式緩存Redis
- `第一篇章`
- 1.1緩存發展史&緩存分類
- 1.1.1 大型網站中緩存的使用
- 帶來的問題
- 1.1.2 常見緩存的分類及對比
- 與memcache對比
- 1.2 數據類型選擇&應用場景
- 1.2.1 string
- 1.2.2 hash
- 1.2.3 鏈表
- 1.2.4 set
- 1.2.5 sortedset有序集合類型
- 1.2.6 總結
- 1.3 Redis高級應用&拓展功能
- 1.3.1 發布訂閱
- redis提供發布訂閱功能,可用于消息的傳輸
- 指令詳情
- 使用場景
- 1.3.2 事務
- redis事務支持回滾嗎
- redis 事務
- 1.3.2 lua腳本
- 1.3.3 慢查詢日志
- `第二篇章`
- 2.1 持久化原理
- 2.1.1 原理
- 2.1.2 持久化流程
- 2.1.3 RDB
- 概念
- 特點
- 觸發方式:指令手動觸發和redis.conf自動觸發
- RDB優勢
- RDB劣勢
- 2.1.4 AOF
- 概念
- 特點
- AOF持久化實現
- AOF重寫原理
- 持久化優先級
- 2.1.5 降低fork阻塞
- 2.1.6 實踐中的其它策略
- 2.2 過期刪除策略
- 2.2.1 問題分析
- 1. 如何設置過期時間
- 2. 如何盤判定key已過期
- 3. 過期刪除策略有哪些
- 4. Redis過期刪除策略是什么
- 2.3 內存淘汰策略
- 2.3.1 概念
- 2.3.2 如何設置Redis的最大運行內存
- 2.3.3 Redis的八種內存淘汰策略
- 2.3.4 LRU算法和LFU算法有什么區別
- LRU傳統算法
- Redis中的LRU算法
- LFU算法
- redis中LFU算法
- 2.4 Redis高可用
- 2.4.1 主從復制的出現
- 2.4.2 主從復制結構
- 2.4.3 主從復制實現
- 2.4.4 sentinel 哨兵模式
- 哨兵的出現
- 客觀下線
- 哨兵掛了怎么辦
- 2.4.5 主從+哨兵存在的問題
- `第三篇章`
- 3.1 分布式鎖
- 何為分布式鎖
- 分布鎖的特點
- 如何設計一把良好的鎖
- 3.2 布隆過濾器(BloomFilter)
- 3.3 Redis Cluster
- `第四篇章-FAQ`
- 4.1 如何保持緩存和數據庫的一致性
- ==總結==
- 1)為什么使用redis來做緩存
- 2)緩存策略帶來的問題
- 3)導致數據不一致原因
- 4)并發引起的一致性問題
- 5)刪除緩存可以保證一致性嗎
- 6)如何保證兩步都執行成功
- 7)主從庫延遲和延遲雙刪策略
- 8)保證更新數據庫和刪除緩存都能成功
- 4.2 redis是單線程架構還是多線程架構
- 4.3 單線程的redis為什么這么快
- 4.4 Redis6.x之后為何引入了多線程?
- 4.5 緩存穿透\緩存擊穿\緩存雪崩
- 4.6 為什么用 Redis 作為 MySQL 的緩存?
- 4.7 Redis 如何實現數據不丟失?
第一篇章
1.1緩存發展史&緩存分類
1.1.1 大型網站中緩存的使用
分析:直接從數據庫中的數據,是存儲在磁盤中的,需要多次的IO,而且請求數據庫是基于TCP連接,單機的mysql qps 1W+,而redis的qps達到10w+;所以可以在Tomcat和mysql中加入屏障,將熱點數據放入redis,非熱點數據放入數據庫中,流程如下
帶來的問題
- 讀寫緩存策略
- 讀寫穿透
- 異步緩存寫入
- 數據庫和緩存如何保證數據一致性
- 寫策略
- 先更新緩存,再刪除緩存
- 先刪除緩存,再更新數據庫
- 寫策略
1.1.2 常見緩存的分類及對比
與memcache對比
共同點:
- 都是基于內存的數據庫,一般都用來當做緩存使用。
- 都有過期策略。
- 兩者的性能都非常高。
區別:
- Redis 支持的數據類型更豐富(String、Hash、List、Set、zset),而 Memcached 只支持最簡單的 key-value 數據類型;
- Redis 支持數據的持久化,可以將內存中的數據保持在磁盤中,重啟的時候可以再次加載進行使用,而 Memcached 沒有持久化功能,數據全部存在內存之中,Memcached 重啟或者掛掉后,數據就沒了
- Redis 原生支持集群模式,Memcached 沒有原生的集群模式,需要依靠客戶端來實現往集群中分片寫入數據;
- Redis 支持發布訂閱模型、Lua 腳本、事務等功能,而 Memcached 不支持
所以,很少使用memcached了
1.2 數據類型選擇&應用場景
- 常見的五種數字類型:string、hash、list、set、zset
1.2.1 string
- redis并不是簡單的使用c的string,而是構建了簡單動態字符串,不光可以保存文本數據還可以保存二進制,并且獲取字符串的長度為0
- 常用命令:set,get,strlen,exists
- 應用場景:緩存對象、常規計數、分布式鎖、共享session
- 對象緩存:直接緩存整個對象的json
- 分布式鎖:setnx product:10001 true;setnx product:10001 false
1.2.2 hash
- key-value,適合存儲
- 適合做對象緩存
電商購物車
用戶id為key;商品id為field;商品數量為value;Hest cart:1 1001 1 //向id為1的商品1001添加1間商品
- 適合做對象緩存
1.2.3 鏈表
- c的鏈表查詢比較難,所以redis使用了雙向鏈表,支持反向查找和遍歷,更方便操作,不過帶了了額外的內存開銷
- 內部實現:quicklist
- 常用命令:rpush、lpop、lpush
- 應用場景:發布與訂閱或者說消息隊列,慢查詢
- 常用數據結構
- Stack(棧)=LPUSH(左邊放)+LPOP(左邊取)–> FILO
- Queue(隊列)=LPUSH(左邊放)+RPOP右邊取)
- BLocking queue(阻塞隊列)=LPUSH(左邊放)+ BRPOP(右邊阻塞取:沒有數據就阻塞!)
- 實現微波朋友圈等的關注列表顯示
- 實現后發的消息在列表中最上方展示
- 小明關注了北京本地寶,京城美味君等公眾號,這些訂閱號發布消息時,通過推或拉的方式把消息LPUSH放入redis中屬于小明的list中。其中key為msg:{小明D}。當小明要獲取大V們發的消息時,使用LRANGE 命令從隊列中獲取指定個數的訂閱號信息
Lpush msg:1 1001 //1001是北京本地寶,mag:1是小明的id
Lpush msg:1 1002
顯示的結果是1002先顯示
1.2.4 set
- 是一個無序并唯一的鍵值集合,它的存儲順序不會按照插入的先后順序進行存儲。一個集合最多可以存儲 2^32-1 個元素。概念和數學中個的集合基本類似,可以交集,并集,差集等等,所以 set 類型除了支持集合內的增刪改查,同時還支持多個集合取交集、并集、差集
- 底層實現:哈希表或整數集合
- 常用命令: sadd,spop,smembers,sismember,scard,sinterstore,sunion 等
- 應用場景: 需要存放的數據不能重復以及需要獲取多個數據源交集和并集等場景
1.2.5 sortedset有序集合類型
- 介紹:zset 類型(有序集合類型)相比于 Set 類型多了一個排序屬性 score(分值),對于有序集合zSet 來說,每個存儲元素相當于有兩值組成的,一個是有序集合的元素值,一個是排序值。
- 內部實現:壓縮列表或跳表
- 常用命會: zadd,zcard,zscore,zrange,zrevrange,zrem等
- 應用場景: 需要對數據根據某個權重進行排序的場景。比如在直播系統中,實時排行信息包含直播間在線用戶列表,各種禮物排行榜,彈幕消息(可以理解為按消息維度的消息排行榜)等信息。
1.2.6 總結
1.3 Redis高級應用&拓展功能
1.3.1 發布訂閱
redis提供發布訂閱功能,可用于消息的傳輸
redis的發布訂閱包含三個部分,publisher(redis客戶端),subscriber(redis客戶端)、channel(服務器)
指令詳情
- SUBSCRIBE/PSUBSCRIBE:訂閱,精確、或者按匹配符UNSUBSCRIBE/PUNSUBSCRIBE:退訂,精確、或者按匹配
- PUBLISH:發送;PUBSUB:查看消息列表
使用場景
- 在Redis哨兵模式中,哨兵通過發布與訂閱的方式與Redis主服務器和Redis從服務器進行通信Redisson是一個分布式鎖框架,在Redisso
- 分布式鎖釋放的時候,是使用發布與訂閱的方式通知的注:重業務的消息,推薦用消息隊列
1.3.2 事務
redis事務支持回滾嗎
所謂事務,是指作為單個邏輯工作單元執行的一系列操作
mysql在執行事務時,會提供回滾機制,當事務執行發生錯誤時,事務中的所有操作都會撤銷,已修改的數據也會被恢復到事務執行前的狀態,但是redis并沒有提供回滾機制,redis事務不一定能保證原子性
redis 事務
redis事務的本質是一組命令的集合:單詞執行多個命令,一次性、排他性、順序性
- redis事務是通過multi、exec、discrd、watch這四個命令來完成的
- redis的單個命令都是原子性的,所以這里需要確保事務的對象是命令集合
- redis將命令集合序列化并確保處于同一事務的命令集合連續且不被打斷的執行
- redis不能保障失敗回滾
原理刨析:
在exec執行事務的一瞬間,判斷監控的key是否變動
變動則取消事務隊列,直接不執行
無變動則執行,提交事務
1.3.2 lua腳本
redis+lua腳本保持原子性
- lua是一種輕量小巧的腳本語言用標準C語言編寫并以源代碼形式開放,其設計目的是為了嵌入應用程序中,從而為應用程序提供靈活的擴展和定制功能。
- Lua應用場景
- 游戲開發、獨立應用腳本、web應用腳本、查詢庫存扣減庫存
- Nginx+lua開發高性能web應用,限流、防止Sql注入
時間復雜度:取決于執行的腳本。
- 使用Lua腳本的好處:
- 減少網絡開銷。可以將多個請求通過腳本的形式一次發送,減少網絡時延。原子操作。redis會將整個腳本作為一個整體執行,中間不會被其他命令插入。因此在編寫腳本的過程中無需擔心會出現競態條件,無換事務。
- 復用。客戶端發送的腳本會永久存在redis中,這樣,其他客戶端可以復用這一腳本而不需要使用代碼完成相同的邏輯。
1.3.3 慢查詢日志
日常使用redis為什么要用慢查詢日志
客戶端請求的生命周期的完整生命周期,4個階段
慢查詢只統計步驟3的時間
- 在生產環境中,慢查詢功能可以有效地幫助我們找到Redis可能存在的瓶頸,但在實際使用過程中要注意以下幾點:
- slowog-max-en:線上建議調大慢查詢列表,記錄慢査詢時Redis會對長命令做階段操作,并不會占用大量內存,增大慢查詢列表可以減緩慢查詢被剔除的可能,例如線上可設置為1000以上.
- 2slowlog-log-slower-than:默認值超過10毫秒判定為慢查詢,需要根據Redis并發量調整該值,慢查詢只記錄命令的執行時間,
并不包括命令排隊和網絡傳輸時間,因此客戶端執行命令的時間會大于命令的實際執行時間,因為命2令執行排隊機制,慢查詢會導致其他命令級聯阻塞,因此客戶端出現請求超時時,需要檢査該時間點是否有對應的慢查詢,從而分析是否為慢查詢導致的命令級聯阻塞.
第二篇章
2.1 持久化原理
2.1.1 原理
redis是內存數據,數據都是存儲在內存中,為了避免進程退出導致數據的永久丟失,需要定期將redis中方的數據以某種形式從內存