Redis學習(八)————深入瞭解Redis主從複製,Redis哨兵機制

一、什麼是Redis主從複製?

在這裏插入圖片描述
將一臺服務器作爲Redis的主庫(Master),另外服務器作爲從庫(Slave)(一臺或多臺)。主庫(Master)只負責寫數據,每次有數據更新的時候,Redis服務器會將數據從主庫同步到其他從庫中,從庫只負責讀取數據。
一個主庫可以擁有多個從庫,一個從庫只能擁有一個主庫,一個從庫也可以擁有從庫,但從庫依然還是從庫,不會擁有寫的功能。

二、爲什麼要Redis複製?

1、儘管Redis的性能很優秀,但它也會遇到沒辦法快速處理請求的情況,特別是在對集合和有序集合進行操作的時候,涉及到的元素可能會有上萬個甚至上百萬,在這種情況下執行所花費的時間可能以秒來計算,而不是毫秒或者微秒。但即使一個命令只需要花費10毫秒就能完成,單個redis實例1s也只能處理100命令。
2、要實現分佈式數據庫的更大存儲量和高併發訪問量,我們會將原來集中式數據庫的數據分別存儲到其他多個網絡節點。Redis爲了解決這個單一節點問題,也會將數據複製多個副本部署到其他節點上進行復制,實現Redis的高可用,實現數據的冗餘備份,從而保證數據和服務的高可用。
Redis複製是高可用的基石。如果沒有redis複製也就不可能實現高可用。

爲什麼不只使用一臺redis?

第一,機器故障。我們部署到一臺 Redis
服務器,當發生機器故障時,需要遷移到另外一臺服務器並且要保證數據是同步的。而數據是最重要的,如果你不在乎,基本上也就不會使用 Redis
了。

第二,容量瓶頸。當我們有需求需要擴容 Redis 內存時,從 16G 的內存升到 64G,單機肯定是滿足不了。當然,你可以重新買個 128G
的新機器。

第三,QPS 瓶頸。Redis 號稱支持10 萬 QPS,當業務需要 100 萬 QPS 時,我們該怎麼做呢?這時就用到了 Redis 複製

三、複製原理

Slave 啓動連接成功到Master後 會發送一個sync命令,Master接到命令啓動後臺的存盤進程,同時收集所有接收到的用於修改數據集命令,在後臺進程執行完畢之後,master將傳送整個數據文件到slave,以完成一次完全同步。

步驟:

步驟 主服務器操作 從服務器操作
1 等待命令進入 連接(或者重連)主服務器,發送SYNC命令
2 開始執行BGSAVE,並使用緩衝區記錄BGSAVE之後執行的所有寫命令 根據配置選項來決定是繼續使用現有的數據(如果有的話)來處理客戶端的命令請求,還是向發送請求的客戶端返回錯誤
3 BGSAVE執行完畢,向從服務器發送快照文件,並在發送期間繼續使用緩衝區記錄被執行的寫命令 丟棄所有舊數據(如果有的話),開始載入主服務器發送來的快照文件
4 快照文件發送完畢,開始向從服務器發送存儲在緩衝區裏面的寫命令 完成對快照文件的解釋操作,嚮往常一樣開始接受命令請求
5 緩衝區存儲的寫命令發送完畢,從現在開始,每執行一個寫命令,就像從服務器發送相同的寫命令 執行主服務器發送來的所有存儲在緩衝區裏面的寫命令,並從現在開始,接收並執行主服務器傳來的每個命令
全量複製與部分複製

1、全量複製

在這裏插入圖片描述

第一步,Redis 內部會發出一個同步命令,剛開始是 Psync 命令,Psync ? -1 表示要求 Master 主機同步數據;

第二步,Master 會向從機發送 runid 和 offset,因爲 Slave 並沒有對應的 offset,所以是全量複製;

第三步,通過指令 save masterInfo,從機 Slave 會保存 Master 的基本信息;

第四步,Master 執行 bgsave 命令(持久化命令),對於一個快照來說,怎麼快怎麼來。實際上 Master 主機裏有
repl_back_buffer(複製緩衝區);

第五步,通過指令 send RDB 發送 RDB 文件;

第六步,發送緩衝區數據;

第七步,刷新舊的數據;

第八步,加載 RDB 文件和緩衝區數據的加載。

那麼全量複製需要哪些開銷呢?

  • bgsave 時間;
  • RDB 文件網絡傳輸時間;
  • 從節點清空數據的時間;
  • 從節點加載 RDB 的時間;
  • AOF 重寫的時間(這裏需要說明一下,RDB 全量複製完加載 RDB,如果 AOF 開啓的話,就會出現 AOF 重寫來保證是最新的)。

