天天看點

分布式緩存Redis使用心得

最近對開源分布式緩存産品redis做了一些研究,于是決定整理一下該産品的特性及使用場景拿出來分享。

一、緩存在系統中用來做什麼

1. 少量資料存儲,高速讀寫通路。通過資料全部in-momery 的方式來保證高速通路,同時提供資料落地的功能,實際這正是redis最主要的适用場景。

2. 海量資料存儲,分布式系統支援,資料一緻性保證,友善的叢集節點添加/删除。redis3.0以後開始支援叢集,實作了半自動化的資料分片,不過需要smart-client的支援。

二、從不同的角度來詳細介紹redis

網絡模型:redis使用單線程的io複用模型,自己封裝了一個簡單的aeevent事件處理架構,主要實作了epoll、kqueue和select,對于單純隻有io操作來說,單線程可以将速度優勢發揮到最大,但是redis也提供了一些簡單的計算功能,比如排序、聚合等,對于這些操作,單線程模型實際會嚴重影響整體吞吐量,cpu計算過程中,整個io排程都是被阻塞住的。

記憶體管理:redis使用現場申請記憶體的方式來存儲資料,并且很少使用free-list等方式來優化記憶體配置設定,會在一定程度上存在記憶體碎片,redis跟據存儲指令參數,會把帶過期時間的資料單獨存放在一起,并把它們稱為臨時資料,非臨時資料是永遠不會被剔除的,即便實體記憶體不夠,導緻swap也不會剔除任何非臨時資料(但會嘗試剔除部分臨時資料),這點上redis更适合作為存儲而不是cache。

資料一緻性問題:在一緻性問題上,個人感覺redis沒有memcached實作的好,memcached提供了cas指令,可以保證多個并發通路操作同一份資料的一緻性問題。 redis沒有提供cas 指令,并不能保證這點,不過redis提供了事務的功能,可以保證一串指令的原子性,中間不會被任何操作打斷。

支援的key類型:redis除key/value之外,還支援list,set,sorted set,hash等衆多資料結構,提供了keys進行枚舉操作,但不能線上上使用,如果需要枚舉線上資料,redis提供了工具可以直接掃描其dump檔案,枚舉出所有資料,redis還同時提供了持久化和複制等功能。

用戶端支援:redis官方提供了豐富的用戶端支援,包括了絕大多數程式設計語言的用戶端,比如我此次測試就選擇了官方推薦了java用戶端jedis.裡面提供了豐富的接口、方法使得開發人員無需關系内部的資料分片、讀取資料的路由等,隻需簡單的調用即可,非常友善。

資料複制:從2.8開始,slave會周期性(每秒一次)發起一個ack确認複制流(replication stream)被處理進度, redis複制工作原理詳細過程如下:

1. 如果設定了一個slave,無論是第一次連接配接還是重連到master,它都會發出一個sync指令;

2. 當master收到sync指令之後,會做兩件事:

a) master執行bgsave:背景寫資料到磁盤(rdb快照);

b) master同時将新收到的寫入和修改資料集的指令存入緩沖區(非查詢類);

3. 當master在背景把資料儲存到快照檔案完成之後,master會把這個快照檔案傳送給slave,而slave則把記憶體清空後,加載該檔案到記憶體中;

4. 而master也會把此前收集到緩沖區中的指令,通過reids指令協定形式轉發給slave,slave執行這些指令,實作和master的同步;

5. master/slave此後會不斷通過異步方式進行指令的同步,達到最終資料的同步一緻;

6. 需要注意的是master和slave之間一旦發生重連都會引發全量同步操作。但在2.8之後,也可能是部分同步操作。

2.8開始,當master和slave之間的連接配接斷開之後,他們之間可以采用持續複制處理方式代替采用全量同步。

master端為複制流維護一個記憶體緩沖區(in-memory backlog),記錄最近發送的複制流指令;同時,master和slave之間都維護一個複制偏移量(replication offset)和目前master伺服器id(masterrun id)。

當網絡斷開,slave嘗試重連時:

a. 如果masterid相同(即仍是斷網前的master伺服器),并且從斷開時到目前時刻的曆史指令依然在master的記憶體緩沖區中存在,則master會将缺失的這段時間的所有指令發送給slave執行,然後複制工作就可以繼續執行了;

b. 否則,依然需要全量複制操作。

讀寫分離:redis支援讀寫分離,而且使用簡單,隻需在配置檔案中把redis讀伺服器和寫伺服器進行配置,多個伺服器使用逗号分開如下:

