
Redis 內容及相關實驗Redis 就像一個請了個「24 小時不睡覺、記憶力還超群」的數據管家你把數據丟給它它直接放在內存里隨取隨用快得離譜。目錄Redis 簡介Redis 安裝部署Redis 主從復制Redis 哨兵模式 SentinelRedis Cluster 集群三種高可用方案對比小結總結一、Redis 簡介1.1 Redis 是什么RedisRemote Dictionary Server是一個開源的、基于內存的鍵值對Key-Value數據庫。它把所有數據放在內存里因此讀寫速度能達到10 萬 QPS同時通過 RDB / AOF 把數據落地到磁盤宕機后也能恢復所以它既快又不怕丟。它和 MySQL 這種把數據放硬盤、用的時候再讀的傳統關系型數據庫不一樣MySQL 是倉庫規整但取貨慢Redis 是手邊的保險柜隨手就能拿。典型使用場景場景說明緩存Cache把熱點數據放 Redis擋在數據庫前面扛住高并發讀數據庫DB直接當主存儲配合持久化保證數據不丟消息隊列 / 發布訂閱用 List、Stream 做輕量隊列、用 Pub/Sub 做消息廣播排行榜 / 計數器用 ZSet、incr 做實時排名、訪問計數分布式鎖用SET key value NX實現跨進程互斥1.2 為什么這么快數據在內存沒有磁盤 IO 瓶頸單線程模型避免了多線程上下文切換和鎖競爭6.0 后引入多線程 IO但命令執行仍是單線程IO 多路復用epoll一個線程就能同時hold住海量連接高效的數據結構SDS、跳表、哈希表等底層結構都為性能量身設計。1.3 數據類型Redis 的 key 都是字符串value 支持多種結構。記住五大基礎類型 擴展類型就夠了String字符串最常用可存文本、數字、序列化對象支持incr自增List列表雙向鏈表可做隊列 / 棧Hash哈希鍵值對集合適合存對象屬性如用戶資料Set集合無序去重支持交集/并集做共同好友、抽獎ZSet有序集合帶分數的有序集合做排行榜神器擴展類型Bitmaps位圖在線狀態、HyperLogLogUV 統計、Geospatial地理附近的人、Streams消息流。1.4 持久化RDB 與 AOF內存數據斷電即失所以 Redis 提供兩種持久化方式生產環境建議兩個都開RDB快照定時把內存全量數據 dump 成.rdb二進制文件。文件小、恢復快適合備份缺點是可能丟最后一次快照之后的數據。AOF日志把每一條寫命令追加到.aof文件。數據更安全可配置每秒/每次刷盤文件大、恢復稍慢。重啟時 Redis優先用 AOF恢復數據更全RDB 主要用來做快速備份和主從全量同步。二、Redis 安裝部署實驗實驗環境3 臺機器redis-node1/2/3IP 分別為172.25.254.10/20/30系統已配置好主機名解析。以下以 node1 為例其余節點同樣操作。2.1 安裝依賴[rootredis-node1 ~]# dnf install make gcc initscripts -y2.2 源碼編譯安裝[rootredis-node1 ~]# wget https://download.redis.io/releases/redis-7.4.8.tar.gz[rootredis-node1 ~]# tar zxf redis-7.4.8.tar.gz[rootredis-node1 ~]# cd redis-7.4.8/[rootredis-node1 redis-7.4.8]# make make install2.3 用腳本生成服務install_server.shRedis 自帶utils/install_server.sh可以一鍵生成 systemd 可管理的服務。systemd環境下腳本默認會退出需要先把它的 systemd 檢測注釋掉[rootredis-node1 redis-7.4.8]# cd utils/[rootredis-node1 utils]# vim install_server.sh# 把下面這段 systemd 檢測注釋掉否則腳本直接 exit#_pid_1_exe$(readlink -f /proc/1/exe)#if [ ${_pid_1_exe##*/} systemd ]#then# echo This systems seems to use systemd.# ...#fi[rootredis-node1 utils]# ./install_server.sh交互提示一路回車用默認值關鍵配置如下Please select the redis port for this instance: [6379] Please select the redis config file name [/etc/redis/6379.conf] /etc/redis/redis.conf Please select the redis log file name [/var/log/redis_6379.log] Please select the data directory for this instance [/var/lib/redis/6379] Please select the redis executable path [/usr/local/bin/redis-server] ... Installation successful!2.4 放開監聽并啟動編輯配置文件關閉保護模式、允許所有網卡監聽[rootredis-node1 utils]# vim /etc/redis/redis.conf# 約 89 行允許所有 IP 監聽bind* -::*# 約 113 行關閉保護模式實驗環境生產請配合密碼/防火墻protected-mode no[rootredis-node1 utils]# systemctl daemon-reload[rootredis-node1 utils]# systemctl start redis_6379.service[rootredis-node1 utils]# systemctl status redis_6379.service2.5 驗證端口監聽[rootredis-node1 ~]# netstat -antlpe | grep redistcp00127.0.0.1:63790.0.0.0:* LISTEN... redis-server tcp00::1:6379 :::* LISTEN... redis-server看到6379端口處于LISTEN說明 Redis 已經跑起來了。node2、node3用同樣的步驟安裝即可。三、Redis 主從復制3.1為什么需要主從復制單節點 Redis 有兩個痛點單點故障掛了就全完和讀壓力集中。主從復制讓一個 Master 把數據同步給多個 Slave讀寫分離Master 負責寫Slave 負責讀分攤壓力數據冗余Slave 是 Master 的備份復制方式首次是全量復制RDB 快照之后是增量復制命令流。注意默認 Slave 是只讀的不能在從節點上寫數據。3.2 實驗搭建一主兩從① 配置主節點node1[rootredis-node1 ~]# vim /etc/redis/redis.conf#bind 127.0.0.1 -::1bind* -::* protected-mode no[rootredis-node1 ~]# systemctl restart redis_6379.service② 配置兩個從節點node2、node3# 在 redis-node2 節點[rootredis-node2 ~]# vim /etc/redis/redis.conf#bind 127.0.0.1 -::1bind* -::* protected-mode no replicaof172.25.254.106379# 指向主節點 IP 端口[rootredis-node2 ~]# systemctl restart redis_6379.service# 在 redis-node3 節點[rootredis-node3 ~]# vim /etc/redis/redis.conf#bind 127.0.0.1 -::1bind* -::* protected-mode no replicaof172.25.254.106379[rootredis-node3 ~]# systemctl restart redis_6379.service3.3 驗證復制狀態主節點查看node1[rootredis-node1 ~]# redis-cli127.0.0.1:6379info replication# Replicationrole:master connected_slaves:2 slave0:ip172.25.254.20,port6379,stateonline,offset391,lag0slave1:ip172.25.254.30,port6379,stateonline,offset391,lag1master_replid:e5f5cddc017ab0d5223213592d0482b832d3af77 master_repl_offset:391看到role:master且connected_slaves:2兩個 slave 都是online說明主從建立成功。從節點查看node2[rootredis-node2 ~]# redis-cli127.0.0.1:6379info replication# Replicationrole:slave master_host:172.25.254.10 master_port:6379 master_link_status:up# 與主節點連接正常slave_read_only:1# 從節點只讀3.4 測試數據同步 從節點只讀在主節點寫數據從節點立刻能讀到# 主節點 node1 寫入[rootredis-node1 ~]# redis-cli127.0.0.1:6379setname lee OK127.0.0.1:6379get namelee# 從節點 node2 / node3 讀取[rootredis-node2 ~]# redis-cli127.0.0.1:6379get namelee嘗試在從節點寫入會被拒絕[rootredis-node3 ~]# redis-cli127.0.0.1:6379get namelee127.0.0.1:6379settest123(error)READONLY You cantwriteagainst areadonly replica.? 主從復制 讀寫分離驗證通過。四、Redis 哨兵模式 Sentinel4.1主從的短板靠哨兵補主從復制解決了讀壓力和數據備份但Master 掛了沒人自動頂上。哨兵Sentinel就是來干這活的——一組哨兵進程專門盯著 Master發現它真掛了自動把一個 Slave 提升為新 Master并讓其他節點改認新主。幾個關鍵概念監控Monitoring哨兵持續 ping 主從節點主觀下線sdown某個哨兵自己覺得節點連不上了客觀下線odown達到quorum個哨兵都認為下線才確認真掛了故障轉移failover選舉領頭哨兵 → 選一個 Slave 提升 → 通知其余節點quorum認定主節點下線的票數實驗中設為 2即至少 2 個哨兵同意。4.2 實驗搭建哨兵① 主節點復制并編輯哨兵配置[rootredis-node1 ~]# cd redis-7.4.8/[rootredis-node1 redis-7.4.8]# cp -p sentinel.conf /etc/redis/[rootredis-node1 ~]# vim /etc/redis/sentinel.confprotected-mode no# 關閉保護模式port26379# 哨兵監聽端口daemonize no# 前臺運行方便看日志pidfile /var/run/redis-sentinel.pid loglevel notice sentinel monitor mymaster172.25.254.1063792# 監控 mymasterquorum2sentinel down-after-milliseconds mymaster10000# 10 秒連不上視為下線sentinel parallel-syncs mymaster1# 故障轉移后同時同步新主的 slave 數sentinel failover-timeout mymaster180000# 故障切換超時 3 分鐘?? 原參考文檔此處寫的是172.25.254.100應為實際 master 的172.25.254.10本文已修正否則哨兵會監控一個不存在的地址。② 從節點也關閉保護模式[rootredis-node2 ~]# vim /etc/redis/redis.confprotected-mode no[rootredis-node2 ~]# systemctl restart redis_6379.service[rootredis-node3 ~]# vim /etc/redis/redis.confprotected-mode no[rootredis-node3 ~]# systemctl restart redis_6379.service③ 把哨兵配置發給兩個從節點三臺一起啟動[rootredis-node1 ~]# scp /etc/redis/sentinel.conf root172.25.254.20:/etc/redis/[rootredis-node1 ~]# scp /etc/redis/sentinel.conf root172.25.254.30:/etc/redis/# 三臺節點都執行[rootredis-node1 ~]# redis-sentinel /etc/redis/sentinel.conf啟動后日志里能看到哨兵發現了 master 和兩個 slave以及彼此# monitor master mymaster 172.25.254.10 6379 quorum 2* slave slave172.25.254.20:6379... mymaster172.25.254.106379* slave slave172.25.254.30:6379... mymaster172.25.254.106379* sentinel sentinel 28f2f3da...172.25.254.2026379 mymaster... * sentinel sentinel89568283...172.25.254.3026379 mymaster...4.3 實驗測試故障切換① 干掉主節點[rootredis-node1 ~]# redis-cli127.0.0.1:6379SHUTDOWN not connected② 觀察哨兵日志故障轉移過程# sdown master mymaster 172.25.254.10 6379 # 主觀下線# odown master mymaster 172.25.254.10 6379 #quorum 2/2 # 客觀下線# try-failover master mymaster ...# vote-for-leader d0780e7f... 1 # 投票選領頭哨兵# selected-slave slave 172.25.254.20:6379 ... # 選中 .20 提升# promoted-slave slave 172.25.254.20:6379 ... # 提升為 master# failover-end master mymaster 172.25.254.10 6379# switch-master mymaster 172.25.254.10 6379 172.25.254.20 6379 # 主切換到 .20③ 在 node3 上確認已認新主[rootredis-node3 ~]# redis-cli127.0.0.1:6379info replication# Replicationrole:slave master_host:172.25.254.20# 已經指向新主 .20master_port:6379 master_link_status:up④ 恢復原主節點node1[rootredis-node1 ~]# /etc/init.d/redis_6379 start原主重啟后變成新主的從節點在 node2 上能看到[rootredis-node2 ~]# redis-cli127.0.0.1:6379info replication# Replicationrole:master connected_slaves:2 slave0:ip172.25.254.30,port6379,stateonline,... slave1:ip172.25.254.10,port6379,stateonline,...# 原主 .10 已成為從? 哨兵自動故障轉移驗證通過。五、Redis Cluster 集群5.1 理論集群解決了什么哨兵解決了主掛了自動切換但它只有一個 Master 寫寫能力和存儲容量都有上限。Redis Cluster 是分布式方案數據分片把數據按slot CRC16(key) % 16384分到 16384 個哈希槽槽平均分配到多個 Master無中心化客戶端連任意節點節點算槽后命中自己就處理否則返回MOVED重定向內置高可用每個 Master 配 SlaveMaster 宕機其 Slave 自動接管槽不需要哨兵在線擴縮容槽可以在節點間遷移集群不中斷。5.2 實驗環境6 臺機器172.25.254.10 ~ 60其中.10/.20/.30為 Master.40/.50/.60為對應 Slave。5.3 配置集群節點6 臺節點都執行以下配置先設主從認證、開啟 cluster[rootredis-node1 ~]# vim /etc/redis/6379.confmasterauth123456# 集群主從認證密碼cluster-enabledyes# 開啟 cluster 功能cluster-config-file nodes-6379.conf# 集群配置文件cluster-node-timeout15000# 節點超時ms[rootredis-node1 ~]# /etc/init.d/redis_6379 stop[rootredis-node1 ~]# /etc/init.d/redis_6379 start# 首次搭建先清掉舊數據已有數據時必須[rootredis-node1 ~]# redis-cli127.0.0.1:6379flushall127.0.0.1:6379CLUSTER RESET HARD5.4 創建集群一條命令拉起 3 主 3 從--cluster-replicas 1表示每個 Master 配 1 個 Slave[rootredis-node1 ~]# redis-cli --cluster create \172.25.254.10:6379172.25.254.20:6379172.25.254.30:6379\172.25.254.40:6379172.25.254.50:6379172.25.254.60:6379\--cluster-replicas1輸出關鍵片段自動分配槽位和主從Master[0] - Slots 0 - 5460 Master[1] - Slots 5461 - 10922 Master[2] - Slots 10923 - 16383 Adding replica 172.25.254.50:6379 to 172.25.254.10:6379 Adding replica 172.25.254.60:6379 to 172.25.254.20:6379 Adding replica 172.25.254.40:6379 to 172.25.254.30:6379 Can I set the above configuration? (type yes to accept): yes Nodes configuration updated [OK] All nodes agree about slots configuration.5.5 驗證集群狀態# 集群信息總覽[rootredis-node1 ~]# redis-cli --cluster info 172.25.254.10:6379172.25.254.10:6379 -0keys|5461slots|1slaves.172.25.254.30:6379 -0keys|5461slots|1slaves.172.25.254.20:6379 -0keys|5462slots|1slaves.[OK]0keysin3masters.# 集群自身狀態[rootredis-node1 ~]# redis-cli cluster infocluster_state:ok cluster_slots_assigned:16384 cluster_slots_ok:16384 cluster_known_nodes:6 cluster_size:3# 健康檢查[rootredis-node1 ~]# redis-cli --cluster check 172.25.254.10:6379[OK]All16384slots covered.cluster_state:ok且All 16384 slots covered說明集群健康。拓撲如下5.6集群擴容加一主一從業務增長要加機器集群支持在線擴容。① 加入新主節點 .70[rootredis-node1 ~]# redis-cli --cluster add-node 172.25.254.70:6379 172.25.254.10:6379[rootredis-node1 ~]# redis-cli --cluster check 172.25.254.10:6379172.25.254.70:6379 -0keys|0slots|0slaves.# 新主還沒槽② 遷移槽給新主reshard 4096 個[rootredis-node1 ~]# redis-cli --cluster reshard 172.25.254.10:6379How many slotsdoyou want to move(from1to16384)?4096What is the receivingnodeID? dfabfe07170ac9b5d20a5a7a70c836877bd64504# .70 的 IDPlease enter all thesourcenodeIDs. Sourcenode#1: all # 從所有現有 master 取槽Sourcenode#2: doneReady to move4096slots.遷移后.70分到 4096 個槽從三個老 master 各取一部分M: dfabfe07170ac9b5d20a5a7a70c836877bd64504 172.25.254.70:6379 slots:[0-1364],[5461-6826],[10923-12287] (4096 slots) master③ 給新主掛從節點 .80[rootredis-node1 ~]# redis-cli --cluster add-node 172.25.254.80:6379 172.25.254.10:6379 \--cluster-slave --cluster-master-id dfabfe07170ac9b5d20a5a7a70c836877bd64504擴容后變成4 主 4 從槽自動均攤到每主 4096 個。5.7集群縮容刪一主一從① 把 .70 的槽遷回 .10[rootredis-node1 ~]# redis-cli --cluster reshard 172.25.254.10:6379How many slotsdoyou want to move(from1to16384)?4096What is the receivingnodeID? 8db833f3c3bc6b8f93e87111f13f56d366f833a0# .10 的 IDSourcenode#1: dfabfe07170ac9b5d20a5a7a70c836877bd64504 # .70 的 IDSourcenode#2: done② 刪除節點先刪從 .80再刪主 .70[rootredis-node1 ~]# redis-cli --cluster del-node 172.25.254.10:6379 1176ee294e6b5071ca57e93374d04ac22028daedSending CLUSTER FORGET messages to the cluster...[rootredis-node1 ~]# redis-cli --cluster del-node 172.25.254.10:6379 dfabfe07170ac9b5d20a5a7a70c836877bd64504[rootredis-node1 ~]# redis-cli --cluster check 172.25.254.10:6379[OK]All16384slots covered.縮容完成恢復為 3 主 3 從。?? 刪除主節點前必須先把它的槽全部遷走否則會丟數據。六、三種高可用方案對比小結方案寫能力存儲上限自動故障轉移是否需要哨兵適用場景主從復制單 Master單節點? 手動否讀多寫少、要備份哨兵 Sentinel單 Master單節點? 自動是高可用、寫量不大Cluster 集群多 Master橫向擴展? 自動否內置大數據量、高并發寫七、總結Redis 是什么基于內存的 KV 數據庫快、支持持久化、數據類型豐富主從復制一主多從做讀寫分離和數據備份但 Master 掛了要人手動頂哨兵模式哨兵自動監控 故障轉移解決主從的單點問題但仍只有一個 Master 寫Cluster 集群數據分 16384 槽、多 Master 分片既能橫向擴容又能自動故障轉移是大規模場景的終極方案持久化RDB AOF 都開重啟優先 AOFRDB 做備份。