作者:Grey
原文地址:Redis學習筆記七:主從復制和哨兵
單機,單節點,單實例的Redis會有什么問題呢?
容易導致單點故障,那么如何解決呢?
可以通過主備方式
同時可以實現讀寫分離
這里的每個節點是全量的,鏡像的。
單節點的容量有限而且單點的壓力比較大,如何解決呢?
可以分不同的實例來存不同的業務數據
每種業務數據也可以根據不同的規則放到同一組的Redis庫中
引入多個Redis實例后,會出現數據一致性的問題,如何解決呢?
如果要達到強一致性(同步方式),就容易導致不可用性,比如一個節點寫成功后,同步到其他節點,假設其他節點有一個網絡延遲或者故障,就會導致整個服務不可用,所以,如果要保證可用 ,需要容忍丟失一些數據(主節點寫成功立即給客戶端返回成功,異步把數據同步到其他備用節點)。如果要保證數據不丟失(保證最終一致性),可以考慮使用消息隊列。
這里就要求消息隊列本身是可靠的,這種方式保證了最終一致性,也會有問題,比如多個客戶端訪問的時候,有可能會取到不一致的數據。
主從方式
客戶端可以訪問主,也可以訪問從
主備方式
客戶端只訪問主,不訪問備,只有當主掛了才訪問備
無論主從和主備,主都成了單點故障,如何解決這個問題呢?
所以必須要對主做HA(比如主掛了,從機頂上去做主機)
要對主進行HA,必須要選擇一個高可用的監控程序,
監控程序的設計要考慮,是多個監控程序報告Redis掛了才算Redis真的掛了(如果不這樣,容易產生腦裂問題,即:出現數據分區)
如果有N個節點,需要N/2+1個節點報告異常(過半),才算真的異常。
腦裂是否要處理,要看你的分區容忍性。
機器的台數是奇數比較好。
主從復制實驗
通過install_server.sh腳本在一台機器安裝三個redis實例
-
6379
-
6380
-
6381
首先停掉這三個實例,然后把這三個實例的配置文件統一放到一個地方,我放在/data目錄下
cp /etc/redic/*.conf /data/
修改三個實例的如下配置
# 關閉aof
appendonly no
# 設置前台運行
daemonize no
# 注釋掉logfile
# logfile /var/log/redis_6379.log
然后啟動三個實例
redis-server /data/6379.conf
redis-server /data/6380.conf
redis-server /data/6381.conf
啟動客戶端
redis-cli -p 6379
redis-cli -p 6380
redis-cli -p 6381
把6380 和 6381 設置為6379的從機,在6380和6381兩個客戶端均執行
replicaof 127.0.0.1 6379
我們在6379客戶端執行一條語句
set k1 from6379
然后在6380和6381都執行
127.0.0.1:6381> get k1
"from6379"
127.0.0.1:6380> get k1
"from6379"
可以看到從機同步到了主機的數據
在6380或者6381中任意一台的客戶端執行
127.0.0.1:6381> set k2 asdfasd
(error) READONLY You can't write against a read only replica.
會提示如下信息:
(error) READONLY You can't write against a read only replica.
即在從機無法做寫操作。
假設兩台從機掛了一台,掛完以后,主機還做了若干次的操作,此時如果掛了的從機繼續啟動(以--appendonly no模式),只會增量同步數據。
如果是以appendonly yes方式啟動掛了的從機,則會觸發全量同步
rdb方式可以記錄當初追隨者的信息,所以可以做到增量,而aof不會記錄,所以只能全量。
假如主機掛了,由於從只能讀不能寫,我們可以人為把其中的一台從機變成主(先在這個從機上執行:replicaof no one),然后讓另外一個從機追隨這個主即可,追隨過程中,如果從機開啟了replica-serve-stale-data=yes, 則從機在同步主機數據的時候,還可以查詢自身的舊數據,
replica-diskless-sync yes 表示直接用網絡來同步主機和從機的數據(不落磁盤),這種情況一般適用於磁盤性能低於網絡性能的情況。
repl—backlog-size 1mb
主機維護的隊列大小,防止從機重啟后又掛掉,這個維護的是一個偏移量,如果寫的頻率不高,則可以設置為1mb,如果寫的頻率非常高,這個值要適當調大。
# 規定最少寫成功的數值
min-replicas-to-write 3
min-replicas-max-lag 10
主從復制的問題:
所以需要人工維護主的故障問題!
所以需要HA, HA如何做呢?
引入:sentinel機制
sentinel實驗
保持前面配置的三個主機(一主兩從)為啟動狀態
其中6379為主,6380和6381為從。
准備三個sentinel的配置文件(配置成監控主機)
在/data/redis/sentinel目錄下准備:26380.conf,26381.conf,26379.conf三個配置文件,配置文件中配置如下內容,以26379.conf為例(其他兩個同理)
port 26379
sentinel monitor mymaster 127.0.0.1 6379 2
配置說明見:http://www.redis.cn/topics/sentinel.html
准備好三個配置后,我們以sentinel模式啟動三個實例,啟動命令如下:以26379為例,其他兩個同理。
redis-server /data/redis/sentinel/26381.conf --sentinel
啟動好以后,我們模擬主機掛掉,停掉6379這個實例,
service redis_6379 stop
查看任何一個sentinel實例的日志,發現開啟新的epoch,並選出了新的主為6380
4594:X 29 May 2021 16:32:19.997 # +new-epoch 1
4594:X 29 May 2021 16:32:19.999 # +vote-for-leader 27e706bf27e99c10310c6c9595fcffef63d67e60 1
4594:X 29 May 2021 16:32:20.762 # +config-update-from sentinel 27e706bf27e99c10310c6c9595fcffef63d67e60 127.0.0.1 26380 @ mymaster 127.0.0.1 6379
4594:X 29 May 2021 16:32:20.762 # +switch-master mymaster 127.0.0.1 6379 127.0.0.1 6380
4594:X 29 May 2021 16:32:20.762 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6380
4594:X 29 May 2021 16:32:20.762 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
用一個客戶端連接6380,進行set操作
[root@base ~]# redis-cli -p 6380
127.0.0.1:6380> set k1 ddd
OK
操作成功,然后連接6381,嘗試get k1
[root@base ~]# redis-cli -p 6381
127.0.0.1:6381> get k1
"ddd"
獲取到了最新的數據,此時重新啟動6379這個實例,然后打開任何一個sentinel的運行日志
4594:X 29 May 2021 16:32:50.823 # +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
4594:X 29 May 2021 16:36:16.528 # -sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
發現6379已經作為從機追隨了6380
嘗試在6379中get和set值
[root@base ~]# redis-cli -p 6379
127.0.0.1:6379> get k1
"ddd"
127.0.0.1:6379> set k1 asdf
(error) READONLY You can't write against a read only replica.
可以get,無法set了。
更多
由於主機知道自己有幾個從機,所以sentinel只要監控了主機,就同時也可以知道主機有幾個從機。
那么一個sentinel是如何知道其他的sentinel的呢?用到了redis中的發布訂閱的功能。