分布式緩存Redis使用心得

水準動态擴充:曆時三年之久,終于等來了期待已由的redis 3.0。新版本主要是實作了cluster的功能,增删叢集節點後會自動的進行資料遷移。實作 redis 叢集線上重配置的核心就是将槽從一個節點移動到另一個節點的能力。因為一個哈希槽實際上就是一些鍵的集合, 是以 redis 叢集在重哈希(rehash)時真正要做的,就是将一些鍵從一個節點移動到另一個節點。

資料淘汰政策:redis 記憶體資料集大小上升到一定大小的時候,就會施行資料淘汰政策。redis 提供 6種資料淘汰政策:

volatile-lru:從已設定過期時間的資料集(server.db[i].expires)中挑選最近最少使用的資料淘汰

volatile-ttl:從已設定過期時間的資料集(server.db[i].expires)中挑選将要過期的資料淘汰

volatile-random:從已設定過期時間的資料集(server.db[i].expires)中任意選擇資料淘汰

allkeys-lru:從資料集(server.db[i].dict)中挑選最近最少使用的資料淘汰

allkeys-random:從資料集(server.db[i].dict)中任意選擇資料淘汰

no-enviction(驅逐):禁止驅逐資料

三、叢集(即分布式)

下面詳細介紹一下redis的叢集功能,從3.0以後的版本開始支援叢集功能,也就是正真意義上實作了分布式。

redis 叢集是一個分布式(distributed)、容錯(fault-tolerant)的 redis 實作, 叢集可以使用的功能是普通單機 redis 所能使用的功能的一個子集(subset)。

redis 叢集中不存在中心(central)節點或者代理(proxy)節點, 叢集的其中一個主要設計目标是達到線性可擴充性(linear scalability)。

redis 叢集為了保證一緻性(consistency)而犧牲了一部分容錯性: 系統會在保證對網絡斷線(netsplit)和節點失效(node failure)具有有限(limited)抵抗力的前提下,盡可能地保持資料的一緻性。

叢集特性:

(1)所有的redis節點彼此互聯(ping-pong機制),内部使用二進制協定優化傳輸速度和帶寬。

(2)節點的fail是通過叢集中超過半數的節點檢測失效時才生效。

(3)用戶端與redis節點直連,不需要中間proxy層.用戶端不需要連接配接叢集所有節點,連接配接叢集中任何一個可用節點即可。

(4)redis-cluster把所有的實體節點映射到[0-16383]slot上,cluster 負責維護node<->slot<->value

redis 叢集實作的功能子集:

redis叢集實作了單機 redis 中, 所有處理單個資料庫鍵的指令。針對多個資料庫鍵的複雜計算操作, 比如集合的并集操作、合集操作沒有被實作,那些理論上需要使用多個節點的多個資料庫鍵才能完成的指令也沒有被實作。在将來, 使用者也許可以通過 migrate copy 指令,在叢集的計算節點(computation node)中執行針對多個資料庫鍵的隻讀操作, 但叢集本身不會去實作那些需要将多個資料庫鍵在多個節點中移來移去的複雜多鍵指令。

redis 叢集不像單機redis 那樣支援多資料庫功能, 叢集隻使用預設的 0 号資料庫, 并且不能使用 select 指令。

redis 叢集協定中的用戶端和伺服器:

redis 叢集中的節點有以下責任:

1. 持有鍵值對資料。

2. 記錄叢集的狀态,包括鍵到正确節點的映射(mappingkeys to right nodes)。

3. 自動發現其他節點,識别工作不正常的節點,并在有需要時,在從節點中選舉出新的主節點。

為了執行以上列出的任務, 叢集中的每個節點都與其他節點建立起了“叢集連接配接(cluster bus)”, 該連接配接是一個 tcp 連接配接, 使用二進制協定進行通訊。

節點之間使用gossip 協定 來進行以下工作:

1. 傳播(propagate)關于叢集的資訊,以此來發現新的節點。

2. 向其他節點發送 ping 資料包,以此來檢查目标節點是否正常運作。

3. 在特定事件發生時,發送叢集資訊。

4. 除此之外, 叢集連接配接還用于在叢集中釋出或訂閱資訊。

