在開發測試環境中,咱們通常搭建Redis的單實例來應對開發測試需求,可是在生產環境,若是對可用性、可靠性要求較高,則須要引入Redis的集羣方案。雖然如今各大雲平臺有提供緩存服務能夠直接使用,但瞭解一下其背後的實現與原理總仍是有些必要(好比面試), 本文就一塊兒來學習一下Redis的幾種集羣方案。html
Redis支持三種集羣方案node
主從複製模式中包含一個主數據庫實例(master)與一個或多個從數據庫實例(slave),以下圖面試
客戶端可對主數據庫進行讀寫操做,對從數據庫進行讀操做,主數據庫寫入的數據會實時自動同步給從數據庫。redis
具體工做機制爲:算法
本示例基於Redis 5.0.3版。shell
redis.conf的主要配置數據庫
###網絡相關###
# bind 127.0.0.1 # 綁定監聽的網卡IP,註釋掉或配置成0.0.0.0可以使任意IP都可訪問
protected-mode no # 關閉保護模式,使用密碼訪問
port 6379 # 設置監聽端口,建議生產環境均使用自定義端口
timeout 30 # 客戶端鏈接空閒多久後斷開鏈接,單位秒,0表示禁用
###通用配置###
daemonize yes # 在後臺運行
pidfile /var/run/redis_6379.pid # pid進程文件名
logfile /usr/local/redis/logs/redis.log # 日誌文件的位置
###RDB持久化配置###
save 900 1 # 900s內至少一次寫操做則執行bgsave進行RDB持久化
save 300 10
save 60 10000
# 若是禁用RDB持久化,可在這裏添加 save ""
rdbcompression yes #是否對RDB文件進行壓縮,建議設置爲no,以(磁盤)空間換(CPU)時間
dbfilename dump.rdb # RDB文件名稱
dir /usr/local/redis/datas # RDB文件保存路徑,AOF文件也保存在這裏
###AOF配置###
appendonly yes # 默認值是no,表示不使用AOF增量持久化的方式,使用RDB全量持久化的方式
appendfsync everysec # 可選值 always, everysec,no,建議設置爲everysec
###設置密碼###
requirepass 123456 # 設置複雜一點的密碼
複製代碼
部署主從複製模式只需稍微調整slave的配置,在redis.conf中添加緩存
replicaof 127.0.0.1 6379 # master的ip,port
masterauth 123456 # master的密碼
replica-serve-stale-data no # 若是slave沒法與master同步,設置成slave不可讀,方便監控腳本發現問題
複製代碼
本示例在單臺服務器上配置master端口6379,兩個slave端口分別爲7001,7002,啓動master,再啓動兩個slavebash
[root@dev-server-1 master-slave]# redis-server master.conf
[root@dev-server-1 master-slave]# redis-server slave1.conf
[root@dev-server-1 master-slave]# redis-server slave2.conf
複製代碼
進入master數據庫,寫入一個數據,再進入一個slave數據庫,當即即可訪問剛纔寫入master數據庫的數據。以下所示服務器
[root@dev-server-1 master-slave]# redis-cli
127.0.0.1:6379> auth 123456
OK
127.0.0.1:6379> set site blog.jboost
OK
127.0.0.1:6379> get site
"blog.jboost"
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=7001,state=online,offset=13364738,lag=1
slave1:ip=127.0.0.1,port=7002,state=online,offset=13364738,lag=0
...
127.0.0.1:6379> exit
[root@dev-server-1 master-slave]# redis-cli -p 7001
127.0.0.1:7001> auth 123456
OK
127.0.0.1:7001> get site
"blog.jboost"
複製代碼
執行info replication
命令能夠查看鏈接該數據庫的其它庫的信息,如上可看到有兩個slave鏈接到master
優勢:
缺點:
哨兵模式基於主從複製模式,只是引入了哨兵來監控與自動處理故障。如圖
哨兵顧名思義,就是來爲Redis集羣站哨的,一旦發現問題能作出相應的應對處理。其功能包括
哨兵模式的具體工做機制:
在配置文件中經過 sentinel monitor <master-name> <ip> <redis-port> <quorum>
來定位master的IP、端口,一個哨兵能夠監控多個master數據庫,只須要提供多個該配置項便可。哨兵啓動後,會與要監控的master創建兩條鏈接:
_sentinel_:hello
頻道與獲取其餘監控該master的哨兵節點信息與master創建鏈接後,哨兵會執行三個操做:
_sentinel_:hello
頻道發送本身的信息發送INFO命令能夠獲取當前數據庫的相關信息從而實現新節點的自動發現。因此說哨兵只須要配置master數據庫信息就能夠自動發現其slave信息。獲取到slave信息後,哨兵也會與slave創建兩條鏈接執行監控。經過INFO命令,哨兵能夠獲取主從數據庫的最新信息,並進行相應的操做,好比角色變動等。
接下來哨兵向主從數據庫的_sentinel_:hello頻道發送信息與一樣監控這些數據庫的哨兵共享本身的信息,發送內容爲哨兵的ip端口、運行id、配置版本、master名字、master的ip端口還有master的配置版本。這些信息有如下用處:
若是被PING的數據庫或者節點超時(經過 sentinel down-after-milliseconds master-name milliseconds
配置)未回覆,哨兵認爲其主觀下線(sdown,s就是Subjectively —— 主觀地)。若是下線的是master,哨兵會向其它哨兵發送命令詢問它們是否也認爲該master主觀下線,若是達到必定數目(即配置文件中的quorum)投票,哨兵會認爲該master已經客觀下線(odown,o就是Objectively —— 客觀地),並選舉領頭的哨兵節點對主從系統發起故障恢復。若沒有足夠的sentinel進程贊成master下線,master的客觀下線狀態會被移除,若master從新向sentinel進程發送的PING命令返回有效回覆,master的主觀下線狀態就會被移除
哨兵認爲master客觀下線後,故障恢復的操做須要由選舉的領頭哨兵來執行,選舉採用Raft算法:
選出領頭哨兵後,領頭者開始對系統進行故障恢復,從出現故障的master的從數據庫中挑選一個來當選新的master,選擇規則以下:
挑選出須要繼任的slave後,領頭哨兵向該數據庫發送命令使其升格爲master,而後再向其餘slave發送命令接受新的master,最後更新數據。將已經中止的舊的master更新爲新的master的從數據庫,使其恢復服務後以slave的身份繼續運行。
本示例基於Redis 5.0.3版。
哨兵模式基於前文的主從複製模式。哨兵的配置文件爲sentinel.conf,在文件中添加
sentinel monitor mymaster 127.0.0.1 6379 1 # mymaster定義一個master數據庫的名稱,後面是master的ip, port,1表示至少須要一個Sentinel進程贊成才能將master判斷爲失效,若是不知足這個條件,則自動故障轉移(failover)不會執行
sentinel auth-pass mymaster 123456 # master的密碼
sentinel down-after-milliseconds mymaster 5000 # 5s未回覆PING,則認爲master主觀下線,默認爲30s
sentinel parallel-syncs mymaster 2 # 指定在執行故障轉移時,最多能夠有多少個slave實例在同步新的master實例,在slave實例較多的狀況下這個數字越小,同步的時間越長,完成故障轉移所需的時間就越長
sentinel failover-timeout mymaster 300000 # 若是在該時間(ms)內未能完成故障轉移操做,則認爲故障轉移失敗,生產環境須要根據數據量設置該值
複製代碼
一個哨兵能夠監控多個master數據庫,只需按上述配置添加多套
分別以26379,36379,46379端口啓動三個sentinel
[root@dev-server-1 sentinel]# redis-server sentinel1.conf --sentinel
[root@dev-server-1 sentinel]# redis-server sentinel2.conf --sentinel
[root@dev-server-1 sentinel]# redis-server sentinel3.conf --sentinel
複製代碼
也可使用redis-sentinel sentinel1.conf
命令啓動。此時集羣包含一個master、兩個slave、三個sentinel,如圖,
咱們來模擬master掛掉的場景,執行 kill -9 3017
將master進程幹掉,進入slave中執行 info replication
查看,
[root@dev-server-1 sentinel]# redis-cli -p 7001
127.0.0.1:7001> auth 123456
OK
127.0.0.1:7001> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:7002
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
# 省略
127.0.0.1:7001> exit
[root@dev-server-1 sentinel]# redis-cli -p 7002
127.0.0.1:7002> auth 123456
OK
127.0.0.1:7002> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=7001,state=online,offset=13642721,lag=1
# 省略
複製代碼
能夠看到slave 7002已經成功上位晉升爲master(role:master),接收一個slave 7001的鏈接。此時查看slave2.conf配置文件,發現replicaof
的配置已經被移除了,slave1.conf的配置文件裏replicaof 127.0.0.1 6379
被改成 replicaof 127.0.0.1 7002
。從新啓動master,也能夠看到master.conf配置文件中添加了replicaof 127.0.0.1 7002
的配置項,可見大哥(master)下位後,再出來混就只能噹噹小弟(slave)了,三十年河東三十年河西。
優勢:
缺點:
哨兵模式解決了主從複製不能自動故障轉移,達不到高可用的問題,但仍是存在難以在線擴容,Redis容量受限於單機配置的問題。Cluster模式實現了Redis的分佈式存儲,即每臺節點存儲不一樣的內容,來解決在線擴容的問題。如圖
Cluster採用無中心結構,它的特色以下:
Cluster模式的具體工做機制:
Cluster模式集羣節點最小配置6個節點(3主3從,由於須要半數以上),其中主節點提供讀寫操做,從節點做爲備用節點,不提供請求,只做爲故障轉移使用。
本示例基於Redis 5.0.3版。
Cluster模式的部署比較簡單,首先在redis.conf中
port 7100 # 本示例6個節點端口分別爲7100,7200,7300,7400,7500,7600
daemonize yes # r後臺運行
pidfile /var/run/redis_7100.pid # pidfile文件對應7100,7200,7300,7400,7500,7600
cluster-enabled yes # 開啓集羣模式
masterauth passw0rd # 若是設置了密碼,須要指定master密碼
cluster-config-file nodes_7100.conf # 集羣的配置文件,一樣對應7100,7200等六個節點
cluster-node-timeout 15000 # 請求超時 默認15秒,可自行設置
複製代碼
分別以端口7100,7200,7300,7400,7500,7600 啓動六個實例(若是是每一個服務器一個實例則配置可同樣)
[root@dev-server-1 cluster]# redis-server redis_7100.conf
[root@dev-server-1 cluster]# redis-server redis_7200.conf
...
複製代碼
而後經過命令將這個6個實例組成一個3主節點3從節點的集羣,
redis-cli --cluster create --cluster-replicas 1 127.0.0.1:7100 127.0.0.1:7200 127.0.0.1:7300 127.0.0.1:7400 127.0.0.1:7500 127.0.0.1:7600 -a passw0rd
複製代碼
執行結果如圖
能夠看到 7100, 7200, 7300 做爲3個主節點,分配的slot分別爲 0-5460, 5461-10922, 10923-16383, 7600做爲7100的slave, 7500做爲7300的slave,7400做爲7200的slave。
咱們鏈接7100設置一個值
[root@dev-server-1 cluster]# redis-cli -p 7100 -c -a passw0rd
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:7100> set site blog.jboost
-> Redirected to slot [9421] located at 127.0.0.1:7200
OK
127.0.0.1:7200> get site
"blog.jboost"
127.0.0.1:7200>
複製代碼
注意添加 -c 參數表示以集羣模式,不然報 (error) MOVED 9421 127.0.0.1:7200
錯誤, 以 -a 參數指定密碼,不然報(error) NOAUTH Authentication required
錯誤。
從上面命令看到key爲site算出的slot爲9421,落在7200節點上,因此有Redirected to slot [9421] located at 127.0.0.1:7200
,集羣會自動進行跳轉。所以客戶端能夠鏈接任何一個節點來進行數據的存取。
經過cluster nodes
可查看集羣的節點信息
127.0.0.1:7200> cluster nodes
eb28aaf090ed1b6b05033335e3d90a202b422d6c 127.0.0.1:7500@17500 slave c1047de2a1b5d5fa4666d554376ca8960895a955 0 1584165266071 5 connected
4cc0463878ae00e5dcf0b36c4345182e021932bc 127.0.0.1:7400@17400 slave 5544aa5ff20f14c4c3665476de6e537d76316b4a 0 1584165267074 4 connected
dbbb6420d64db22f35a9b6fa460b0878c172a2fb 127.0.0.1:7100@17100 master - 0 1584165266000 1 connected 0-5460
d4b434f5829e73e7e779147e905eea6247ffa5a2 127.0.0.1:7600@17600 slave dbbb6420d64db22f35a9b6fa460b0878c172a2fb 0 1584165265000 6 connected
5544aa5ff20f14c4c3665476de6e537d76316b4a 127.0.0.1:7200@17200 myself,master - 0 1584165267000 2 connected 5461-10922
c1047de2a1b5d5fa4666d554376ca8960895a955 127.0.0.1:7300@17300 master - 0 1584165268076 3 connected 10923-16383
複製代碼
咱們將7200經過 kill -9 pid
殺死進程來驗證集羣的高可用,從新進入集羣執行cluster nodes
能夠看到7200 fail了,可是7400成了master,從新啓動7200,能夠看到此時7200已經變成了slave。
優勢:
缺點:
Redis Cluster模式不建議使用pipeline和multi-keys操做,減小max redirect產生的場景。
本文介紹了Redis集羣方案的三種模式,其中主從複製模式能實現讀寫分離,可是不能自動故障轉移;哨兵模式基於主從複製模式,能實現自動故障轉移,達到高可用,但與主從複製模式同樣,不能在線擴容,容量受限於單機的配置;Cluster模式經過無中心化架構,實現分佈式存儲,可進行線性擴展,也能高可用,但對於像批量操做、事務操做等的支持性不夠好。三種模式各有優缺點,可根據實際場景進行選擇。
參考:
做者:空山新雨,一枚仍在學習路上的大齡碼農
近期做者寫了幾十篇技術博客,內容包括Java、Spring Boot、Spring Cloud、Docker,技術管理心得等
歡迎關注做者微信公衆號:空山新雨的技術空間,一塊兒學習成長