天天看點

redis主從複制與哨兵模式

一個Redis服務可以有多個複制品,這個Redis服務稱為Master,其它複制品稱為Slaves;Master會一直将自己的資料更新同步到Slaves,保持主從一緻。

1. 主從配置

有兩種方式可以配置redis的主從複制,一是在啟動時,二是在啟動後:

①在服務啟動時,就指定它為一個從伺服器(這種配置方式是臨時的)

  指令:redis-server --slaveof <master-ip> <master-port>

redis主從複制與哨兵模式

  或者,配置redis.conf檔案,開啟slaveof配置(這種配置方式是永久的)

redis主從複制與哨兵模式

②在服務啟動後,将它的狀态由master改為slave,指令:

127.0.0.1:6380> slaveof 127.0.0.1 6379,将伺服器狀态轉換成slave

127.0.0.1:6380> slaveof no one,将伺服器狀态重新轉換成master

(這種方式也是臨時的,在伺服器關閉以後,就不在生效)

其它配置:

1、如果master伺服器開啟了身份認證,即配置了requirepass屬性(比如requirepass root)表示連接配接到master伺服器需要密碼root;則slave伺服器需要配置masterauth屬性(即:masterauth root)否則master會拒絕slave的連接配接。

2、slave伺服器在一般情況下,都要配置成隻讀模式,即配置slave-read-only屬性(即:slave-read-only no,從redis2.6開始此項就預設為no)。這樣master就負責寫,其它從伺服器slave就負責讀。如果slave也可以寫,它并不會把自己的資料同步到master上,導緻主從資料不一緻。

2.主從拓撲

redis有3種主從伺服器的搭建拓撲:

①一主一從,用于master故障轉移slave。使用場景:master的“寫”指令頻繁并且需要持久化,可以隻在slave開啟AOF(master就不需要開啟),既可以保證資料安全性,也避免持久化對master的影響。

redis主從複制與哨兵模式

②一主多從,适用于“讀”指令較多的場景,配置多個slave來分擔master的讀壓力,但是,slave越多,master同步資料到slave的次數也會增多,可能會影響帶寬

redis主從複制與哨兵模式

③樹狀主從,用來解決第②種一主多從的問題(master同步資料到slave的壓力過大),master同步修改的指令給從節點B,再由從節點B把修改指令同步給C和E。這種拓撲的配置步驟:

①配置主伺服器master-A;

②配置從伺服器slave-B,它的主伺服器是master-A;

③配置從伺服器slave-C,它的主伺服器是slave-B(說白了,就是從伺服器是另一個從伺服器的“主伺服器”)這樣master-A就不用直接把資料同步給slave-C,A隻需要把資料同步給B,再由B同步給C,減輕主伺服器master-A的資料同步壓力!

redis主從複制與哨兵模式

3.主從同步政策

當将一個redis服務配置為另一個redis服務的從伺服器時,為了保證主從資料同步,從伺服器需要複制主伺服器的資料。這個過程有兩種情況:一種是剛剛配置主從關系時,此時的複制操作稱為“全量同步”;另一種是主從配置以後,主伺服器的修改都會同步到從伺服器上,此時的複制操作稱為“增量同步”

3.1 全量同步

全量同步發生在主從複制剛配置好的階段,此時主伺服器上的資料需要全部同步到從伺服器上,會發生以下步驟:

redis主從複制與哨兵模式

①slave連接配接到master上,并發送SYNC指令

②master收到SYNC指令後,執行BGSAVE生成RDB快照,在快照生成後,master向所有slave發送RDB快照,并且master還會緩沖區記錄期間的寫指令

③slave收到RDB快照,清空自己的資料庫,載入RDB快照

④master發送完快照後,開始發送②步記錄在緩沖區的寫指令

⑤slave接收并執行master的寫指令。至此,主從資料基本同步

3.2 增量同步

經過全量同步後,主從伺服器的資料基本一緻,但主伺服器master的資料并不是一成不變的。當執行寫指令後,master會把這條指令發送給slave,slave接收并執行這條寫指令,繼續保持主從資料一緻,這個過程就是增量同步。

4.主從同步原理

當主從伺服器在執行資料同步時,redis2.8版本之前,從伺服器是發送SYNC指令給主伺服器;而當redis2.8起,從伺服器是發送PSYNC指令給主伺服器。

4.1 SYNC