因為叢集節點不能代理(proxy)指令請求, 是以用戶端應該在節點傳回 -moved 或者 -ask 轉向(redirection)錯誤時,自行将指令請求轉發至其他節點。因為用戶端可以自由地向叢集中的任何一個節點發送指令請求, 并可以在有需要時, 根據轉向錯誤所提供的資訊, 将指令轉發至正确的節點,是以在理論上來說, 用戶端是無須儲存叢集狀态資訊的。不過, 如果用戶端可以将鍵和節點之間的映射資訊儲存起來, 可以有效地減少可能出現的轉向次數, 籍此提升指令執行的效率。

鍵分布模型

redis 叢集的鍵空間被分割為 16384 個槽(slot), 叢集的最大節點數量也是 16384 個。

推薦的最大節點數量為 1000 個左右。每個主節點都負責處理 16384 個哈希槽的其中一部分。

當我們說一個叢集處于“穩定”(stable)狀态時, 指的是叢集沒有在執行重配(reconfiguration)操作,每個哈希槽都隻由一個節點進行處理。重配置指的是将某個/某些槽從一個節點移動到另一個節點。一個主節點可以有任意多個從節點,這些從節點用于在主節點發生網絡斷線或者節點失效時, 對主節點進行替換。

叢集節點屬性:

每個節點在叢集中都有一個獨一無二的 id , 該 id 是一個十六進制表示的 160 位随機數, 在節點第一次啟動時由 /dev/urandom 生成。

節點會将它的 id 儲存到配置檔案, 隻要這個配置檔案不被删除,節點就會一直沿用這個 id 。節點 id 用于辨別叢集中的每個節點。一個節點可以改變它的 ip 和端口号, 而不改變節點 id 。叢集可以自動識别出 ip/端口号的變化, 并将這一資訊通過 gossip 協定廣播給其他節點知道。

以下是每個節點都有的關聯資訊, 并且節點會将這些資訊發送給其他節點:

1. 節點所使用的 ip 位址和 tcp 端口号。

2. 節點的标志(flags)。

3. 節點負責處理的哈希槽。

4. 節點最近一次使用叢集連接配接發送 ping 資料包(packet)的時間。

5. 節點最近一次在回複中接收到 pong 資料包的時間。

6. 叢集将該節點标記為下線的時間。

7. 該節點的從節點數量。

8. 如果該節點是從節點的話,那麼它會記錄主節點的節點 id 。如果這是一個主節點的話,那麼主節點 id 這一欄的值為 0000000 。

以上資訊的其中一部分可以通過向叢集中的任意節點(主節點或者從節點都可以)發送 cluster nodes 指令來獲得。

節點握手:

節點總是應答(accept)來自叢集連接配接端口的連接配接請求,并對接收到的 ping 資料包進行回複, 即使這個 ping 資料包來自不可信的節點。然而,除了 ping 之外, 節點會拒絕其他所有并非來自叢集節點的資料包。要讓一個節點承認另一個節點同屬于一個叢集,隻有以下兩種方法:

1. 一個節點可以通過向另一個節點發送 meet 資訊,來強制讓接收資訊的節點承認發送資訊的節點為叢集中的一份子。 一個節點僅在管理者顯式地向它發送cluster meet ipport 指令時, 才會向另一個節點發送 meet 資訊。

2. 如果一個可信節點向另一個節點傳播第三者節點的資訊, 那麼接收資訊的那個節點也會将第三者節點識别為叢集中的一份子。也即是說, 如果 a 認識 b , b 認識 c , 并且 b 向 a 傳播關于 c 的資訊, 那麼 a 也會将 c 識别為叢集中的一份子, 并嘗試連接配接 c 。

這意味着如果我們将一個/一些新節點添加到一個叢集中, 那麼這個/這些新節點最終會和叢集中已有的其他所有節點連接配接起來。

這說明隻要管理者使用 cluster meet 指令顯式地指定了可信關系,叢集就可以自動發現其他節點。這種節點識别機制通過防止不同的 redis 叢集因為 ip 位址變更或者其他網絡事件的發生而産生意料之外的聯合(mix), 進而使得叢集更具健壯性。當節點的網絡連接配接斷開時,它會主動連接配接其他已知的節點。

moved 轉向:

一個 redis 用戶端可以向叢集中的任意節點(包括從節點)發送指令請求。節點會對指令請求進行分析, 如果該指令是叢集可以執行的指令, 那麼節點會查找這個指令所要處理的鍵所在的槽。如果要查找的哈希槽正好就由接收到指令的節點負責處理,那麼節點就直接執行這個指令。另一方面, 如果所查找的槽不是由該節點處理的話, 節點将檢視自身内部所儲存的哈希槽到節點 id 的映射記錄,并向用戶端回複一個 moved 錯誤。

