天天看點

深度幹貨 | OceanBase 主動切主技術解讀

深度幹貨 | OceanBase 主動切主技術解讀

OceanBase(以下以 OB 簡稱)中有一個總控節點服務稱之為 RootService,用于管理整個叢集中的負載均衡等操作。該服務啟動在

__all_core_table

的主副本(Leader)所在的伺服器上。本文主要介紹 RootService(以下以 RS 簡稱)對切主的管理。主要分為以下五個部分:

  • 涉及到的基礎概念
  • 負載均衡場景描述
  • 對主動切主的管理
  • 切主是如何觸發的
  • 切主是如何執行的

我們先來認識或回顧下 5 個本文會涉及到的基本概念:

1.1. 主副本(Leader)

OB 通過 Multi-Paxos 選舉協定來保證叢集内資料的高可用。選舉以分區為機關,每個分區的多個資料副本形成一個獨立的 Paxos 組,其中隻有一個分區副本會被選舉為主副本(Leader,可讀可寫),其餘通常情況下是從副本(Follower)。

切主,指的是資料分區副本角色在主副本和從副本間的切換,即 OB 對各個分區的主副本位置的調整。

1.2. 均衡組

租戶内的切主是以均衡組為次元進行的,而不是簡單的将該租戶下的所有分區的leader打散。

目前,均衡組有以下 3 種存在形态:

  • PARTITION_TABLE_BALANCE_GROUP

針對不在表組(TableGroup)中的多分區表,每個分區表自己是一個均衡組。

  • TABLE_GROUP_BALANCE_GROUP

針對在表組(TableGroup)中的多分區表,每個表組是一個均衡組。

  • NON_PARTITION_TABLE_BALANCE_GROUP

如果是隻有一個分區的分區表、單分區表或非分區表,會統一歸入一個均衡組。

1.3. 租戶(Tenant)

OB 實作了租戶級别的資源隔離,每個資料庫租戶執行個體不會感覺其他執行個體的存在,并通過綜合的權限控制確定租戶資料的安全性。

1.4. 首選區(Primary Zone)

如果你還不太了解 OB 關于區(Zone)的概念,請查閱 OB 官方手冊。

首選區可用以指定分區主副本在選擇 Zone 時的優先級順序。OB 可在租戶級别指定資料副本 Leader 在 Zone 間的分布政策。此外,向下遞進,OB 允許在 Scheme 級别(MySQL 中術語是 Database 級别)、TableGroup級别、直至表級别上配置首選區。建立租戶時,屬性

primary_zone

預設為

RANDOM

;其它級别該屬性預設為依次向上繼承,直到發現非空屬性:表 ➡︎(TableGroup 或 Schema)➡︎ 租戶。如果對該屬性有顯式制定,以顯式指定為準。

以下例來具體解讀 Zone 的優先政策:

primary_zone = zone1,zone2;zone3,zone4;zone5      

注意标點符号的文法含義:逗号代表兩邊優先級相同;分号代表前者優先級更高、後者次之。

這個例子中,五個 Zone 優先級從高到低被分号劃分為三個級别:前兩個

zone1

zone2

(以逗号隔開)的優先級相同且優先級最高,

zone3

zone4

(以逗号隔開)的優先級并列,最後面的

zone5

的優先級最低。

1.5. 首選域(Primary Region)

OB 預設将 Primary Zone 所在的地區(Region,例如北京或上海)指定為 Primary Region。每個 Primary Region 至少要有兩個 Zone,這是出于可用和性能考慮 OB 做出的硬性限制,這有助于避免跨 Region 切主導緻的性能劣化。

舉例,若三個 Zone 分别屬于不同的地區(如杭州、上海和深圳),那麼,

不可取的設定是隻将一個 Zone 設定成 Primary Region:

  • zone1; zone2; zone3

  • zone1; zone2, zone3

可行的設定為:

  • random

    (預設設定)
  • zone1,zone2,zone3

    (效果和

    random

    相同)
  • zone1,zone2;zone3

負載分攤場景描述

我們通過代入一個具體場景來簡單介紹資料副本 Leader 的負載分攤。

在同一 Region,建立一個擁有 3 個 Zone 的叢集,每個 Zone 中都包含 3 台伺服器(OBServer)。

建立一個資料庫租戶,該租戶的資料根據資源配置允許分布在全部 9 台伺服器上。

假設建立租戶時 Primary Zone 沒有指定,則其預設采用 RANDOM 政策。

随後,使用者在該租戶下建立了一張擁有 9 個分區的分區表,未指定 Primary Zone。

此時分區表的 primary_zone 屬性繼承租戶的 RANDOM 預設配置。

RS 會将表的 9 個分區的 Leader 均勻打散到 3 個 Zone 的 9 台伺服器上。

分區的 Leader 分布如下:

深度幹貨 | OceanBase 主動切主技術解讀
深度幹貨 | OceanBase 主動切主技術解讀

當然,如果業務需要,使用者也可選擇将 Leader 都集中布在某個 Zone 上。比如,我們選擇把這張表所有分區 Leader 都布在 Zone1,具體做法:在建立表時直接指定

primary_zone='zone1'

;或,在已存在的租戶上調整

primary_zone

配置。

新的分區 Leader 分布情況如下:

深度幹貨 | OceanBase 主動切主技術解讀
深度幹貨 | OceanBase 主動切主技術解讀

RS 是根據目前叢集的狀态來主動決定各個租戶的 Leader 分布。其中叢集的狀态包括但不限于 Zone 狀态、伺服器狀态、是否發生遷移、租戶是否發生 Locality 變更、管理者主動發起切主等。OB 中不同租戶互相間資源隔離、互相不影響,同樣切主行為也是各個租戶互相獨立的,是以 RS 對切主的管理是以租戶為次元進行的。

OB 中強讀和寫都是在 Leader上進行的。若分區 Leader 沒有打散而是聚集在個别幾台伺服器上,大量的 IO 會導緻這些伺服器的性能很快達到瓶頸。有時使用者希望利用所有的伺服器來避免達到瓶頸,将

primary_zone

設定成

RANDOM

,語義就是将 Leader 均勻地打散到該租戶下所有可用

Zone

的所有可用伺服器上。當然,有時使用者就是希望所有的 Leader 都集中在一兩個 Zone 上,以避免發生跨城市切主,造成通路延遲,對業務産生不良影響。是以,RS 對切主的管理,首要還是根據使用者的需要,結合目前叢集的狀态,來調整各個租戶下所有分區的 Leader 分布。

OB 中有一套完整的無主選舉的邏輯,當網絡不穩定、伺服器當機等非預期的情況導緻的各種無主場景,會由選舉(Election)子產品進行無主選舉。本文并不讨論無主選舉的場景,隻讨論預期内的切主,即所有的切主情況都是在叢集正常情況下。

RS 管理切主有一個重要的配置項,叫做

enable_auto_leader_switch

,該配置項決定是否運作 RS 的背景切主線程。

Alter system set enable_auto_leader_switch = true/false;      

下面的操作 4.1 和 4.2 都不依賴這個開關,即使開關關閉,操作都是可以正常進行的,但其餘的操作都依賴這個開關,當開關關閉時,都不能正常執行切主操作。

4.1. 手動切主

管理者可手動觸發對某個分區的切主,指定其 Leader 或 Follower 的位置。

參考指令:

alter system switch replica leader/follower partition = '$partition_id' server = '$server_ip:$server_port';
alter system switch replica leader/follower zone = '$zone_name' tenant = '$tenant_name';
alter system switch replica leader/follower server = '$server_ip:$server_port' tenant = '$tenant_name';      

💡注意:該操作不依賴配置項

enable_auto_leader_switch

4.2. 容災操作

容災操作包括 locality 變更、資源(resource unit)遷移、緊急停機(stop server/zone)及伺服器隔離(isolate/fence)。其中對于 locality 變更和資源遷移,當操作的資料副本是 Leader 時,會先行切主,繼而進行相關的操作,當變更和遷移完成後再根據目前環境來決定是否需要将主切回。緊急停機及伺服器隔離都會先行切主,該指令是阻塞的,即需要等待全部 Leader 都切走後,才能完成相關操作。

注意:上述操作也不依賴配置項

enable_auto_leader_switch

4.3. 修改 Primary Zone

在對象建立時或建立好後,

primary_zone

屬性都是可以動态調整的。

參考指令:

alter tenant/database/tablegroup/table $name primary_zone = '$new_pz_strategy';      

4.4. 自動均衡

以均衡組為次元對租戶進行自動均衡,OB 中均衡的含義是不同 Zone、不同伺服器之間的 Leader 數相差不超過 1。由于均衡是以均衡組為次元,是以具體到一個租戶下的 Leader 分布可能不是完全均衡的。

舉例說明,叢集有 3 個 Zone,每個 Zone 隻有一台伺服器。某租戶現有 3 張分區表,每張表擁有 10 個分區。每個表自己是一個均衡組,那麼每個表的 10 個分區副本 Leader 均衡分布為4:3:3。如果每個均衡組将 4 個 Leader 的 Zone 都指定為Zone1,那麼雖然每個均衡組自己内部是均衡的,但租戶層面上 Leader 的分布是不均衡的,因為該租戶分區副本 Leader 的分布為 12:9:9。