2、部分複製

部分複製是 Redis 2.8 以後出現的,之所以要加入部分複製,是因爲全量複製會產生很多問題,比如像上面的時間開銷大、無法隔離等問題,
Redis 希望能夠在 Master 出現抖動(相當於斷開連接)的時候,可以有一些機制將複製的損失降低到最低。

第一步,如果打算抖動(連接斷開 connection lost);

第二步,Master 還是會寫 repl_back_buffer(複製緩衝區);

第三步,Slave 會繼續嘗試連接主機;

第四步,Slave 會把自己當前 runid 和偏移量傳輸給主機 Master,並且執行 pysnc 命令同步;

第五步,如果 Master 發現你的偏移量在緩衝區的範圍內,就會返回 continue 命令;

第六步,同步了 offset 的部分數據,所以部分複製的基礎就是偏移量 offset。

通過部分複製,可以有效的減少全量複製的開銷。

四、實踐操作

爲了方便 這裏使用一臺服務器進行操作,拷貝了3個配置文件,分別是redis6379.conf;redis6380.conf;redis6381.conf.

配從(庫)不配主(庫)

模擬環境

1、修改配置文件:

1、修改配置文件端口號(6379,6380,6381);port:***

2、開啓守護進程 daemonize yes

3、指定不同的pid名稱如:pidfile /var/run/redis_6380.pid

4、指定不同的log名如:logfile “redis6380.log”

5、指定不同的dump.rdb如:dbfilename dump6380.rdb

6、指定不同的aof(如果開啓的話),如:appendfilename “appendonly6381.aof”

2、啓動

以配置文件的方式分別啓動三個服務6379,6380,6381

redis-server /usr/local/redis6379.conf
redis-server /usr/local/redis6380.conf
redis-server /usr/local/redis6381.conf

進入redis

redis-cli -p 6379
redis-cli -p 6380
redis-cli -p 6381
常見Redis複製

1、一主二僕

即一個主機兩個從機

在這裏插入圖片描述

這裏6379作爲我們的主機,6381,6380作爲從機。 當Slave與Master斷開後需要重新slave
of連接纔可建立之前的主從關係;Master掛掉後,Master關係依然存在,Master重啓即可恢復。

2、薪火相傳

上一個Slave可以是下一個slave的Master,Slave同樣可以接收其他slaves的連接和同步請求,那麼該slave作爲了鏈條中下一個的master,可以有效減輕master的寫壓力

中途變更轉向:會清除之前的數據,重新建立拷貝最新的

在這裏插入圖片描述
3、反客爲主

當Master掛掉後,Slave可鍵入命令 slaveof no one使當前redis停止與其他Master redis數據同步,轉成Master redis。

五、Redis哨兵機制

反客爲主的自動版,能夠後臺監控主機是否故障,如果故障了根據投票數自動將從庫轉換爲主庫

哨兵(Sentinel)機制的意義:

Redis複製過程中有一個很大的缺點,當我們的主機宕機過後,需要我們人工去解決,Redis哨兵就是爲了解決這個問題。
Redis哨兵是一個分佈式的架構,每一個Sentinel節點會對數據節點和其餘Sentinel節點進行監控,當發現某個節點無法到達的時候,會自動標識該節點。如果這個節點是主節點,那麼他會和其他Sentinel節點‘協商’,大部分節點都認爲主節點無法到達的時候,他們會選舉一個Sentinel節點來完成自動故障轉移,同時告訴Redis應用方。

哨兵(Sentinel)的作用:

監控(Monitoring): 哨兵(sentinel) 會不斷地檢查你的Master和Slave是否運作正常。

提醒(Notification):當被監控的某個 Redis出現問題時, 哨兵(sentinel) 可以通過 API 向管理員或者其他應用程序發送通知。

自動故障遷移(Automatic failover): 當一個Master不能正常工作時,哨兵(sentinel) 會開始一次自動故障遷移操作,它會將失效Master的其中一個Slave升級爲新的Master, 並讓失效Master的其他Slave改爲複製新的Master; 當客戶端試圖連接失效的Master時,集羣也會向客戶端返回新Master的地址,使得集羣可以使用Master代替失效Master。

哨兵(Sentinel)工作方式:

1、每個Sentinel(哨兵)進程以每秒鐘一次的頻率向整個集羣中的Master主服務器,Slave從服務器以及其他Sentinel(哨兵)進程發送一個PING 命令。

