Redis主從同步與集群管理

1.主從同步原理像MySQL一樣,Redis是支持主從同步的,而且也支持一主多從以及多級從結(jié)構(gòu)。主從結(jié)構(gòu),一是為了純粹的冗余備份,二是為了提升讀性能,比如很消耗性能的SORT就可以由從服務(wù)器來承擔。Redis的主從同步是異步進行的,這意味著主從同步不會影響主邏輯,也不會降低Redis的處理性能。主從架構(gòu)中,可以考慮關(guān)閉主服務(wù)器的數(shù)據(jù)持久化功能,只讓從服務(wù)器進行持久化,這樣可以提高主服務(wù)器的處理性能。在主從架構(gòu)中,從服務(wù)器通常被設(shè)置為只讀模式,這樣可以避免從服務(wù)器的數(shù)據(jù)被誤修改。但是從服務(wù)器仍然可以接受CONFIG等指令,所以還是不應(yīng)該將從服務(wù)器直接暴露到不安全的網(wǎng)絡(luò)環(huán)境中。如果必須如此,那可以考慮給重要指令進行重命名,來避免命令被外人誤執(zhí)行。


從服務(wù)器會向主服務(wù)器發(fā)出SYNC指令,當主服務(wù)器接到此命令后,就會調(diào)用BGSAVE指令來創(chuàng)建一個子進程專門進行數(shù)據(jù)持久化工作,也就是將主服務(wù)器的數(shù)據(jù)寫入RDB文件中。在數(shù)據(jù)持久化期間,主服務(wù)器將執(zhí)行的寫指令都緩存在內(nèi)存中。

在BGSAVE指令執(zhí)行完成后,主服務(wù)器會將持久化好的RDB文件發(fā)送給從服務(wù)器,從服務(wù)器接到此文件后會將其存儲到磁盤上,然后再將其讀取到內(nèi)存中。這個動作完成后,主服務(wù)器會將這段時間緩存的寫指令再以Redis協(xié)議的格式發(fā)送給從服務(wù)器。


另外,要說的一點是,即使有多個從服務(wù)器同時發(fā)來SYNC指令,主服務(wù)器也只會執(zhí)行一次BGSAVE,然后把持久化好的RDB文件發(fā)給多個下游。在Redis2.8版本之前,如果從服務(wù)器與主服務(wù)器因某些原因斷開連接的話,都會進行一次主從之間的全量的數(shù)據(jù)同步;而在2.8版本之后,Redis支持了效率更高的增量同步策略,這大大降低了連接斷開的恢復(fù)成本。

主服務(wù)器會在內(nèi)存中維護一個緩沖區(qū),緩沖區(qū)中存儲著將要發(fā)給從服務(wù)器的內(nèi)容。從服務(wù)器在與主服務(wù)器出現(xiàn)網(wǎng)絡(luò)瞬斷之后,從服務(wù)器會嘗試再次與主服務(wù)器連接,一旦連接成功,從服務(wù)器就會把“希望同步的主服務(wù)器ID”和“希望請求的數(shù)據(jù)的偏移位置(replication offset)”發(fā)送出去。主服務(wù)器接收到這樣的同步請求后,首先會驗證主服務(wù)器ID是否和自己的ID匹配,其次會檢查“請求的偏移位置”是否存在于自己的緩沖區(qū)中,如果兩者都滿足的話,主服務(wù)器就會向從服務(wù)器發(fā)送增量內(nèi)容。

增量同步功能,需要服務(wù)器端支持全新的PSYNC指令。這個指令,只有在Redis-2.8之后才具有。

Redis復(fù)制工作原理的總結(jié)如下:

1. 如果設(shè)置了一個Slave,無論是第一次連接還是重連到Master,它都會發(fā)出一個SYNC命令;

2. 當Master收到SYNC命令之后,會做兩件事:

a) Master執(zhí)行BGSAVE,即在后臺保存數(shù)據(jù)到磁盤(rdb快照文件);

b) Master同時將新收到的寫入和修改數(shù)據(jù)集的命令存入緩沖區(qū)(非查詢類);

3. 當Master在后臺把數(shù)據(jù)保存到快照文件完成之后,Master會把這個快照文件傳送給Slave,而Slave則把內(nèi)存清空后,加載該文件到內(nèi)存中;

4. 而Master也會把此前收集到緩沖區(qū)中的命令,通過Reids命令協(xié)議形式轉(zhuǎn)發(fā)給Slave,Slave執(zhí)行這些命令,實現(xiàn)和Master的同步;

