首頁>技術>

原文連結:https://mp.weixin.qq.com/s/ui-0sPZlrUF-O6XkepU6kw

在實際的專案中,服務高可用非常重要,如,當Redis作為快取服務使用時, 緩解資料庫的壓力,提高資料的訪問速度,提高網站的效能 ,但如果使用Redis 是單機模式執行 ,只要一個伺服器宕機就不可以提供服務,這樣會可能造成服務效率低下,甚至出現其相對應的服務應用不可用。

因此為了實現高可用,Redis 提供了哪些高可用方案?

Redis主從複製Redis持久化哨兵叢集...

Redis基於一個Master主節點多Slave從節點的模式和Redis持久化機制,將一份資料保持在多個例項中實現增加副本冗餘量,又使用哨兵機制實現主備切換, 在master故障時,自動檢測,將某個slave切換為master,最終實現Redis高可用 。

Redis主從複製

Redis主從複製,主從庫模式一個Master主節點多Slave從節點的模式,將一份資料儲存在多Slave個例項中,增加副本冗餘量,當某些出現宕機後,Redis服務還可以使用。

但是這會存在資料不一致問題,那redis的副本集是如何資料一致性?

Redis為了保證資料副本的一致,主從庫之間採用讀寫分離的方式:

讀操作:主庫、從庫都可以執行處理;寫操作:先在主庫執行,再由主庫將寫操作同步給從庫。

使用讀寫分離方式的好處,可以避免當主從庫都可以處理寫操作時,主從庫處理寫操作加鎖等一系列鉅額的開銷。

採用讀寫分離方式,寫操作只會在主庫中進行後同步到從庫中,那主從庫是如何同步資料的呢?

主從庫是同步資料方式有兩種:

全量同步:通常是主從伺服器剛剛連線的時候,會先進行全量同步增量同步 :一般在全同步結束後,進行增量同步,比如主從庫間網路斷開後,再進行資料同步。全量同步

主從庫間第一次全量同步,具體分成三個階段:

當一個從庫啟動時,從庫給主庫傳送 psync 命令進行資料同步(psync 命令包含:主庫的 runID 和複製進度 offset 兩個引數),當主庫接收到psync 命令後將會儲存RDB 檔案併發送給從庫,傳送期間會使用快取區(replication buffer)記錄後續的所有寫操作 ,從庫收到資料後,會先清空當前資料庫,然後載入從主庫獲取的RDB 檔案,當主庫完成 RDB 檔案傳送後,也會把將儲存傳送RDB檔案期間寫操作的replication buffer發給從庫,從庫再重新執行這些操作。這樣一來,主從庫就實現同步了。

另外,為了分擔主庫生成 RDB 檔案和傳輸 RDB 檔案壓力,提高效率,可以使用 “主 - 從 - 從”模式將主庫生成 RDB 和傳輸 RDB 的壓力,以級聯的方式分散到從庫上。

增量同步

增量同步,基於環形緩衝區repl_backlog_buffer快取區實現。

在環形緩衝區,主庫會記錄自己寫到的位置 master_repl_offset ,從庫則會記錄自己已經讀到的位置slave_repl_offset, 主庫並透過master_repl_offset 和 slave_repl_offset的差值的資料同步到從庫。

主從庫間網路斷了, 主從庫會採用增量複製的方式繼續同步,主庫會把斷連期間收到的寫操作命令,寫入 replication buffer,同時也會把這些操作命令也寫入 repl_backlog_buffer 這個緩衝區,然後主庫並透過master_repl_offset 和 slave_repl_offset的差值資料同步到從庫。

因為repl_backlog_buffer 是一個環形緩衝區,當在緩衝區寫滿後,主庫會繼續寫入,此時,會出現什麼情況呢?

覆蓋掉之前寫入的操作。如果從庫的讀取速度比較慢,就有可能導致從庫還未讀取的操作被主庫新寫的操作覆蓋了,這會導致主從庫間的資料不一致。因此需要關注 repl_backlog_size引數,調整合適的緩衝空間大小,避免資料覆蓋,主從資料不一致。