SYNC指令是非常消耗性能的,redis伺服器每次執行SYNC指令,都要先生成RDB檔案,再發送給從伺服器,然後從伺服器再來執行這個RDB檔案,整個過程不僅消耗主伺服器的CPU和網絡資源,且從伺服器在載入RDB檔案時,也會因為阻塞而不能處理請求。但問題遠沒有那麼簡單,SYNC指令被抛棄的原因是:當master和slave在增量同步時,由于各種原因slave斷開連接配接,然後slave會一直自動重連master,一段時間後,主從伺服器恢複連接配接,但是此時的主從資料已經不同步了,slave會發送SYNC指令重新請求同步資料。但其實slave缺失的僅僅是master掉線期間更新的資料,但是卻要同步master所有的資料,相當于重新執行一遍SYNC,這是十分低效且浪費資源的

4.2 PSYNC

redis為了解決SYNC效率低的問題,開始在2.8版本以後,使用PSYNC代替SYNC指令。PSNYC指令具有“完整重同步”和“部分重同步”兩種模式,“完整重同步”适用于全量同步,這一點與SYNC指令一樣;“部分重同步”則專門用于處理主從伺服器斷開連接配接後重同步的情況,把斷線期間,master執行的指令同步到slave上。那麼master在收到PSYNC指令後是怎麼判斷要對slave使用“完整重同步”還是“部分重同步”?這就涉及到PSYNC指令的原理,PSYNC的部分重同步模式由以下3個部分組成:

   ①主、從伺服器各自的複制偏移量

   ②主伺服器的複制積壓緩沖區

   ③伺服器的運作ID

4.2.1 複制偏移量

master和slave都各自維護一個複制偏移量,master每次同步給slave伺服器N個位元組的資料時,就把自己的複制偏移量+N;同理,slave接收到master伺服器的N個位元組的資料,就把自己的複制偏移量+N;通過這個複制偏移量,就可以知道主從伺服器之間是否處于資料一緻狀态。

redis主從複制與哨兵模式

4.2.2 複制積壓緩沖區

複制積壓緩沖區是由master維護的一個固定長度的先進先出隊列,預設為1MB。當複制積壓緩沖區滿的時候,仍有新元素進來,則最先入隊的元素會被彈出,而新元素被放到隊尾。master在進行資料同步時,不僅會把指令發送給從伺服器,還會把指令儲存到複制積壓緩沖區裡,且複制積壓緩沖區會把指令的每個位元組記錄相應的複制偏移量:

redis主從複制與哨兵模式

是以當slave重新連接配接上master時,會将自己的複制偏移量通過PSYNC發送給master。master判斷:若slave發過來的複制偏移量+1後的資料仍在複制積壓緩沖區内,就執行“部分重同步”操作,反之執行“完整重同步”。由此可見,複制積壓緩沖區是非常重要的,設定太大和太小都不能發揮PSYNC的正常功能。一般是根據公式:

緩沖區大小 = second * write_size_per_second

second:從伺服器斷線後重新連接配接上主伺服器所需的平均時間(以秒計算)

write_size_per_second:是主伺服器平均每秒産生的寫指令資料量(協定格式的寫指令的長度總和);

例如:

如果主伺服器平均每秒産生1 MB的寫資料,而從伺服器斷線之後平均要5秒才能重新連接配接上主伺服器,那麼複制積壓緩沖區的大小就不能低于5MB!

4.2.3 服務運作ID

每個redis伺服器,不論是master還是slave,都會有自己的運作ID,該ID會在服務啟動時自動生成,為40個随機的十六進制字元。除了複制偏移量和複制積壓緩沖區,要實作PSYNC指令的“部分重同步”還需要用到這個服務運作ID。

當主從伺服器第一次互動,即全量同步時,master會把自己的運作ID發送給slave,slave儲存該運作ID;當slave掉線重連,需要重新更新資料,slave會通過PSYNC指令将之前儲存的master運作ID一并發送給目前重連的master;若master發現這個運作ID跟自己的運作ID一樣,它就會對slave執行“部分重同步”操作(當然還需要判斷複制偏移量和複制積壓緩沖區的情況);否則,一旦slave發送的運作ID跟自己的運作ID不一樣,說明slave之前連接配接的主伺服器不是自己,那麼它就會對slave執行“完整重同步”操作。