5. Master/Slave此后會不斷通過異步方式進行命令的同步,達到最終數(shù)據(jù)的同步一致;

6. 需要注意的是Master和Slave之間一旦發(fā)生重連都會引發(fā)全量同步操作。但在2.8之后版本,也可能是部分同步操作。

部分復(fù)制

2.8開始,當Master和Slave之間的連接斷開之后,他們之間可以采用持續(xù)復(fù)制處理方式代替采用全量同步。

Master端為復(fù)制流維護一個內(nèi)存緩沖區(qū)(in-memory backlog),記錄最近發(fā)送的復(fù)制流命令;同時,Master和Slave之間都維護一個復(fù)制偏移量(replication offset)和當前Master服務(wù)器ID(Masterrun id)。當網(wǎng)絡(luò)斷開,Slave嘗試重連時:

a. 如果MasterID相同(即仍是斷網(wǎng)前的Master服務(wù)器),并且從斷開時到當前時刻的歷史命令依然在Master的內(nèi)存緩沖區(qū)中存在,則Master會將缺失的這段時間的所有命令發(fā)送給Slave執(zhí)行,然后復(fù)制工作就可以繼續(xù)執(zhí)行了;b. 否則,依然需要全量復(fù)制操作;Redis 2.8 的這個部分重同步特性會用到一個新增的PSYNC 內(nèi)部命令,?

而 Redis 2.8 以前的舊版本只有 SYNC 命令, 不過, 只要從服務(wù)器是 Redis 2.8 或以上的版本,它就會根據(jù)主服務(wù)器的版本來決定到底是使用 PSYNC 還是 SYNC :如果主服務(wù)器是 Redis 2.8 或以上版本,那么從服務(wù)器使用 PSYNC 命令來進行同步;如果主服務(wù)器是 Redis 2.8 之前的版本,那么從服務(wù)器使用 SYNC 命令來進行同步。

注意:SYNC命令是一個非常耗費資源的操作

SYNC命令是非常消耗資源的,因為每次執(zhí)行SYNC命令,主從服務(wù)器需要執(zhí)行一下操作:

主服務(wù)器需要執(zhí)行BGSAVE命令來生成RDB文件,這個生成操作會耗費主服務(wù)器大量的CPU、內(nèi)存和磁盤I/O資源;

主服務(wù)器需要將自己生成的RDB文件發(fā)送給從服務(wù)器,這個發(fā)送操作會耗費主從服務(wù)器大量的網(wǎng)絡(luò)資源(帶寬和流量),并對主服務(wù)器響應(yīng)命令請求的時間產(chǎn)生影響;

接收到RDB文件的從服務(wù)器需要載入主服務(wù)器發(fā)來的RDB文件,并且在載入期間,從服務(wù)器會因為阻塞而沒辦法處理命令請求。

SYNC是一個如此消耗資源的命令,所以Redis最好在真需要的時候才需要執(zhí)行SYNC命令。

可以在一臺機器上使用不同的端口來模擬多臺機器的主從同步。

2.主從同步配置:

下面以默認端口6379為Master,以6380、6381端口為兩個Slave。

找到Redis安裝路徑下的redis.conf,復(fù)制兩份,分別命名為“redis-6380.conf”與“redis-6381.conf”。


使用命令“redis-server–h 127.0.0.1 –p 6379”啟動Master實例,再使用“redis-server –h 127.0.0.1 –p 6380”與“redis-server–h 127.0.0.1 –p 6381”啟動兩個Slave實例。

通過set和get實驗同步是否進行。

3 Sentinel實現(xiàn)機制與用法:哨兵模式

Redis-Sentinel是Redis官方推薦的高可用性(HA,High Available)解決方案,當用Redis做Master-slave的高可用方案時,假如master宕機了,Redis本身(包括它的很多客戶端)都沒有實現(xiàn)自動進行主備切換,而Redis-sentinel本身也是一個獨立運行的進程,它能監(jiān)控多個master-slave集群,發(fā)現(xiàn)master宕機后能進行選舉切換。

它的主要功能有以下幾點

(1)不時地監(jiān)控redis是否按照預(yù)期良好地運行;

(2)如果發(fā)現(xiàn)某個redis節(jié)點運行出現(xiàn)狀況,能夠通知另外一個進程(例如它的客戶端);

(3)能夠進行自動切換。當一個master節(jié)點不可用時,能夠選舉出master的多個slave(如果有超過一個slave的話)中的一個來作為新的master,其它的slave節(jié)點會將它所追隨的master的地址改為被提升為master的slave的新地址。

