部署如下圖

可以分為 Master-Slave Cluster 和 Sentinel HA Solution 兩個(gè)部分
??
通常會(huì)將其中一個(gè) Sentinel 節(jié)點(diǎn)和一個(gè) Redis 節(jié)點(diǎn)部署在一臺(tái)機(jī)上
Master-Slave Cluster
- 配置
?master 不需要特殊配置
?slave 需要在配置文件里添加一項(xiàng)
????slaveof <Master IP> <Port>
?所有節(jié)點(diǎn)添加以下配置
????min-slaves-to-write 1??# 至少要有 1 個(gè)健康的 slave 才允許寫(xiě)數(shù)據(jù),默認(rèn)是 0
?讀寫(xiě)分離,默認(rèn) slave 為只讀,寫(xiě)操作要通過(guò) master - 數(shù)據(jù)同步
?(1). 配置文件有 slaveof 命令的節(jié)點(diǎn)啟動(dòng)為 slave
?(2). Slave 檢查是否存有 master id
?(3). 沒(méi)有則向 master 發(fā)送 PSYNC ? -1 做全量復(fù)制,有則發(fā)送 PSYNC id offset 做增量復(fù)制
?(4). Master 收到 PSYNC 后,將全量或增量寫(xiě)命令傳給 slave
?(5). Slave 更新數(shù)據(jù)
?(6). 此后 master 每次執(zhí)行寫(xiě)命令,都會(huì)將命令發(fā)給 slave,slave 收到后更新數(shù)據(jù) - 由于數(shù)據(jù)復(fù)制是異步的,只保證最終一致性,不保證強(qiáng)一致性,強(qiáng)一致性需讀寫(xiě)都在 master
Sentinel HA
- Master 不會(huì)自動(dòng)切換,Sentinel 監(jiān)控 Redis 集群,master 故障后從 slave 中選舉新 master
- Sentinel 同樣會(huì)有單點(diǎn)故障,所以需要 Sentinel 集群
- 配置 sentinel.conf
daemonize yes
# master-name 自定義,2 個(gè) sentinel 認(rèn)為 master 死了才認(rèn)為該 master 不可用
sentinel monitor master-name <Master IP> <Master Port> 2
# 30 秒內(nèi)沒(méi)返回心跳就被認(rèn)為 master 死了
sentinel down-after-milliseconds master-name 30000
# 切換的 timeout 時(shí)間
sentinel failover-timeout master-name 180000
# 切換時(shí),可以有多少個(gè) slave 同時(shí)對(duì)新的 master 進(jìn)行同步
sentinel parallel-syncs master-name 1
監(jiān)控
?(1). Sentinel 通過(guò)配置文件發(fā)現(xiàn) master,向 master 發(fā)送 info 獲取 master 下的所有 slave
?(2). Sentinel 向 redis 發(fā)送 hello 信息(每秒一次),告知自己的 IP,端口,id 等信息
?(3). Sentinel 通過(guò) redis 訂閱功能發(fā)現(xiàn)其他 sentinel 的 hello 信息,并建立連接
?(4). Sentinel 通過(guò) ping 檢查 redis 狀態(tài),一定時(shí)間內(nèi)沒(méi)回復(fù)就被判為下線(xiàn)
?(5). 當(dāng)多數(shù) sentinel 都認(rèn)為 master 下線(xiàn)后開(kāi)始主從切換,選舉新的 master
?(6). 向當(dāng)選的 slave 發(fā)送 slaveof no one 命令使其成為新的 master
?(7). 向其他 redis 發(fā)送 slaveof new-master-IP 命令,與新的 master 同步客戶(hù)端通過(guò) Sentinel 獲取 redis 集群的信息
from redis.sentinel import Sentinel
sentinel = Sentinel([('sentinel ip 1', 26379), ('sentinel ip 2', 26379), ('sentinel ip 3', 26379)], socket_timeout=0.5)
master = sentinel.master_for('master-name', socket_timeout=0.5, db=15)
master.set(key, value)
slave = sentinel.slave_for('master-name', socket_timeout=0.5, db=15)
value = slave.get(key)
masterIP, masterPort = sentinel.discover_master('master-name')
slaveList = sentinel.discover_slaves('master-name') # e.g. [(slave-1 IP, slave-1 Port), (slave-2 IP, slave-2 Port)]