緣由
鑒于之前面試某大廠掛掉了,被面試官問了一些 Redis 和 MySQL 的高可用相關(guān)的東西,之前自己接觸的項目沒有用到過,也沒有去深入研究,今日便來實(shí)踐一番。
Redis 集群目前主要有3種方案,分別是:主從復(fù)制方案,sentinel哨兵模式,redis-cluster模式。
主從復(fù)制方案
理論基礎(chǔ)
Redis 的主從復(fù)制與 MySQL 的 binlog 復(fù)制有些類似。Redis 本身有 rdb 和 aof 兩種持久化方案,這是其能實(shí)現(xiàn)復(fù)制功能的基礎(chǔ)。
我們可以通過slaveof <host> <port>命令,或者通過配置slaveof選項,來使當(dāng)前的服務(wù)器(slave)復(fù)制指定服務(wù)器(master)的內(nèi)容,被復(fù)制的服務(wù)器稱為主服務(wù)器(master),對主服務(wù)器進(jìn)行復(fù)制操作的為從服務(wù)器(slave)。
主服務(wù)器master可以進(jìn)行讀寫操作,當(dāng)主服務(wù)器的數(shù)據(jù)發(fā)生變化,master會發(fā)出命令流來保持對salve的更新,而從服務(wù)器slave通常是只讀的(可以通過slave-read-only指定),在主從復(fù)制模式下,即便master宕機(jī)了,slave是不能變?yōu)橹鞣?wù)器進(jìn)行寫操作的。
主從復(fù)制的過程大概是:
- 當(dāng)slave啟動后會向master發(fā)送
SYNC命令,master節(jié)點(diǎn)收到從數(shù)據(jù)庫的命令后通過bgsave保存快照(「RDB持久化」),并且期間的執(zhí)行的些命令會被緩存起來。 - 然后master會將保存的快照發(fā)送給slave,并且繼續(xù)緩存期間的寫命令。
- slave收到主數(shù)據(jù)庫發(fā)送過來的快照就會加載到自己的數(shù)據(jù)庫中。
- 最后master將緩存的命令同步給slave,slave收到命令后執(zhí)行一遍,這樣master與slave數(shù)據(jù)就保持一致了。
實(shí)踐
環(huán)境:Mac,homebrew,redis-5.0.5
先在
/usr/local/Cellar/redis/5.0.5/conf目錄下建3個文件夾,分別放置不同實(shí)例的配置和數(shù)據(jù),日志等文件。-
先創(chuàng)建master的配置文件:
8000/redis.conf:(redis配置文件詳解)
bind 0.0.0.0 protected-mode no port 8000 timeout 30 daemonize yes pidfile /usr/local/Cellar/redis/5.0.5/conf/8000/redis.pid logfile /usr/local/Cellar/redis/5.0.5/conf/8000/redis.log save 900 1 save 300 10 save 60 10000 rdbcompression yes dbfilename dump.rdb dir /usr/local/Cellar/redis/5.0.5/conf/8000 appendonly yes appendfsync everysec requirepass 123456 -
再復(fù)制一份到slave
cp 8000/redis.conf 8001/修改端口號和相關(guān)路徑,然后在末尾加上salve的配置:
slaveof 127.0.0.1 8000 masterauth 123456 slave-serve-stale-data no -
依次啟動master和slave
redis-server 8000/redis.conf redis-server 8001/redis.conf 使用客戶端測試一下:
master:

slave:

可以看到,數(shù)據(jù)同步過去了,我們試著將master進(jìn)程kill掉,再看看slave能否繼續(xù)提供服務(wù):

不能繼續(xù)提供服務(wù),這個是通過配置參數(shù):slave-serve-stale-data控制的,默認(rèn)是yes,具體設(shè)置還得看實(shí)際業(yè)務(wù)需求。
另外,可以看到每個配置文件夾下有 appendonly.aof 文件,我們看看該文件的內(nèi)容:

內(nèi)容就是設(shè)計數(shù)據(jù)更新的語句的redis協(xié)議格式的內(nèi)容,redis協(xié)議在之前的文章說過了~
優(yōu)缺點(diǎn)
可見,主從復(fù)制方案支持讀寫分離,支持讀擴(kuò)展。但只有一個master,存在寫的單點(diǎn)問題,而且不支持故障自動恢復(fù),每個節(jié)點(diǎn)都是全部數(shù)據(jù),不可擴(kuò)容。
Sentinel 哨兵模式
理論基礎(chǔ)
哨兵模式是主從的升級版,因為主從的出現(xiàn)故障后,不會自動恢復(fù),需要人為干預(yù),這就很蛋疼啊。
在主從的基礎(chǔ)上,實(shí)現(xiàn)哨兵模式就是為了監(jiān)控主從的運(yùn)行狀況,對主從的健壯進(jìn)行監(jiān)控,就好像哨兵一樣,只要有異常就發(fā)出警告,對異常狀況進(jìn)行處理。
哨兵模式的原理細(xì)節(jié)可以講很久,所以暫不列出,可以查閱其他文檔~
實(shí)踐
因為主從復(fù)制是 Sentinel 哨兵模式的基礎(chǔ),所以我們需要在上面的實(shí)踐的基礎(chǔ)上進(jìn)行,現(xiàn)在再加一個salve,8001。然后開始
-
新建三個文件夾,9000,9001,9002,里面放sentinel.conf文件,模板:
daemonize yes sentinel monitor mymaster 127.0.0.1 6379 1 sentinel auth-pass mymaster 123456 port 9000 sentinel down-after-milliseconds mymaster 3000 sentinel parallel-syncs mymaster 2 sentinel failover-timeout mymaster 100000 -
依次啟動3個sentinel:
../bin/redis-server 9000/sentinel.conf --sentinel ../bin/redis-server 9001/sentinel.conf --sentinel ../bin/redis-server 9002/sentinel.conf --sentinel

- 使用客戶端測試一下:


在master寫入,成功同步到了slave;slave不能寫,只能讀。期間我有試過kill掉master的進(jìn)程,sentinel成功切換了master。
期間遇到一個坑,8000作為第一個master,之前是沒有slave相關(guān)配置信息的,后面kill掉8000,又重啟,發(fā)現(xiàn)其變成了slave,但是一直連接不上slave,查看日志之后發(fā)現(xiàn)是因為缺少 masterauth 配置。
另外觀察到sentinel會實(shí)時更新我們的配置文件:


優(yōu)缺點(diǎn)
可以看到,sentinel 明顯的優(yōu)勢是可以自動進(jìn)行故障切換。但是切換master后,我們無法得知新的master的地址,除非登錄一臺,執(zhí)行info replication這樣顯得有點(diǎn)麻煩。
缺點(diǎn)也跟主從復(fù)制方案差不多,單臺實(shí)例擁有全部數(shù)據(jù),無法從存儲層面擴(kuò)容。
Redis-Cluster 模式
理論基礎(chǔ)
實(shí)踐
-
新建7001-7007共7個文件夾,每個文件夾下一個redis.conf文件:
port 7000(其他文件相應(yīng)更改) cluster-enabled yes cluster-config-file /usr/local/Cellar/redis/5.0.5/conf/7000/nodes.conf cluster-node-timeout 5000 appendonly yes daemonize yes masterauth 123456 requirepass 123456 -
依次啟動server
../bin/redis-server 7000/redis.conf ... ../bin/redis-server 7006/redis.conf 暫時先留一個待集群建立起來之后加入 -
創(chuàng)建集群
redis-cli --cluster create --cluster-replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006 -a 123456輸入yes確認(rèn)之后,集群就建立成功了:

- 使用客戶端測試一下:

redis-cli 需要使用 -c 進(jìn)入 redis-cluster 模式,可以看到,有一個 Redirect 的過程,key 最后hash到哪個實(shí)例,就 Redirect 到那個實(shí)例去了,而且 keys * 的結(jié)果是不準(zhǔn)確的,只是單個實(shí)例的結(jié)果,并不是整個集群的。
- 加入新節(jié)點(diǎn):


優(yōu)缺點(diǎn)
Redis-cluster 是真正意義上的集群,數(shù)據(jù)分散在多個實(shí)例,不存在容量的問題。而且每個節(jié)點(diǎn)都可以讀寫,不存在寫的壓力。
PHP使用
predis 完美支持以上3種模式。簡單測試一下:
- 主從:


- sentinel :(predis sentinel 老是報錯,所以換了python來測試~)


- redis-cluster:


總結(jié)
有些東西雖然沒有用到,但是不能不知道!
2020-09-26