很顯然,只使用單個sentinel進程來監(jiān)控redis集群是不可靠的,當sentinel進程宕掉后(sentinel本身也有單點問題,single-point-of-failure)整個集群系統(tǒng)將無法按照預(yù)期的方式運行。所以有必要將sentinel集群:


運行sentinel有兩種方式:

redis-sentinel /path/to/sentinel.conf

redis-server /path/to/sentinel.conf --sentinel

以上兩種方式,都必須指定一個sentinel的配置文件sentinel.conf,如果不指定,將無法啟動sentinel。sentinel默認監(jiān)聽26379端口,所以運行前必須確定該端口沒有被別的進程占用。

Redis源碼包中包含了一個sentinel.conf文件作為sentinel的配置文件,配置文件自帶了關(guān)于各個配置項的解釋。典型的配置項如下所示:

port 26379

工作端口,默認值為26379。

dir "/private/tmp"

工作路徑。

sentinelmonitor mymaster 127.0.0.1 6379 2

這一行代表sentinel監(jiān)控的master的名字叫做mymaster,地址為127.0.0.1:6379,行尾最后的一個2代表什么意思呢?我們知道,網(wǎng)絡(luò)是不可靠的,有時候一個sentinel會因為網(wǎng)絡(luò)堵塞而誤以為一個master redis已經(jīng)死掉了,當sentinel集群式,解決這個問題的方法就變得很簡單,只需要多個sentinel互相溝通來確認某個master是否真的死了,這個2代表,當集群中有2個sentinel認為master死了時,才能真正認為該master已經(jīng)不可用了。(sentinel集群中各個sentinel也有互相通信,通過gossip協(xié)議)。

sentineldown-after-milliseconds mymaster 1800

sentinel會向master發(fā)送心跳PING來確認master是否存活,如果master在“一定時間范圍”內(nèi)不回應(yīng)PONG 或者是回復(fù)了一個錯誤消息,那么這個sentinel會主觀地(單方面地)認為這個master已經(jīng)不可用了(subjectively down, 也簡稱為SDOWN)。而這個down-after-milliseconds就是用來指定這個“一定時間范圍”的,單位是毫秒。

不過需要注意的是,這個時候sentinel并不會馬上進行failover主備切換,這個sentinel還需要參考sentinel集群中其他sentinel的意見,如果超過某個數(shù)量的sentinel也主觀地認為該master死了,那么這個master就會被客觀地(這次不是主觀,是客觀,與剛才的subjectively down相對,這次是objectively down,簡稱為ODOWN)認為已經(jīng)死了。需要一起做出決定的sentinel數(shù)量在上一條配置中進行配置。

sentinelfailover-timeout mymaster 36000

若sentinel在該配置值內(nèi)未能完成failover操作(即故障時master/slave自動切換),則認為本次failover失敗

parallel-syncsmymaster 1

在發(fā)生failover主備切換時,這個選項指定了最多可以有多少個slave同時對新的master進行同步,這個數(shù)字越小,完成failover所需的時間就越長,但是如果這個數(shù)字越大,就意味著越多的slave因為replication而不可用。可以通過將這個值設(shè)為 1 來保證每次只有一個slave處于不能處理命令請求的狀態(tài)。

其余配置項可參考原文的注釋。

所有的配置都可以在運行時用命令SENTINEL SET command動態(tài)修改。

sentinel集群中各個sentinel都互相連接彼此來檢查對方的可用性以及互相發(fā)送消息。但是不用在任何一個sentinel配置任何其它的sentinel的節(jié)點。因為sentinel利用了master的發(fā)布/訂閱機制去自動發(fā)現(xiàn)其它也監(jiān)控了同一master的sentinel節(jié)點。通過向名為__sentinel__:hello的管道中發(fā)送消息來實現(xiàn)。同樣,也不需要在sentinel中配置某個master的所有slave的地址,sentinel會通過詢問master來得到這些slave的地址的。每個sentinel通過向每個master和slave的發(fā)布/訂閱頻道__sentinel__:hello每秒發(fā)送一次消息,來宣布它的存在。每個sentinel也訂閱了每個master和slave的頻道__sentinel__:hello的內(nèi)容,來發(fā)現(xiàn)未知的sentinel,當檢測到了新的sentinel,則將其加入到自身維護的master監(jiān)控列表中。每個sentinel發(fā)送的消息中也包含了其當前維護的最新的master配置。如果某個sentinel發(fā)現(xiàn)。自己的配置版本低于接收到的配置版本,則會用新的配置更新自己的master配置。為一個master添加一個新的sentinel前,sentinel總是檢查是否已經(jīng)有sentinel與新的sentinel的進程號或者是地址是一樣的。如果是那樣,這個sentinel將會被刪除,而把新的sentinel添加上去。