主從複製,除了會出現資料不一致外,甚至可能出現主庫宕機的情況,Redis會有主從自主切換機制,那如何實現的呢?

Redis哨兵機制

當主庫掛了,redis寫操作和資料同步無法進行,為了避免這樣情況,可以在主庫掛了後重新在從庫中選舉出一個新主庫,並通知到客戶端,redis提供了 哨兵機制,哨兵為執行在特殊模式下的 Redis 程序。

Redis會有主從自主切換機制,那如何實現的呢?

哨兵機制是實現主從庫自動切換的關鍵機制,其主要分為三個階段:

監控:哨兵程序會週期性地給所有的主從庫傳送 PING 命令,檢測它們是否仍然線上執行。選主(選擇主庫):主庫掛了以後,哨兵基於一定規則評分選選舉出一個從庫例項新的主庫 。通知 :哨兵會將新主庫的資訊傳送給其他從庫,讓它們和新主庫建立連線,並進行資料複製。同時,哨兵會把新主庫的資訊廣播通知給客戶端,讓它們把請求操作發到新主庫上。

其中,在監控中如何判斷主庫是否處於下線狀態?

哨兵對主庫的下線判斷分為:

主觀下線:哨兵程序會使用 PING 命令檢測它自己和主、從庫的網路連線情況,用來判斷例項的狀態, 如果單哨兵發現主庫或從庫對 PING 命令的響應超時了,那麼,哨兵就會先把它標記為“主觀下線”客觀下線:在哨兵叢集中,基於少數服從多數,多數例項都判定主庫已“主觀下線”,則認為主庫“客觀下線”。

為什麼會有這兩種"主觀下線"和“客觀下線”的下線狀態呢?

由於單機哨兵很容易產生誤判,誤判後主從切換會產生一系列的額外開銷,為了減少誤判,避免這些不必要的開銷,採用哨兵叢集,引入多個哨兵例項一起來判斷,就可以避免單個哨兵因為自身網路狀況不好,而誤判主庫下線的情況,

基於少數服從多數原則, 當有 N 個哨兵例項時,最好要有 N/2 + 1 個例項判斷主庫為“主觀下線”,才能最終判定主庫為“客觀下線” (可以自定義設定閾值)。

那麼哨兵之間是如何互相通訊的呢?

哨兵叢集中哨兵例項之間可以相互發現,基於 Redis 提供的釋出 / 訂閱機制(pub/sub 機制),

哨兵可以在主庫中釋出/訂閱訊息,在主庫上有一個名為“\__sentinel__:hello”的頻道,不同哨兵就是透過它來相互發現,實現互相通訊的,而且只有訂閱了同一個頻道的應用,才能透過釋出的訊息進行資訊交換。

哨兵 1連線相關資訊(IP埠)釋出到“\__sentinel__:hello”頻道上,哨兵 2 和 3 訂閱了該頻道。

哨兵 2 和 3 就可以從這個頻道直接獲取哨兵 1連線資訊,以這樣的方式哨兵叢集就形成了,實現各個哨兵互相通訊。

哨兵叢集中各個實現通訊後,就可以判定主庫是否已客觀下線。

在已判定主庫已下線後,又如何選舉出新的主庫?

新主庫選舉按照一定條件篩選出的符合條件的從庫,並按照一定規則對其進行打分,最高分者為新主庫。

通常一定條件包括:

從庫的當前線上狀態,判斷它之前的網路連線狀態,透過down-after-milliseconds * num(斷開連線次數),當斷開連線次數超過閾值,不適合為新主庫。

一定規則包括

從庫優先順序 , 透過slave-priority 配置項,給不同的從庫設定不同優先順序,優先順序最高的從庫得分高從庫複製進度,和舊主庫同步程度最接近的從庫得分高,透過repl_backlog_buffer緩衝區記錄主庫 master_repl_offset 和從庫slave_repl_offset 相差最小高分從庫 ID 號 , ID 號小的從庫得分高。