個人了解:服務運作ID的判斷優先于複制偏移量和複制積壓緩沖區!

5.哨兵模式

單單的主從複制,在發生故障時,沒有辦法自行故障轉移。是以,在實際生産運用中,主從複制往往和哨兵模式結合在一起,使用哨兵模式Sentinel管理多個redis服務執行個體。Redis Sentinel是一個分布式系統,可以在一個架構中運作多個Sentinel程序,編譯後産生redis-sentinel程式檔案。

5.1 sentinel工作流程

一個Sentinel可以監控多個master以及它們對應的slave,如下圖所示:

redis主從複制與哨兵模式

哨兵Sentinel是分布式架構,是為了防止當Sentinel伺服器當機而使整個監控系統崩潰。監控同一個Master的Sentinel會自動連接配接,組成一個分布式的Sentinel網絡,互相通信并且交換彼此對Master的監控資訊,如下圖所示:

redis主從複制與哨兵模式

工作過程:

   Sentinel會不斷檢查Master和它的slave是否正常,當一個Sentinel監控到有個伺服器下線(出故障了),它會向哨兵網絡的其他Sentinel進行确認,判斷該伺服器是否真的下線(出故障了);如果下線的伺服器是master伺服器,Sentinel網絡會對下線master伺服器進行自動故障轉移:将該master伺服器旗下的某個slave伺服器提升為新的master伺服器,并且在其他slave伺服器中設定新的master伺服器。(若下線的伺服器重新上線,它将變為slave伺服器,請求複制新選舉的master)

注意:Sentinel在選舉新的slave節點為master節點時,會修改所有相關節點的配置檔案redis.conf,包括哨兵自己的配置檔案sentinel.conf

5.2 配置sentinel.conf

啟動一個哨兵Sentinel需要sentibel.conf,該配置檔案可以在redis的源碼包找到。當啟動了多個哨兵sentinel,監聽相同master的sentinel就會自動組成一個哨兵網絡。一個哨兵網絡内的sentinel,它們的配置檔案

sentibel.conf,除了端口号不一樣外,其它屬性基本一緻。

常用屬性配置:

// Sentinel節點啟動時占用的端口(預設是26379)

// dir是sentinel節點的工作目錄

// logfile是sentinel節點的日志記錄檔案名

port 26379 

dir /var/redis/data/

logfile "26379.log"

// 目前Sentinel節點監控 127.0.0.1:6379 這個主節點(即master)

// mymaster是主節點的别名,後面的配置就可以使用這個别名

// 2代表判斷主節點故障,至少需要2個Sentinel節點認可

sentinel monitor mymaster 127.0.0.1 6379 2

(注:這邊為什麼隻需要配置master伺服器即可?因為slave伺服器的資訊可以從master伺服器拿到)

//每個Sentinel節點都要定期PING指令來判斷Redis資料節點和其餘//Sentinel節點是否可達,如果超過30000毫秒且沒有回複,則判定不可達

sentinel down-after-milliseconds mymaster 30000

//當Sentinel節點集合對主節點故障判定達成一緻時,Sentinel上司者節點//會做故障轉移操作,選出新的主節點。原來的從節點會向新的主節點發起複制//操作,限制每次向新的主節點發起複制操作的從節點個數為1

sentinel parallel-syncs mymaster 1

//故障轉移逾時時間為180000毫秒

sentinel failover-timeout mymaster 180000

//如果redis服務節點配置了認證,則Sentinel需要配置認證密碼,不然它//連接配接不上該服務節點,更談不上監控了

//mymaster是配置監控節點時設定的别名,root是redis服務節點的密碼

sentinel auth-pass mymaster root

5.3 啟動sentinel

配置好sentinel.conf以後,就可以啟動一個哨兵執行個體,有兩種方式啟動:

①使用redis-server啟動

  指令:redis-server <sentinel.conf路徑> --sentinel

  例子:redis-server /usr/redis/sentinel.conf –-sentinel

②使用redis-sentinel啟動

  将redis源碼包/src/redis-sentinel程式檔案拷貝到redis安裝包的bin目錄下(如果bin目錄已經有redis-sentinel,這一步就可以省略了)。

  指令:redis-sentinel < sentinel.conf路徑>

  例子:redis-sentinel /usr/redis/sentinel.conf

啟動并且監聽成功的資訊:

redis主從複制與哨兵模式