需要注意的是,配置文件在sentinel運行期間是會被動態(tài)修改的,例如當發(fā)生主備切換時候,配置文件中的master會被修改為另外一個slave。這樣,之后sentinel如果重啟時,就可以根據(jù)這個配置來恢復(fù)其之前所監(jiān)控的redis集群的狀態(tài)。

failover機制

前面我們談到,當一個master被sentinel集群監(jiān)控時,需要為它指定一個參數(shù),這個參數(shù)指定了當需要判決master為不可用并且進行failover時所需要的sentinel數(shù)量,本文中我們暫時稱這個參數(shù)為票數(shù)。

不過,當failover主備切換真正被觸發(fā)后,failover并不會馬上進行,還需要sentinel中的大多數(shù)sentinel授權(quán)后才可以進行failover。

當ODOWN時,failover被觸發(fā)。failover一旦被觸發(fā),嘗試去進行failover的sentinel會去獲得“大多數(shù)”sentinel的授權(quán)(如果票數(shù)比大多數(shù)還要大的時候,則詢問更多的sentinel)

例如,集群中有5個sentinel,票數(shù)被設(shè)置為2,當2個sentinel認為一個master已經(jīng)不可用了以后,將會觸發(fā)failover,但是,進行failover的那個sentinel必須先獲得至少3個sentinel的授權(quán)才可以實行failover。

如果票數(shù)被設(shè)置為5,要達到ODOWN狀態(tài),必須所有5個sentinel都主觀認為master為不可用,要進行failover,那么得獲得所有5個sentinel的授權(quán)。

而且,sentinel集群都遵守一個規(guī)則:如果sentinel A推薦sentinel B去執(zhí)行failover,B會等待一段時間后,自行再次去對同一個master執(zhí)行failover,這個等待的時間是通過failover-timeout配置項去配置的。從這個規(guī)則可以看出,sentinel集群中的sentinel不會再同一時刻并發(fā)去failover同一個master,第一個進行failover的sentinel如果失敗了,另外一個將會在一定時間內(nèi)進行重新進行failover,以此類推。

(1)redis sentinel保證了活躍性:如果大多數(shù)sentinel能夠互相通信,最終將會有一個被授權(quán)去進行failover.

(2)redis sentinel也保證了安全性:每個試圖去failover同一個master的sentinel都會得到一個獨一無二的版本號。

一旦一個sentinel成功地對一個master進行了failover,它將會把關(guān)于master的最新配置通過廣播形式通知其它sentinel,其它的sentinel則更新對應(yīng)master的配置。

一個faiover要想被成功實行,sentinel必須能夠向選為master的slave發(fā)送SLAVE OF NO ONE命令,然后能夠通過INFO命令看到新master的配置信息。

當將一個slave選舉為master并發(fā)送SLAVE OF NO ONE后,即使其它的slave還沒針對新master重新配置自己,failover也被認為是成功了的,然后所有sentinels將會發(fā)布新的配置信息。

新配在集群中相互傳播的方式,就是為什么我們需要當一個sentinel進行failover時必須被授權(quán)一個版本號的原因。

每個sentinel使用##發(fā)布/訂閱##的方式持續(xù)地傳播master的配置版本信息,配置傳播的##發(fā)布/訂閱##管道是:__sentinel__:hello。

因為每一個配置都有一個版本號,所以以版本號最大的那個為標準。

例如:假設(shè)有一個名為mymaster的地址為192.168.1.50:6379。一開始,集群中所有的sentinel都知道這個地址,于是為mymaster的配置打上版本號1。一段時候后mymaster死了,有一個sentinel被授權(quán)用版本號2對其進行failover。如果failover成功了,假設(shè)地址改為了192.168.1.50:9000,此時配置的版本號為2,進行failover的sentinel會將新配置廣播給其他的sentinel,由于其他sentinel維護的版本號為1,發(fā)現(xiàn)新配置的版本號為2時,版本號變大了,說明配置更新了,于是就會采用最新的版本號為2的配置。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,732評論 6 539
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,214評論 3 426
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,781評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,588評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,315評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,699評論 1 327
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,698評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,882評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,441評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,189評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,388評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,933評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,613評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,023評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,310評論 1 293
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,112評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,334評論 2 377

推薦閱讀更多精彩內(nèi)容