全都都基於在只有在一定規則中的某一輪評出最高分從庫就選舉結束,哨兵發起主從切換

leader哨兵

選舉完新的主庫後,不能每個哨兵都發起主從切換,需要選舉成leader哨兵,那如何選舉leader哨兵執行主從切換?

選舉leader哨兵,也是基於少數服從多數原則"投票仲裁"選舉出來,

當任何一個從庫判定主庫“主觀下線”後,傳送命令 s-master-down-by-addr命令傳送想要成為Leader的訊號,其他哨兵根據與主機連線情況作出相對的響應,贊成票Y,反對票N,而且如果有多個哨兵發起請求,每個哨兵的贊成票只能投給其中一個,其他只能為反對票。

想要成為Leader 的哨兵,要滿足兩個條件:

第一,獲得半數以上的贊成票;第二,獲得的票數同時還需要大於等於哨兵配置檔案中的quorum值。

選舉完leader哨兵並新主庫切換完畢之後,那麼leader哨兵怎麼通知客戶端?

還是基於哨兵自身的 pub/sub 功能,實現了客戶端和哨兵之間的事件通知,客戶端訂閱哨兵自身訊息頻道 ,而且哨兵提供的訊息訂閱頻道有很多,不同頻道包含了:

其中,當客戶端從哨兵訂閱訊息主從庫切換,當主庫切換後,客戶端就會接收到新主庫的連線資訊:

switch-master <master name> <oldip> <oldport> <newip> <newport>  

在這樣的方式哨兵就可以通知客戶端切換了新庫。

基於上述的機制和原理Redis實現了高可用,但也會帶了一些潛在的風險,比如資料缺失。

資料問題

Redis實現高可用,但實現期間可能產出一些風險:

主備切換的過程, 非同步複製導致的資料丟失腦裂導致的資料丟失主備切換的過程,非同步複製導致資料不一致資料丟失-主從非同步複製

因為master 將資料複製給slave是非同步實現的,在複製過程中,這可能存在master有部分資料還沒複製到slave,master就宕機了,此時這些部分資料就丟失了。

總結:主庫的資料還沒有同步到從庫,結果主庫發生了故障,未同步的資料就丟失了。

資料丟失-腦裂

何為腦裂?當一個叢集中的 master 恰好網路故障,導致與 sentinal 通訊不上了,sentinal會認為master下線,且sentinal選舉出一個slave 作為新的 master,此時就存在兩個 master了。

此時,可能存在client還沒來得及切換到新的master,還繼續寫向舊master的資料,當master再次恢復的時候,會被作為一個slave掛到新的master 上去,自己的資料將會清空,重新從新的master 複製資料,這樣就會導致資料缺失。

總結:主庫的資料還沒有同步到從庫,結果主庫發生了故障,等從庫升級為主庫後,未同步的資料就丟失了。

資料丟失解決方案

資料丟失可以透過合理地配置引數 min-slaves-to-write 和 min-slaves-max-lag 解決,比如

min-slaves-to-write 1min-slaves-max-lag 10

如上兩個配置:要求至少有 1 個 slave,資料複製和同步的延遲不能超過 10 秒,如果超過 1 個 slave,資料複製和同步的延遲都超過了 10 秒鐘,那麼這個時候,master 就不會再接受任何請求了。

資料不一致

在主從非同步複製過程,當從庫因為網路延遲或執行復雜度高命令阻塞導致滯後執行同步命令,這樣就會導致資料不一致

解決方案:可以開發一個外部程式來監控主從庫間的複製進度(master_repl_offset 和 slave_repl_offset ),透過監控 master_repl_offset 與slave_repl_offset差值得知複製進度,當複製進度不符合預期設定的Client不再從該從庫讀取資料。

總結

Redis使用主從複製、持久化、哨兵機制等實現高可用,需要理解其實現過程,也要明白其帶了風險以及解決方案,才能在實際專案更好最佳化,提升系統的可靠性、穩定性。

12
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 「python」字典型別及操作