redis分布式設(shè)計(jì)的實(shí)現(xiàn)示例
Redis 的分布式設(shè)計(jì)主要通過三種模式實(shí)現(xiàn),每種模式解決不同的問題:
一、三種分布式模式對(duì)比
| 模式 | 解決的問題 | 數(shù)據(jù)關(guān)系 | 適用場景 |
|---|---|---|---|
| 主從復(fù)制 | 讀寫分離、數(shù)據(jù)備份 | 全量復(fù)制 | 讀多寫少、數(shù)據(jù)備份 |
| 哨兵模式 | 高可用、自動(dòng)故障轉(zhuǎn)移 | 全量復(fù)制 | 需要自動(dòng)容災(zāi) |
| Cluster 集群 | 水平擴(kuò)展、海量數(shù)據(jù) | 分片存儲(chǔ) | 數(shù)據(jù)量大、需要擴(kuò)展 |
二、主從復(fù)制(Replication)
核心機(jī)制
┌─────────┐ 全量/增量復(fù)制 ┌─────────┐
│ Master │ ───────────────────────────? │ Slave │
│ (寫) │ │ (讀) │
└─────────┘ └─────────┘
復(fù)制流程
1. Slave 發(fā)送 SYNC/PSYNC 命令 2. Master 執(zhí)行 BGSAVE,生成 RDB 文件 3. Master 將 RDB 發(fā)送給 Slave 4. Slave 加載 RDB 5. 后續(xù)寫命令實(shí)時(shí)同步(增量復(fù)制)
關(guān)鍵配置
# slave 配置 replicaof 192.168.1.10 6379 masterauth <password> # 只讀(默認(rèn)) replica-read-only yes
問題
- 無法自動(dòng)故障轉(zhuǎn)移:Master 掛了需要手動(dòng)切換
- 寫壓力集中在 Master
- 復(fù)制延遲:Slave 數(shù)據(jù)可能落后
三、哨兵模式(Sentinel)
在主從基礎(chǔ)上增加自動(dòng)監(jiān)控和故障轉(zhuǎn)移。
架構(gòu)
┌─────────┐
│ Client │
└────┬────┘
│
┌────────┼────────┐
▼ ▼ ▼
┌───────┐ ┌───────┐ ┌───────┐
│Sentinel│ │Sentinel│ │Sentinel│ (至少3個(gè),投票決策)
│ 1 │ │ 2 │ │ 3 │
└────┬───┘ └────┬───┘ └────┬───┘
│ │ │
└──────────┼──────────┘
▼
┌─────────────┐
│ Master │
└──────┬──────┘
│
┌──────┴──────┐
▼ ▼
┌───────┐ ┌───────┐
│ Slave1│ │ Slave2│
└───────┘ └───────┘
哨兵的核心功能
| 功能 | 說明 |
|---|---|
| 監(jiān)控 | 定期檢查 Master/Slave 是否存活 |
| 通知 | 故障時(shí)通知管理員或其他應(yīng)用 |
| 自動(dòng)故障轉(zhuǎn)移 | Master 宕機(jī)時(shí),選舉 Slave 為新 Master |
| 配置提供者 | 客戶端向 Sentinel 詢問當(dāng)前 Master 地址 |
故障轉(zhuǎn)移流程
1. 主觀下線(SDOWN):某個(gè) Sentinel 發(fā)現(xiàn) Master 無響應(yīng)
2. 客觀下線(ODOWN):多個(gè) Sentinel 投票確認(rèn) Master 故障
3. 選舉 Leader Sentinel:Raft 算法投票
4. 選擇最優(yōu) Slave(優(yōu)先級(jí)高、復(fù)制偏移量大、RunID?。?br />5. 提升為 Master,其他 Slave 重新配置
6. 通知客戶端更新 Master 地址
客戶端連接方式
# Python 示例:Sentinel 自動(dòng)發(fā)現(xiàn) Master
from redis.sentinel import Sentinel
sentinel = Sentinel([
('sentinel1', 26379),
('sentinel2', 26379),
('sentinel3', 26379)
])
# 自動(dòng)獲取當(dāng)前 Master
master = sentinel.master_for('mymaster', password='xxx')
slave = sentinel.slave_for('mymaster', password='xxx')
master.set('key', 'value')
value = slave.get('key')缺點(diǎn)
- 只有一個(gè) Master 寫,無法水平擴(kuò)展寫性能
- 數(shù)據(jù)量受限于單節(jié)點(diǎn)內(nèi)存
四、Cluster 集群(最核心)
Redis 真正的分布式方案,通過數(shù)據(jù)分片實(shí)現(xiàn)水平擴(kuò)展。
架構(gòu)
┌─────────────────────────────────────────────┐
│ Redis Cluster │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Node 1 │ │ Node 2 │ │ Node 3 │ │
│ │ [0-5460]│ │[5461-10922]│[10923-16383] │
│ │ Master A│ │ Master B│ │ Master C│ │
│ └───┬─────┘ └────┬────┘ └────┬────┘ │
│ │ │ │ │
│ ┌───┴───┐ ┌───┴───┐ ┌───┴───┐ │
│ │Slave A1│ │Slave B1│ │Slave C1│ │
│ └────────┘ └────────┘ └────────┘ │
│ │
│ 16384 個(gè)哈希槽(Slot)均勻分配到各 Master │
└─────────────────────────────────────────────┘
核心概念:哈希槽(Hash Slot)
Slot = CRC16(key) % 16384 key "user:1000" → CRC16 = 12345 → 12345 % 16384 = 12345 → 屬于 Node 3
為什么用 16384 個(gè)槽?
- CRC16 輸出范圍 0~65535
- 16384 = 2^14,平衡了元數(shù)據(jù)大小和分片粒度
- 集群節(jié)點(diǎn)配置中傳播的是槽位映射,不是具體 key
節(jié)點(diǎn)通信:Gossip 協(xié)議
每個(gè)節(jié)點(diǎn)每秒隨機(jī)向幾個(gè)其他節(jié)點(diǎn)發(fā)送 PING
攜帶:自身狀態(tài) + 已知其他節(jié)點(diǎn)的狀態(tài)
通過"謠言傳播"方式,最終整個(gè)集群狀態(tài)一致
客戶端路由
┌─────────┐
│ Client │
└────┬────┘
│ SET key value
▼
┌─────────┐ 計(jì)算 key 的 Slot
│ Node 1 │ 發(fā)現(xiàn) Slot 不在本地
└────┬────┘
│ 返回 MOVED 錯(cuò)誤,告知正確節(jié)點(diǎn)
▼
┌─────────┐
│ Client │ 重定向到正確節(jié)點(diǎn)
└────┬────┘
▼
┌─────────┐
│ Node 3 │ 執(zhí)行命令
└─────────┘
Smart Client(如 redis-py-cluster)會(huì)緩存槽位映射,減少重定向。
數(shù)據(jù)遷移(擴(kuò)容/縮容)
1. 新節(jié)點(diǎn)加入集群
2. 分配部分 Slot 給新節(jié)點(diǎn)(如從 Node1 遷 1000 個(gè) Slot)
3. 遷移過程中:
- 源節(jié)點(diǎn):遷出的 Slot 標(biāo)記為 IMPORTING
- 目標(biāo)節(jié)點(diǎn):標(biāo)記為 MIGRATING
- 遷移中的 key:先查源節(jié)點(diǎn),沒有則查目標(biāo)節(jié)點(diǎn)
4. 遷移完成后更新槽位映射
Cluster 配置示例
# redis.conf cluster-enabled yes cluster-config-file nodes-6379.conf cluster-node-timeout 5000 cluster-require-full-coverage no # 部分槽不可用時(shí)不拒絕所有請(qǐng)求
# 創(chuàng)建集群(6 節(jié)點(diǎn),3 主 3 從) redis-cli --cluster create \ 192.168.1.11:6379 192.168.1.12:6379 192.168.1.13:6379 \ 192.168.1.14:6379 192.168.1.15:6379 192.168.1.16:6379 \ --cluster-replicas 1
五、三種模式對(duì)比總結(jié)
| 維度 | 主從復(fù)制 | 哨兵模式 | Cluster 集群 |
|---|---|---|---|
| 數(shù)據(jù)容量 | 單機(jī)內(nèi)存 | 單機(jī)內(nèi)存 | 多機(jī)總和 |
| 寫性能 | 單機(jī) | 單機(jī) | 水平擴(kuò)展 |
| 讀性能 | 擴(kuò)展 | 擴(kuò)展 | 擴(kuò)展 |
| 高可用 | 手動(dòng)切換 | 自動(dòng)切換 | 自動(dòng)切換 |
| 數(shù)據(jù)分片 | 否 | 否 | 是 |
| 復(fù)雜度 | 低 | 中 | 高 |
六、生產(chǎn)環(huán)境建議
| 場景 | 推薦方案 |
|---|---|
| 數(shù)據(jù) < 10GB,讀多寫少 | 主從 + 哨兵 |
| 數(shù)據(jù) > 10GB 或需要擴(kuò)展寫 | Cluster 集群 |
| 需要跨機(jī)房容災(zāi) | Cluster + 主從交叉部署 |
| 超大規(guī)模(TB 級(jí)) | 業(yè)務(wù)分片 + 多 Cluster |
七、常見問題
1. Cluster 的 key 限制
# 默認(rèn)不支持跨 Slot 的多 key 操作
MGET key1 key2 # 如果 key1 和 key2 在不同 Slot,報(bào)錯(cuò)
# 解決方案:Hash Tag
MGET {user:1000}:name {user:1000}:age
# {} 內(nèi)內(nèi)容用于計(jì)算 Slot,確保同一用戶數(shù)據(jù)在同一節(jié)點(diǎn)
2. 腦裂問題
網(wǎng)絡(luò)分區(qū)時(shí),原 Master 和 Sentinel 隔離
Sentinel 選舉新 Master → 出現(xiàn)兩個(gè) Master
解決方案:min-slaves-to-write 配置,確保有足夠 Slave 才接受寫
3. 數(shù)據(jù)傾斜
Big Key 或 Hash Tag 使用不當(dāng)導(dǎo)致某些 Slot 數(shù)據(jù)量過大
解決方案:監(jiān)控 Slot 大小,避免 Big Key,合理設(shè)計(jì) key
到此這篇關(guān)于redis分布式設(shè)計(jì)的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)redis分布式設(shè)計(jì)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
redis調(diào)用二維碼時(shí)的不斷刷新排查分析
這篇文章主要為大家介紹了redis調(diào)用二維碼時(shí)不斷刷新排查分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04
為什么斷電后Redis數(shù)據(jù)不會(huì)丟失
Redis 作為一款內(nèi)存數(shù)據(jù)庫,被廣泛使用于緩存,分布式鎖等場景,那么假如斷電或者因其他因素導(dǎo)致 Reids 服務(wù)宕機(jī),在重啟之后數(shù)據(jù)會(huì)丟失嗎?本文就來介紹與一下2021-08-08
Redis進(jìn)行驗(yàn)證碼登錄的項(xiàng)目實(shí)踐
本文主要介紹了Redis進(jìn)行驗(yàn)證碼登錄的項(xiàng)目實(shí)踐,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2025-09-09
Redis查看KEY的數(shù)據(jù)類型的方法和步驟
在Redis中,可以使用 TYPE 命令來查看指定key的數(shù)據(jù)類型,該命令會(huì)返回存儲(chǔ)在指定key中的值的數(shù)據(jù)類型,本文給大家介紹了具體的使用方法和步驟,感興趣的朋友可以參考下2024-04-04
Redis存儲(chǔ)的列表分頁和檢索的實(shí)現(xiàn)方法
在 Redis 中,列表(List)是一種有序的數(shù)據(jù)結(jié)構(gòu),通常用于存儲(chǔ)一系列元素,由于列表是有序的,可以通過索引來訪問元素,因此可以很方便地實(shí)現(xiàn)分頁和檢索功能,以下是 Redis 列表的分頁和檢索的實(shí)現(xiàn)方法,需要的朋友可以參考下2025-02-02

