文章目錄
- 9.Redis訂閱與發布
- 9.1發布訂閱命令
- 9.2示例
- 10.Redis主從復制
- 10.1概念
- 10.2環境配置
- 10.3集群搭建(一主二從配置)
- 10.4使用規則&原理
- 11.哨兵模式
- 11.1基本概念
- 11.2工作原理
- 11.3使用案例
- 12.緩存穿透,雪崩(待拓展)
- 12.1緩存穿透
- 12.2緩存擊穿
- 12.3緩存雪崩
9.Redis訂閱與發布
Redis 發布訂閱(pub/sub)是一種消息通信模式:發送者(pub)發送消息,訂閱者(sub)接收消息。
Redis 發布訂閱 | 菜鳥教程
9.1發布訂閱命令
下表列出了 redis 發布訂閱常用命令:
9.2示例
------------訂閱端----------------------
127.0.0.1:6379> SUBSCRIBE sakura # 訂閱sakura頻道
Reading messages... (press Ctrl-C to quit) # 等待接收消息
1) "subscribe" # 訂閱成功的消息
2) "sakura"
3) (integer) 1
1) "message" # 接收到來自sakura頻道的消息 "hello world"
2) "sakura"
3) "hello world"
1) "message" # 接收到來自sakura頻道的消息 "hello i am sakura"
2) "sakura"
3) "hello i am sakura"--------------消息發布端-------------------
127.0.0.1:6379> PUBLISH sakura "hello world" # 發布消息到sakura頻道
(integer) 1
127.0.0.1:6379> PUBLISH sakura "hello i am sakura" # 發布消息
(integer) 1-----------------查看活躍的頻道------------
127.0.0.1:6379> PUBSUB channels
1) "sakura"-------------其他指令--------------
#訂閱符合模式的頻道(PSUBSCRIBE)
#訂閱所有以 news. 開頭的頻道
PSUBSCRIBE news.*#退訂指定頻道(UNSUBSCRIBE)
UNSUBSCRIBE sports.news#退訂符合模式的頻道(PUNSUBSCRIBE)
PUNSUBSCRIBE news.*#查看訂閱與發布系統狀態(PUBSUB)
#查看頻道的訂閱者數量
PUBSUB NUMSUB tech.news#查看符合模式的頻道數量
PUBSUB NUMPAT news.*
10.Redis主從復制
10.1概念
主從復制,是指將一臺Redis服務器的數據,復制到其他的Redis服務器。前者稱為主節點(Master/Leader),后者稱為從節點(Slave/Follower), 數據的復制是單向的!只能由主節點復制到從節點(主節點以寫為主、從節點以讀為主)。
默認情況下,每臺Redis服務器都是主節點,一個主節點可以有0個或者多個從節點,但每個從節點只能由一個主節點。
作用
- 數據冗余:主從復制實現了數據的熱備份,是持久化之外的一種數據冗余的方式。
- 故障恢復:當主節點故障時,從節點可以暫時替代主節點提供服務,是一種服務冗余的方式
- 負載均衡:在主從復制的基礎上,配合讀寫分離,由主節點進行寫操作,從節點進行讀操作,分擔服務器的負載;尤其是在多讀少寫的場景下,通過多個從節點分擔負載,提高并發量。
- 高可用基石:主從復制還是哨兵和集群能夠實施的基礎。
為什么使用集群
- 單臺服務器難以負載大量的請求
- 單臺服務器故障率高,系統崩壞概率大
- 單臺服務器內存容量有限。
10.2環境配置
配置文件有一個replication
模塊 。
查看當前庫的信息:info replication
127.0.0.1:6379> info replication
# Replication
role:master # 角色
connected_slaves:0 # 從機數量
master_replid:3b54deef5b7b7b7f7dd8acefa23be48879b4fcff
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
既然需要啟動多個服務,就需要多個配置文件。每個配置文件對應修改以下信息:
- 端口號
- pid文件名
- 日志文件名
- rdb文件名
啟動單機多服務集群:
10.3集群搭建(一主二從配置)
默認情況下,每臺Redis服務器都是主節點;所以只用配置從機即可。
因為是單機多服務,一主(79)二從(80,81)。(這里79是指6379端口,也是服務的標識)。
使用SLAVEOF host port
就可以為從機配置主機了。
然后主機上也能看到從機的狀態:
我們這里是使用命令搭建,是暫時的,真實開發中應該在從機的配置文件中進行配置,這樣的話是永久的。
10.4使用規則&原理
-
從機只能讀,不能寫,主機可讀可寫但是多用于寫。
127.0.0.1:6381> set name sakura # 從機6381寫入失敗 (error) READONLY You can't write against a read only replica.127.0.0.1:6380> set name sakura # 從機6380寫入失敗 (error) READONLY You can't write against a read only replica.127.0.0.1:6379> set name sakura OK 127.0.0.1:6379> get name "sakura"
-
當主機斷電宕機后,默認情況下從機的角色不會發生變化 ,集群中只是失去了寫操作,當主機恢復以后,又會連接上從機恢復原狀。
-
當從機斷電宕機后,若不是使用配置文件配置的從機,再次啟動后作為主機是無法獲取之前主機的數據的,若此時重新配置稱為從機,又可以獲取到主機的所有數據。這里就要提到一個同步原理。
-
第二條中提到,默認情況下,主機故障后,不會出現新的主機,有兩種方式可以產生新的主機:
- 從機手動執行命令
slaveof no one
,這樣執行以后從機會獨立出來成為一個主機。(人為選定,哪個從機執行的命令哪個就會變為主機) - 使用哨兵模式(自動選舉)
- 從機手動執行命令
如果主機斷開了連接,我們可以使用SLAVEOF no one
讓自己變成主機!其他的節點就可以手動連接到最新的主節點(手動)!如果這個時候舊主機修復了,如果想恢復之前的主從模式,需要重新連接,也就是說新主機還是作為集群主機,而恢復的舊主機相當于一個單獨的redis服務(默認主機)。
如果有新的從機進入集群,則會和集群的數據保持一致,總之,集群的數據總是一致的,無論宕機重連還是新增從機。那他是如何保證的呢?
- 全量復制
- 主節點執行
BGSAVE
生成 RDB 文件,并將文件發送給從節點。 - 從節點清空當前數據,加載 RDB 文件。
- 主節點執行
- 增量復制
- 主節點將寫命令寫入復制緩沖區(replication buffer)。
- 從節點通過長連接接收這些命令并執行,保持數據同步。
11.哨兵模式
Redis 哨兵(Sentinel)模式是在主從復制的基礎上,為了實現 Redis 主節點故障自動切換而設計的一種高可用方案。它可以自動監控 Redis 主節點和從節點的運行狀態,當主節點出現故障時,自動將一個從節點晉升為主節點,其他從節點指向新的主節點進行數據復制,從而保證系統的高可用性。
11.1基本概念
- 哨兵節點:哨兵模式由一個或多個哨兵節點組成,哨兵節點是特殊的 Redis 節點,不存儲數據,主要負責監控 Redis 主從節點的運行狀態,并且在主節點出現故障時自動執行故障轉移操作。
- 監控:哨兵節點會定期向主節點和從節點發送 PING 命令,通過節點的響應情況判斷節點是否正常運行。
- 故障轉移:當哨兵節點發現主節點出現故障(主觀下線和客觀下線判斷)后,會從從節點中挑選一個合適的節點晉升為主節點,然后通知其他從節點切換到新的主節點進行數據復制。
單哨兵模式:
多哨兵模式:
11.2工作原理
- 監控:哨兵節點以一定的頻率向主節點和從節點發送心跳檢測命令(PING 命令),以判斷節點是否正常運行。每個哨兵節點都有一個
down-after-milliseconds
配置參數,用于指定如果在指定時間內沒有收到節點的響應,就認為該節點主觀下線(Subjectively Down,簡稱 SDOWN)。 - 主觀下線判斷:如果一個哨兵節點發現主節點在
down-after-milliseconds
時間內沒有響應 PING 命令,或者直接連接主節點失敗,那么這個哨兵節點就會將主節點標記為主觀下線狀態。 - 客觀下線判斷:當一個哨兵節點將主節點標記為主觀下線后,它會向其他哨兵節點發送
is-master-down-by-addr
命令,詢問其他哨兵節點對主節點的判斷。當有足夠數量(超過配置的quorum
值)的哨兵節點都認為主節點主觀下線時,就會將主節點標記為客觀下線(Objectively Down,簡稱 ODOWN)。只有主節點會被標記為客觀下線,從節點只會被標記為主觀下線。 - 故障轉移:當主節點被標記為客觀下線后,哨兵節點會發起一次選舉(投票/選舉算法),選舉出一個哨兵節點來執行故障轉移操作。選舉過程基于 Raft 算法實現。被選舉出的哨兵節點會從從節點中挑選一個節點晉升為主節點,挑選依據包括節點的優先級(
slave-priority
配置)、復制偏移量(復制的數據量)等。然后,哨兵節點會向新的主節點發送slaveof no one
命令,使其成為主節點,接著向其他從節點發送slaveof
命令,讓它們指向新的主節點進行數據復制。 - 通知:故障轉移完成后,哨兵節點會向客戶端發送通知,告知主節點已經發生了變化。
11.3使用案例
在 Redis 哨兵模式里,每個哨兵都是以獨立進程的形式存在。可以通過 redis-sentinel
命令來啟動哨兵服務。
哨兵的核心配置
sentinel monitor mymaster 127.0.0.1 6379 1
- 數字1表示 :當一個哨兵主觀認為主機斷開,就可以客觀認為主機故障,然后開始選舉新的主機。
測試(xxx代表配置文件路徑)
redis-sentinel xxx/sentinel.conf
成功啟動哨兵模式
此時哨兵監視著我們的主機6379,當我們斷開主機后:
哨兵模式優缺點
優點:
- 哨兵集群,基于主從復制模式,所有主從復制的優點它都有
- 主從可以切換,故障可以轉移,系統的可用性更好
- 哨兵模式是主從模式的升級,手動到自動,更加健壯
缺點:
- Redis不好在線擴容,集群容量一旦達到上限,在線擴容就十分麻煩
- 實現哨兵模式的配置其實是很麻煩的,里面有很多配置項
完整的哨兵模式配置文件 sentinel.conf
# Example sentinel.conf# 哨兵sentinel實例運行的端口 默認26379
port 26379# 哨兵sentinel的工作目錄
dir /tmp# 哨兵sentinel監控的redis主節點的 ip port
# master-name 可以自己命名的主節點名字 只能由字母A-z、數字0-9 、這三個字符".-_"組成。
# quorum 當這些quorum個數sentinel哨兵認為master主節點失聯 那么這時 客觀上認為主節點失聯了
# sentinel monitor <master-name> <ip> <redis-port> <quorum>
sentinel monitor mymaster 127.0.0.1 6379 1# 當在Redis實例中開啟了requirepass foobared 授權密碼 這樣所有連接Redis實例的客戶端都要提供密碼
# 設置哨兵sentinel 連接主從的密碼 注意必須為主從設置一樣的驗證密碼
# sentinel auth-pass <master-name> <password>
sentinel auth-pass mymaster MySUPER--secret-0123passw0rd# 指定多少毫秒之后 主節點沒有應答哨兵sentinel 此時 哨兵主觀上認為主節點下線 默認30秒
# sentinel down-after-milliseconds <master-name> <milliseconds>
sentinel down-after-milliseconds mymaster 30000# 這個配置項指定了在發生failover主備切換時最多可以有多少個slave同時對新的master進行 同步,
這個數字越小,完成failover所需的時間就越長,
但是如果這個數字越大,就意味著越 多的slave因為replication而不可用。
可以通過將這個值設為 1 來保證每次只有一個slave 處于不能處理命令請求的狀態。
# sentinel parallel-syncs <master-name> <numslaves>
sentinel parallel-syncs mymaster 1# 故障轉移的超時時間 failover-timeout 可以用在以下這些方面:
#1. 同一個sentinel對同一個master兩次failover之間的間隔時間。
#2. 當一個slave從一個錯誤的master那里同步數據開始計算時間。直到slave被糾正為向正確的master那里同步數據時。
#3.當想要取消一個正在進行的failover所需要的時間。
#4.當進行failover時,配置所有slaves指向新的master所需的最大時間。不過,即使過了這個超時,slaves依然會被正確配置為指向master,但是就不按parallel-syncs所配置的規則來了
# 默認三分鐘
# sentinel failover-timeout <master-name> <milliseconds>
sentinel failover-timeout mymaster 180000# SCRIPTS EXECUTION#配置當某一事件發生時所需要執行的腳本,可以通過腳本來通知管理員,例如當系統運行不正常時發郵件通知相關人員。
#對于腳本的運行結果有以下規則:
#若腳本執行后返回1,那么該腳本稍后將會被再次執行,重復次數目前默認為10
#若腳本執行后返回2,或者比2更高的一個返回值,腳本將不會重復執行。
#如果腳本在執行過程中由于收到系統中斷信號被終止了,則同返回值為1時的行為相同。
#一個腳本的最大執行時間為60s,如果超過這個時間,腳本將會被一個SIGKILL信號終止,之后重新執行。#通知型腳本:當sentinel有任何警告級別的事件發生時(比如說redis實例的主觀失效和客觀失效等等),將會去調用這個腳本,
#這時這個腳本應該通過郵件,SMS等方式去通知系統管理員關于系統不正常運行的信息。調用該腳本時,將傳給腳本兩個參數,
#一個是事件的類型,
#一個是事件的描述。
#如果sentinel.conf配置文件中配置了這個腳本路徑,那么必須保證這個腳本存在于這個路徑,并且是可執行的,否則sentinel無法正常啟動成功。
#通知腳本
# sentinel notification-script <master-name> <script-path>sentinel notification-script mymaster /var/redis/notify.sh# 客戶端重新配置主節點參數腳本
# 當一個master由于failover而發生改變時,這個腳本將會被調用,通知相關的客戶端關于master地址已經發生改變的信息。
# 以下參數將會在調用腳本時傳給腳本:
# <master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port>
# 目前<state>總是“failover”,
# <role>是“leader”或者“observer”中的一個。
# 參數 from-ip, from-port, to-ip, to-port是用來和舊的master和新的master(即舊的slave)通信的
# 這個腳本應該是通用的,能被多次調用,不是針對性的。
# sentinel client-reconfig-script <master-name> <script-path>
sentinel client-reconfig-script mymaster /var/redis/reconfig.sh
12.緩存穿透,雪崩(待拓展)
12.1緩存穿透
緩存穿透:緩存穿透是指客戶端請求的數據在緩存和數據庫中都不存在,導致請求每次都 “穿透” 緩存,直接擊中數據庫。由于緩存無法命中,所有請求都會落到數據庫上,若存在大量此類請求(如惡意攻擊),可能導致數據庫過載宕機。
解決方案
- 緩存空值
當數據庫查詢結果為空時,在緩存中存儲一個空值(如null
),并設置較短的過期時間(避免長期占用緩存)。后續相同請求會直接命中緩存的空值,不再訪問數據庫。
示例:查詢user:999999
返回空,緩存user:999999 → null
,過期時間設為 5 分鐘。 - 布隆過濾器
在緩存層之前添加布隆過濾器,預先存儲所有可能存在的合法數據(如用戶 ID、商品 ID)。請求到來時,先通過布隆過濾器判斷數據是否存在:- 若不存在,直接返回空,不訪問緩存和數據庫;
- 若存在(存在一定誤判率),再走正常的緩存→數據庫流程。
適合場景:數據量極大(如 10 億級 ID),且對誤判可容忍的場景。
- 接口層限流與校驗
對接口添加限流措施(如限制每秒請求量),并校驗請求參數的合法性(如用戶 ID 格式是否正確),過濾明顯的惡意請求。
12.2緩存擊穿
概念
相較于緩存穿透,緩存擊穿的目的性更強,一個存在的key,在緩存過期的一刻,同時有大量的請求,這些請求都會擊穿到DB,造成瞬時DB請求量大、壓力驟增。這就是緩存被擊穿,只是針對其中某個key的緩存不可用而導致擊穿,但是其他的key依然可以使用緩存響應。
比如熱搜排行上,一個熱點新聞被同時大量訪問就可能導致緩存擊穿。
解決方案
-
設置熱點數據永不過期
這樣就不會出現熱點數據過期的情況,但是當Redis內存空間滿的時候也會清理部分數據,而且此種方案會占用空間,一旦熱點數據多了起來,就會占用部分空間。
-
加互斥鎖(分布式鎖)
在訪問key之前,采用SETNX(set if not exists)來設置另一個短期key來鎖住當前key的訪問,訪問結束再刪除該短期key。保證同時刻只有一個線程訪問。這樣對鎖的要求就十分高。
12.3緩存雪崩
緩存雪崩:緩存雪崩是指大量緩存 key 在同一時間過期失效,或緩存服務器整體故障(如 Redis 集群宕機),導致所有請求瞬間落到數據庫上,造成數據庫壓力激增,甚至崩潰。
常見原因
- 批量設置緩存時,使用了相同的過期時間(如凌晨 0 點統一過期)。
- Redis 集群因網絡故障、硬件問題等整體不可用。
解決方案
-
redis高可用
這個思想的含義是,既然redis有可能掛掉,那我多增設幾臺redis,這樣一臺掛掉之后其他的還可以繼續工作,其實就是搭建的集群
-
限流降級
這個解決方案的思想是,在緩存失效后,通過加鎖或者隊列來控制讀數據庫寫緩存的線程數量。比如對某個key只允許一個線程查詢數據和寫緩存,其他線程等待。
-
數據預熱
數據加熱的含義就是在正式部署之前,我先把可能的數據先預先訪問一遍,這樣部分可能大量訪問的數據就會加載到緩存中。在即將發生大并發訪問前手動觸發加載緩存不同的key,設置不同的過期時間,讓緩存失效的時間點盡量均勻。