即使用戶端在重新發送 get 指令之前, 等待了非常久的時間,以至于叢集又再次更改了配置, 使得節點 127.0.0.1:6381 已經不再處理槽 3999 , 那麼當用戶端向節點 127.0.0.1:6381 發送 get 指令的時候, 節點将再次向用戶端傳回 moved 錯誤, 訓示現在負責處理槽 3999 的節點。

雖然我們用 id 來辨別叢集中的節點, 但是為了讓用戶端的轉向操作盡可能地簡單,,節點在 moved 錯誤中直接傳回目标節點的 ip 和端口号,而不是目标節點的 id 。但一個用戶端應該記錄(memorize)下“槽 3999 由節點 127.0.0.1:6381 負責處理“這一資訊, 這樣當再次有指令需要對槽 3999 執行時, 用戶端就可以加快尋找正确節點的速度。

注意, 當叢集處于穩定狀态時, 所有用戶端最終都會儲存有一個哈希槽至節點的映射記錄(map of hash slots to nodes), 使得叢集非常高效: 用戶端可以直接向正确的節點發送指令請求, 無須轉向、代理或者其他任何可能發生單點故障(single point failure)的實體(entiy)。

除了 moved轉向錯誤之外, 一個用戶端還應該可以處理稍後介紹的 ask 轉向錯誤。

叢集線上重配置:

redis 叢集支援在叢集運作的過程中添加或者移除節點。實際上, 節點的添加操作和節點的删除操作可以抽象成同一個操作,那就是, 将哈希槽從一個節點移動到另一個節點:添加一個新節點到叢集, 等于将其他已存在節點的槽移動到一個空白的新節點裡面。從叢集中移除一個節點, 等于将被移除節點的所有槽移動到叢集的其他節點上面去。

是以, 實作redis 叢集線上重配置的核心就是将槽從一個節點移動到另一個節點的能力。 因為一個哈希槽實際上就是一些鍵的集合, 是以 redis 叢集在重哈希(rehash)時真正要做的, 就是将一些鍵從一個節點移動到另一個節點。

要了解redis 叢集如何将槽從一個節點移動到另一個節點, 我們需要對 cluster 指令的各個子指令進行介紹,這些命理負責管理叢集節點的槽轉換表(slots translation table)。

以下是cluster 指令可用的子指令:

分布式緩存Redis使用心得

最開頭的兩條指令addslots 和 delslots 分别用于向節點指派(assign)或者移除節點,當槽被指派或者移除之後, 節點會将這一資訊通過 gossip 協定傳播到整個叢集。 addslots 指令通常在新建立叢集時, 作為一種快速地将各個槽指派給各個節點的手段來使用。

clustersetslot slot node node 子指令可以将指定的槽 slot 指派給節點node 。

至于cluster setslot slot migrating node 指令和 cluster setslotslot importing node 指令, 前者用于将給定節點 node 中的槽 slot 遷移出節點, 而後者用于将給定槽 slot導入到節點 node :

當一個槽被設定為migrating 狀态時, 原來持有這個槽的節點仍然會繼續接受關于這個槽的指令請求, 但隻有指令所處理的鍵仍然存在于節點時, 節點才會處理這個指令請求。

如果指令所使用的鍵不存在與該節點, 那麼節點将向用戶端傳回一個 -ask 轉向(redirection)錯誤, 告知用戶端, 要将指令請求發送到槽的遷移目标節點。

當一個槽被設定為importing 狀态時, 節點僅在接收到 asking 指令之後, 才會接受關于這個槽的指令請求。

如果用戶端沒有向節點發送 asking 指令, 那麼節點會使用 -moved 轉向錯誤将指令請求轉向至真正負責處理這個槽的節點。

上面關于migrating 和 importing 的說明有些難懂, 讓我們用一個實際的執行個體來說明一下。

假設現在, 我們有 a 和 b 兩個節點, 并且我們想将槽8 從節點 a 移動到節點 b , 于是我們:

向節點 b 發送指令 cluster setslot 8 importing a

向節點 a 發送指令 cluster setslot 8 migrating b

每當用戶端向其他節點發送關于哈希槽 8 的指令請求時, 這些節點都會向用戶端傳回指向節點 a 的轉向資訊:

如果指令要處理的鍵已經存在于槽 8 裡面, 那麼這個指令将由節點 a 處理。

如果指令要處理的鍵未存在于槽 8 裡面(比如說,要向槽添加一個新的鍵), 那麼這個指令由節點 b 處理。

這種機制将使得節點 a 不再建立關于槽 8 的任何新鍵。

與此同時, 一個特殊的用戶端 redis-trib 以及 redis 叢集配置程式(configuration utility)會将節點 a 中槽 8 裡面的鍵移動到節點 b 。

鍵的移動操作由以下兩個指令執行:

clustergetkeysinslot slot count

上面的指令會讓節點傳回 count 個 slot 槽中的鍵, 對于指令所傳回的每個鍵, redis-trib 都會向節點 a 發送一條 migrate 指令, 該指令會将所指定的鍵原子地(atomic)從節點 a 移動到節點 b (在移動鍵期間,兩個節點都會處于阻塞狀态,以免出現競争條件)。

以下為migrate 指令的運作原理:

migratetarget_host target_port key target_database id timeout

執行migrate 指令的節點會連接配接到 target 節點, 并将序列化後的 key 資料發送給 target , 一旦 target 傳回 ok , 節點就将自己的 key 從資料庫中删除。

從一個外部用戶端的視角來看, 在某個時間點上, 鍵 key 要麼存在于節點 a , 要麼存在于節點 b , 但不會同時存在于節點 a 和節點 b 。

因為 redis叢集隻使用 0 号資料庫, 是以當 migrate 指令被用于執行叢集操作時, target_database 的值總是 0 。

target_database參數的存在是為了讓 migrate 指令成為一個通用指令, 進而可以作用于叢集以外的其他功能。

我們對migrate 指令做了優化, 使得它即使在傳輸包含多個元素的清單鍵這樣的複雜資料時, 也可以保持高效。

不過, 盡管migrate 非常高效, 對一個鍵非常多、并且鍵的資料量非常大的叢集來說, 叢集重配置還是會占用大量的時間, 可能會導緻叢集沒辦法适應那些對于響應時間有嚴格要求的應用程式。

ask 轉向:

在之前介紹 moved 轉向的時候, 我們說除了 moved 轉向之外, 還有另一種 ask 轉向。當節點需要讓一個用戶端長期地(permanently)将針對某個槽的指令請求發送至另一個節點時,節點向用戶端傳回 moved 轉向。另一方面, 當節點需要讓用戶端僅僅在下一個指令請求中轉向至另一個節點時, 節點向用戶端傳回 ask 轉向。

比如說, 在我們上一節列舉的槽 8 的例子中, 因為槽 8 所包含的各個鍵分散在節點 a 和節點 b 中, 是以當用戶端在節點 a 中沒找到某個鍵時, 它應該轉向到節點 b 中去尋找, 但是這種轉向應該僅僅影響一次指令查詢,而不是讓用戶端每次都直接去查找節點 b : 在節點 a 所持有的屬于槽 8 的鍵沒有全部被遷移到節點 b 之前, 用戶端應該先通路節點 a , 然後再通路節點 b 。因為這種轉向隻針對 16384 個槽中的其中一個槽, 是以轉向對叢集造成的性能損耗屬于可接受的範圍。

因為上述原因, 如果我們要在查找節點 a 之後, 繼續查找節點 b , 那麼用戶端在向節點 b 發送指令請求之前, 應該先發送一個 asking 指令, 否則這個針對帶有importing 狀态的槽的指令請求将被節點 b 拒絕執行。接收到用戶端 asking 指令的節點将為用戶端設定一個一次性的标志(flag), 使得用戶端可以執行一次針對 importing 狀态的槽的指令請求。從用戶端的角度來看, ask 轉向的完整語義(semantics)如下:

1. 如果用戶端接收到 ask 轉向, 那麼将指令請求的發送對象調整為轉向所指定的節點。

2. 先發送一個 asking 指令,然後再發送真正的指令請求。

3. 不必更新用戶端所記錄的槽 8 至節點的映射: 槽 8 應該仍然映射到節點 a , 而不是節點 b 。

一旦節點 a 針對槽 8 的遷移工作完成, 節點 a 在再次收到針對槽 8 的指令請求時, 就會向用戶端傳回 moved 轉向, 将關于槽 8 的指令請求長期地轉向到節點 b 。