2、如果一個實例(instance)距離最後一次有效回覆 PING 命令的時間超過 down-after-milliseconds 選項所指定的值, 則這個實例會被 Sentinel(哨兵)進程標記爲主觀下線(SDOWN)。

3、如果一個Master主服務器被標記爲主觀下線(SDOWN),則正在監視這個Master主服務器的所有 Sentinel(哨兵)進程要以每秒一次的頻率確認Master主服務器的確進入了主觀下線狀態。

4、當有足夠數量的 Sentinel(哨兵)進程(大於等於配置文件指定的值)在指定的時間範圍內確認Master主服務器進入了主觀下線狀態(SDOWN), 則Master主服務器會被標記爲客觀下線(ODOWN)。

5、在一般情況下, 每個 Sentinel(哨兵)進程會以每 10 秒一次的頻率向集羣中的所有Master主服務器、Slave從服務器發送 INFO 命令。

6、當Master主服務器被 Sentinel(哨兵)進程標記爲客觀下線(ODOWN)時,Sentinel(哨兵)進程向下線的 Master主服務器的所有 Slave從服務器發送 INFO 命令的頻率會從 10 秒一次改爲每秒一次。

7、若沒有足夠數量的 Sentinel(哨兵)進程同意 Master主服務器下線, Master主服務器的客觀下線狀態就會被移除。若 Master主服務器重新向 Sentinel(哨兵)進程發送 PING 命令返回有效回覆,Master主服務器的主觀下線狀態就會被移除。

哨兵(Sentinel)機制實踐:

這裏我的環境分別爲:

134.98.1.72 6379 Master 作爲主服務器

134.98.1.80 6379 slave 從服務器 slaveof 134.98.1.72 6379

134.98.1.81 6381 slave 從服務器 slaveof 134.98.1.72 6381

分別啓動三臺服務器的Redis。可以通過配置文件或者手動的將80,81配置爲從服務器。

配置文件主要改動

bind 0.0.0.0

protected-mode no

sentinel.conf文件配置

#
bind 0.0.0.0
#
protected-mode no

# port <sentinel-port>
# The port that this sentinel instance will run on
port 26379 端口號

daemonize no  

pidfile "/var/run/redis-sentinel.pid" 

logfile "/usr/local/log/sentinel.log" 日誌地址


sentinel monitor mymaster 134.98.1.72 6379 2 
表示 Sentinel(哨兵)進程去監視一個名爲 mymaster 的主服務器,這個主服務器的 IP 地址爲 134.98.1.72, 端口號爲 6379,而將這個主服務器判斷爲失效至少需要 2 個 Sentinel(哨兵)進程的同意

sentinel down-after-milliseconds mymaster 5000
 Sentinel(哨兵)進程判斷服務器已經掉線所需的毫秒數。


  sentinel parallel-syncs mymaster 1

sentinel failover-timeout mymaster 60000


按照順序 分別啓動Master–>slave–>sentinel

sentinel 啓動:redis-sentinel sentinel.conf

啓動後:

此時的master是我們的72服務器,80,81爲從服務器;