當然内部進行了一些優化,在建立表的時候,會指定好每個表的 Leader 分布。對于非分區表均衡組的指定是根據目前的非分區表分布,來決定新表的 Leader 分布。而對于分區表,在建立時是根據表的 ID 編号,計算出其 Leader 的分布,如果是連續的表,那麼其 Leader 位置是錯開的,比如 1 号表的起始 Leader 在 Zone1 上,那麼 2 号表的起始 Leader 是在 Zone2 上,依次類推。進而盡量避免在整體上出現 Leader 分布不均衡的問題。

4.5. 輪轉合并

當打開輪狀合并開關時,對于合并目标 Zone,會首先将該 Zone 上的 Leader 都切走,然後才開始對該 Zone 的合并。

5.1. Leader 的配置設定原則

首先介紹一下 RS 的切主原則。

叢集中可能出現的一種場景是雖然設定了 Primary Zone,但目前的 Leader 分布卻與設定不符,這是由于 RS 決定 Leader 分布不僅僅隻參考 Primary Zone 資訊。

RS 會擷取每個分區的每個副本的相關資訊,綜合分析後決定 Leader 職責到底配置設定在哪個資料副本上。

下面是幾個比較關鍵的參考資訊:

  • 伺服器或 Zone 的可用狀态
  • Primary Region 的設定
  • 合并狀态
  • 候選數量(candidate_cnt)
  • 拉黑清單(In_blacklist)
  • Primary Zone 的設定

這些副本的資訊從上到下優先級逐漸降低。

1、最先看這個副本所在的伺服器或 Zone 是否可用,若處于停止狀态,則不能将 Leader 切到該副本上;

2、Primary Region 就是 Primary Zone 所在的地區,RS 會優先将 Leader 切到 Primary Region 中;

3、檢視副本是否處于合并狀态,RS 不傾向于将副本的 Leader 切到處于合并狀态的 Zone 上;

4、候選數量(candidate_cnt)是由 clog 層傳回給 RS 分區候選 Leader 的伺服器清單,RS 根據清單計算出每個伺服器能夠作為候選分區的數量,數量越大,則該伺服器上的副本越有可能成為 Leader;

5、拉黑清單(in_blacklist)代表該伺服器是否在黑名單中,當該分區發生無故卸任時,clog 會将原來 Leader 所在的伺服器放入到黑名單中,RS 會根據這份黑名單拉黑對應伺服器的 Leader 候選資格;

6、最後才是 Primary Zone。需要通過前面的 5 項判斷,RS 才會聽取 Primary Zone 的建議。

這裡沒有完整羅列 RS 的全部檢查,但已經很清楚,有各種各樣的因素會導緻 RS 沒有按照 Primary Zone 去配置設定 Leader。

5.2. Leader 的切換流程

在啟動 RS 服務時,會建立一個切主管理的線程。當自動切主開關打開時,該線程會一直在背景輪詢周遊所有的租戶,每個租戶的切主流程是一緻的,下面以一個租戶為例,介紹一下租戶的切主流程。

首先通過周遊内部表的方式,擷取這個租戶下所有的分區資訊,包括比較優先級時需要的各種副本資訊。RS 是基于一個時間點擷取的租戶下所有分區資訊,由于叢集可能是在變化的,是以擷取的資訊可能會過期失效,根據過期的資訊得到的切主方案可能也是不準确的。幸運的是 RS 也考慮到這一點,切主管理線程在背景不斷輪詢、更新資訊,即使有變化,但當叢集最終達到穩态時,也可保證 Leader 分布是符合預期的。

随後根據擷取到的資訊,按照均衡組,比較分區各個副本的優先級,決定每個均衡組中的分區是否需要進行切主。如果通過比較沒有找到需要切主的分區,那麼後續的所有操作都跳過,直接周遊下一個租戶。否則,根據 RS 生成的切主資訊,向底層發送 RPC 消息,來擷取和确認目前真實準确的副本資訊,進而進一步判斷是否真的需要進行切主:如果不需要切,那麼直接結束;否則,就根據需要進行切主的資訊,給目前的 Leader 發送切主指令 —— 指令其卸任。

最後等待所有的分區切主完成,等待的方法就是檢查内部表,檢查待切主分區的 Leader 是否在預期的位置,如果與預期相符,則認為該分區切主成功。否則,繼續等待。限定每個租戶最長隻會等待 64 秒,若超過這個時間還沒有檢查到對應分區的 Leader 在預期的伺服器上,就會強行結束該租戶的等待,進行下一個租戶的周遊。失敗的租戶,等待下一輪周遊到該租戶時再重複進行同樣的切主操作。

寫在最後

感興趣的同學可點選閱讀原文檢視OB 開源源碼中的 ob_leader_coordinator.cpp 檔案,該檔案包含全部 RS 管理切主的流程。RS 對切主的管理,流程相對清晰,但是涉及概念比較多,本文簡單對 RS 的切主管理進行了梳理,希望能對大家有所幫助。