注意, 即使用戶端出現 bug , 過早地将槽 8 映射到了節點 b 上面, 但隻要這個用戶端不發送 asking 指令, 用戶端發送指令請求的時候就會遇上 moved 錯誤, 并将它轉向回節點 a 。

容錯:

節點失效檢測,以下是節點失效檢查的實作方法:

1. 當一個節點向另一個節點發送 ping 指令, 但是目标節點未能在給定的時限内傳回 ping 指令的回複時, 那麼發送指令的節點會将目标節點标記為 pfail(possible failure,可能已失效)。等待 ping 指令回複的時限稱為“節點逾時時限(node timeout)”, 是一個節點選項(node-wise setting)。

2. 每次當節點對其他節點發送 ping 指令的時候,它都會随機地廣播三個它所知道的節點的資訊, 這些資訊裡面的其中一項就是說明節點是否已經被标記為 pfail或者 fail 。

當節點接收到其他節點發來的資訊時, 它會記下那些被其他節點标記為失效的節點。這稱為失效報告(failure report)。

3. 如果節點已經将某個節點标記為 pfail , 并且根據節點所收到的失效報告顯式,叢集中的大部分其他主節點也認為那個節點進入了失效狀态, 那麼節點會将那個失效節點的狀态标記為 fail 。

4. 一旦某個節點被标記為 fail , 關于這個節點已失效的資訊就會被廣播到整個叢集,所有接收到這條資訊的節點都會将失效節點标記為 fail 。

簡單來說, 一個節點要将另一個節點标記為失效, 必須先詢問其他節點的意見, 并且得到大部分主節點的同意才行。因為過期的失效報告會被移除,是以主節點要将某個節點标記為 fail 的話, 必須以最近接收到的失效報告作為根據。

從節點選舉:一旦某個主節點進入 fail 狀态, 如果這個主節點有一個或多個從節點存在,那麼其中一個從節點會被更新為新的主節點, 而其他從節點則會開始對這個新的主節點進行複制。

新的主節點由已下線主節點屬下的所有從節點中自行選舉産生,以下是選舉的條件:

1. 這個節點是已下線主節點的從節點。

2. 已下線主節點負責處理的槽數量非空。

3. 從節點的資料被認為是可靠的, 也即是, 主從節點之間的複制連接配接(replication link)的斷線時長不能超過節點逾時時限(nodetimeout)乘以redis_cluster_slave_validity_mult 常量得出的積。

如果一個從節點滿足了以上的所有條件, 那麼這個從節點将向叢集中的其他主節點發送授權請求, 詢問它們,是否允許自己(從節點)更新為新的主節點。

如果發送授權請求的從節點滿足以下屬性, 那麼主節點将向從節點返failover_auth_granted 授權, 同意從節點的更新要求:

1. 發送授權請求的是一個從節點, 并且它所屬的主節點處于 fail狀态。

2. 在已下線主節點的所有從節點中, 這個從節點的節點 id 在排序中是最小的。

3. 這個從節點處于正常的運作狀态: 它沒有被标記為 fail 狀态,也沒有被标記為 pfail 狀态。

一旦某個從節點在給定的時限内得到大部分主節點的授權,它就會開始執行以下故障轉移操作:

1. 通過 pong 資料包(packet)告知其他節點, 這個節點現在是主節點了。

2. 通過 pong 資料包告知其他節點, 這個節點是一個已更新的從節點(promoted slave)。

3. 接管(claiming)所有由已下線主節點負責處理的哈希槽。

4. 顯式地向所有節點廣播一個 pong 資料包, 加速其他節點識别這個節點的進度,而不是等待定時的 ping / pong 資料包。

所有其他節點都會根據新的主節點對配置進行相應的更新:

所有被新的主節點接管的槽會被更新。

已下線主節點的所有從節點會察覺到 promoted 标志,并開始對新的主節點進行複制。

如果已下線的主節點重新回到上線狀态, 那麼它會察覺到promoted 标志, 并将自身調整為現任主節點的從節點。

在叢集的生命周期中, 如果一個帶有 promoted 辨別的主節點因為某些原因轉變成了從節點,那麼該節點将丢失它所帶有的 promoted 辨別。

作者介紹:張小博

新炬網絡中間件運維工程師

擁有多年的電信行業的運維經驗,為客戶建構高可用、高性能、分布式的系統架構設計提供技術支援。

<b></b>

<b>本文來自雲栖社群合作夥伴"dbaplus",原文釋出時間:2016-02-03</b>