13437:X 23 Apr 2019 16:04:48.053 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
13437:X 23 Apr 2019 16:04:48.053 # Redis version=5.0.4, bits=64, commit=00000000, modified=0, pid=13437, just started
13437:X 23 Apr 2019 16:04:48.053 # Configuration loaded
13437:X 23 Apr 2019 16:04:48.054 * Increased maximum number of open files to 10032 (it was originally set to 1024).
13437:X 23 Apr 2019 16:04:48.055 # Could not create server TCP listening socket 192.168.1.1:26379: bind: Cannot assign requested address
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 5.0.4 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                   
 (    '      ,       .-`  | `,    )     Running in sentinel mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 26379
 |    `-._   `._    /     _.-'    |     PID: 13437
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           http://redis.io        
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               

13437:X 23 Apr 2019 16:04:48.056 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
13437:X 23 Apr 2019 16:04:48.060 # Sentinel ID is 1065cb78d77eabcccbee19b2c2f4585fa08e9390
13437:X 23 Apr 2019 16:04:48.060 # +monitor master mymaster 134.98.1.72 6379 quorum 2
13437:X 23 Apr 2019 16:04:48.061 * +slave slave 134.98.1.81:6379 134.98.1.81 6379 @ mymaster 134.98.1.72 6379
13437:X 23 Apr 2019 16:04:48.063 * +slave slave 134.98.1.80:6380 134.98.1.80 6380 @ mymaster 134.98.1.72 6379
13437:X 23 Apr 2019 16:05:31.929 * +sentinel sentinel 0881a984e2229c92812a37e24dfddfc338caf8d8 134.98.1.81 26379 @ mymaster 134.98.1.72 6379
13437:X 23 Apr 2019 16:06:12.481 * +sentinel sentinel 034d49988aa4f58efbe2db5f6c6c5475d3651ad4 134.98.1.80 26379 @ mymaster 134.98.1.72 6379

我們模擬master宕機,將master shutdown後,sentinel開始工作選舉新的slave作爲master

13437:X 23 Apr 2019 16:07:36.863 # +sdown master mymaster 134.98.1.72 6379
13437:X 23 Apr 2019 16:07:36.990 # +new-epoch 1
13437:X 23 Apr 2019 16:07:36.992 # +vote-for-leader 0881a984e2229c92812a37e24dfddfc338caf8d8 1
13437:X 23 Apr 2019 16:07:37.988 # +odown master mymaster 134.98.1.72 6379 #quorum 3/2
13437:X 23 Apr 2019 16:07:37.988 # Next failover delay: I will not start a failover before Tue Apr 23 16:09:37 2019
13437:X 23 Apr 2019 16:07:38.070 # +config-update-from sentinel 0881a984e2229c92812a37e24dfddfc338caf8d8 134.98.1.81 26379 @ mymaster 134.98.1.72 6379
13437:X 23 Apr 2019 16:07:38.070 # +switch-master mymaster 134.98.1.72 6379 134.98.1.81 6379
13437:X 23 Apr 2019 16:07:38.070 * +slave slave 134.98.1.80:6380 134.98.1.80 6380 @ mymaster 134.98.1.81 6379
13437:X 23 Apr 2019 16:07:38.070 * +slave slave 134.98.1.72:6379 134.98.1.72 6379 @ mymaster 134.98.1.81 6379
13437:X 23 Apr 2019 16:07:43.145 # +sdown slave 134.98.1.72:6379 134.98.1.72 6379 @ mymaster 134.98.1.81 6379

上面可以看到 81機器已經成功上位 成爲新的master,80自動跟從於81主機

通過info replication 查看信息可看到
81機器

# Replication
role:master
connected_slaves:1
slave0:ip=134.98.1.80,port=6380,state=online,offset=1059414,lag=1
master_replid:49c4d69750208186e74d53f6e7d02576cbc67fa6
master_replid2:b754d6583e4c987d8b51fe29f443479397ef8572
master_repl_offset:1059551
second_repl_offset:1050157
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1023219
repl_backlog_histlen:36333

80機器

# Replication
role:slave
master_host:134.98.1.81
master_port:6379
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
slave_repl_offset:1062593
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:49c4d69750208186e74d53f6e7d02576cbc67fa6
master_replid2:b754d6583e4c987d8b51fe29f443479397ef8572
master_repl_offset:1062593
second_repl_offset:1050157
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1023303
repl_backlog_histlen:39291

問題:如果此時原來的master 72機器恢復好了 重新啓動會是什麼情況呢?下面我們模擬一下。
啓動成功 sentinel日誌裏看見:
在這裏插入圖片描述
info replication 查看得知

# Replication
role:slave
master_host:134.98.1.80
master_port:6380
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:1125636
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:49c4d69750208186e74d53f6e7d02576cbc67fa6
master_replid2:b754d6583e4c987d8b51fe29f443479397ef8572
master_repl_offset:1125636
second_repl_offset:1050157
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1050157
repl_backlog_histlen:75480

此時我們的主機依然還是81機器,而原來的主機會自動成爲slave跟從於81機器。

哨兵選舉算法:

會考慮slave的一些信息:

  1. 跟master斷開連接的時長
  2. slave優先級
  3. 複製offset
  4. run id

如果一個slave跟master斷開連接已經超過了down-after-milliseconds的10倍,外加master宕機的時長,那麼slave就被認爲不適合選舉爲master(down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state

接下來會對slave進行排序(1)按照slave優先級進行排序,slave priority越低,優先級就越高(2)如果slave priority相同,那麼看replica offset,哪個slave複製了越多的數據,offset越靠後,優先級就越高(3)如果上面兩個條件都相同,那麼選擇一個run id比較小的那個slav

如果想要slave 永遠不參與選舉 可以將slave priority設爲0

【參考資料】
《Redis實戰》
GitChat – Redis入門到分佈式實踐
https://www.jianshu.com/p/63e2d3e1d9ee
https://www.cnblogs.com/PatrickLiu/p/8444546.html

如有總結不當,有問題,錯誤的地方請大家予以指正,共同學習,共同進步

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章