OceanBase是一個通用的分布式的關系型數據庫,有很多獨特的特點。比如數據庫的多租戶、高可用、極緻彈性伸縮能力。如果把OceanBase當作單庫使用,就沒有把OceanBase的分布式優勢發揮到極緻。
本文主要分享一個基于分布式架構的應用把OceanBase數據庫的分布式優勢發揮到極緻所需要了解的OceanBase基礎,這也是理解螞蟻金服的基于OceanBase構建的三地五中心異地多活架構的基礎。
分布式數據庫開發相關問題好的性能首先是設計出來的,應用如果追求極緻的性能,就需要關注OceanBase裡數據的相關事情。如:
這些問題對理解OceanBase的分布式特點很有幫助。後面我們逐步看看OceanBase是如何應對。
OceanBase集群外觀首先簡介一下OceanBase集群的外觀。
圖 1 OceanBase集群外觀
OceanBase是以集群形式運行的,由一堆服務器組成。上圖是「三副本」部署,機器會分為三組,每組一個區域(稱為Zone),各個機器通過網絡互相訪問。沒有光纖交換機、共享存儲以及直連網線等。
服務器通常建議CPU、内存和磁盤盡可能的大,磁盤建議用普通SSD盤。普通服務器的好處是便宜,劣勢是可靠性和性能可能不如小型機那麼高。也就是說OceanBase可以部署在一組可靠性和性能不是特别高的普通服務器上,卻提供了高性能、高可用和高可靠、彈性伸縮等多項能力。
以上是一個OceanBase集群的外觀和能力,但是提供給業務的并不是這個集群的全部資源和能力,而是其子集,即租戶(Tenant)。
OceanBase多租戶特性OceanBase定義了一些基本的資源規格(Resource unit config,如4CPU8Gmem500Gdisk等),然後選取某類資源規格創建一組資源池(Resource Pool),此時集群資源就有一部分被分配出去了。最後将這個資源池關聯到一個新建租戶,則租戶就可以使用這個資源池的能力。
OceanBase默認有個sys租戶,管理整個集群。用戶租戶必須在sys租戶内部創建。
如下示例就是創建租戶的過程。
OceanBase兼容了大部分MySQL連接協議和語法,租戶的使用體驗跟MySQL實例很像。研發可以在租戶裡創建數據庫(Database)、表(Table)。還包括分區表等。
OceanBase裡描述數據的最小粒度是分區。普通的表(非分區表)就是一個分區,分區表則包含多個分區。
租戶的示意圖如下。租戶之間數據是絕對隔離,資源有一定程度隔離。研發可以将業務先垂直拆分為多個獨立的子業務,分别使用不同的租戶或者集群。
圖2 OceanBase多租戶示意圖
OceanBase資源單元租戶裡并不知道數據具體在哪個機器上,也可以說沒必要知道。隻是租戶的性能還取決于運維為租戶規劃的資源池分布情況,所以了解一下資源單元的分布特點對性能規劃也是有意義的。
資源池(Resource Pool)是由一組資源單元(Resource Unit)組成。資源單元數量默認跟Zone的數量一緻或者是它的倍數(可以配置具體分布在哪些Zone以及每個Zone裡的Unit數量)。如下圖
圖 3 OceanBase 資源池分配示意圖
資源單元具備一定的資源能力,是數據的容器。租戶擁有的資源單元規格和數量決定了這個租戶最大性能。資源單元可以在同一個Zone的不同節點之間自由遷移,OceanBase借此來維持各個節點的資源利用率盡可能維持一個均衡狀态。
OceanBase拆分設計數據庫拆分
數據庫拆分有兩種。
一是垂直拆分。即按業務模塊拆分到不同的實例或庫裡。為了模塊之間互不影響,拆分到不同的實例比較好。在OceanBase裡實現時可以是拆分到同一個集群裡不同租戶或者不同集群裡的租戶都可以,取決于業務規模和數據庫集群規模。垂直拆分很好理解,後面不再贅述。
一是水平拆分。即按某個業務維度将數據拆分到多個分片。這些分片可以是在一個庫或者不同庫或者不同實例的不同庫下。水平拆分實現又有兩類常用的選擇。如下:
水平拆分示意圖如下:
圖 4 水平拆分的分庫分表和分區表
上圖是分庫分表和分區表同時結合使用。業務表order先經過中間件拆分為100個分表(存在10個分庫裡),每個分表在OceanBase内部又是一個分區表(100個分區)。分庫分表的維度和分區表分區的維度都是一緻的,根據用戶ID。
分庫分表和分區各有利弊。
分庫分表的好處是各個分表的結構一緻性是在中間件層保證,比較好控制,比較适合灰度變更(允許部分分表結構不一緻,最終必須全部一緻)。此外更大的好處是,分庫分表是實現異地多活單元話架構的必不可少的條件。缺點是中間件的SQL支持範圍有限。
分區的好處是在數據庫内部解決了拆分問題。針對分區表的SQL功能是數據庫SQL引擎的本質工作,相關特性(全局索引、二級分區等)會持續開發完善。
分區
分庫分表架構設計,需要确定機器數、實例數、分庫數和分表數的拓撲,性能理論上限取決于主實例所處的機器節點數。此後要做擴展就要調整這四個元素的數目及其聯系。這種擴展很可能涉及到分表數據的遷移,需要借助外部工具或産品實現。
分區架構設計,研發确定分區策略和分區數,運維确定租戶的資源單元數量,OceanBase确定資源單元(Unit)在哪些機器節點上以及分區(Partition)在哪些資源單元裡。同一個分區不能跨節點存儲。如下圖。此後要做擴展就是調整資源單元的規格、數量。
OceanBase在确定Unit裡的分區的位置時會盡量讓每個節點的負載維持均衡。這個負載的計算方式比較複雜,會綜合考慮OB節點内部CPU、内存和空間利用率等。分區随意分布對應用性能很可能有負面影響。當業務上有聯系的兩個表的分區分布在不同的資源單元裡(同時也分布在不同的節點裡),這兩個表的連接就難以避免跨節點請求數據,網絡上的延時會影響這個連接的性能。
圖5 分區在資源單元中的位置
注: t1(p0) 表示表t1的0号分區。
每個分區在集群裡數據實際有三份,即三副本(Replica)。圖中忽略了Zone2和Zone3的細節。三副本之間的數據同步靠把Leader副本的事務日志同步到其他Follower副本中。Paxos協議會保障這個事務日志傳輸的可靠性(事務日志在一半以上成員裡落盤,剩餘成員最終也會落盤),同時還有個以分區為粒度的選舉機制,保障Leader副本不可用的時候,能快速從現有兩個Follower副本裡選舉出新的Leader副本,并且數據還絕對不丢。這裡就體現了故障切換時兩個重要指标:RPO=0, RTO<30s。
Locality
圖5中t0和t1業務上是有聯系的表(如主表和詳情表),兩者都是分區表,分區策略和分片數都相同,OceanBase提供了一個表屬性“表分組”(TableGroup)。設置為同一個表分組的不同表的分區數一定一樣,并且同号分區組成一個“分區分組”(PartitionGroup)。同一個分區分組的分區一定會分配在同一個資源單元(Unit)内部(也就是會在同一個節點内部),彼此的連接邏輯就避免了跨節點請求。另外一個效果是如果一個事務同時修改兩個有業務關聯的分區,使用分區分組也可以規避跨節點的分布式事務。這個表分組屬性的設置就是OceanBase的Locality特性之一——影響相關分區的分布。
實際上每個分區都有三副本(Replica, 本文例子),圖5中省略了t0(p0)和t1(p0)的其他兩個副本都分别會在同一個Unit裡分配。不僅如此,每個分區的三副本裡都會有leader副本默認提供讀寫服務。leader副本是選舉出來的。t0(p0)和t1(p0)的leader副本也一定會在同一個Unit裡(即在同一個Zone裡)。這樣才徹底的避免了連接的時候跨節點請求。
OceanBase的Locality特性還可以指定租戶/數據庫/表的默認Zone,這樣下面的表的leader副本會優先被選舉為這個Zone裡副本。
如下面例子,數據庫和表會繼承租戶的默認設置,當然也可以自己修改primary_zone或者locality屬性覆蓋上層設置。:
create tenant obtrans0primary_zone='hz1';
create table item (…)locality = 'F@hz1, F@hz2, F@hz3,R{all_server}@hz1, R{all_server}@hz2, R{all_server}@hz3'
注:F表示全功能副本,R表示隻讀副本。
設置primary_zone後單個租戶的所有表的讀寫都集中到一個Zone裡,該租戶在其他zone裡的Unit就沒有讀寫壓力。通常這樣做是源于業務應用的要求。如應用的請求都是來自于這個Zone,為了規避應用跨Zone讀寫數據性能下降。不過primary_zone更大的意義在于當集群裡有很多租戶的時候,可以将不同業務租戶的讀寫壓力分攤到不同Zone的機器,這樣集群整體資源利用率提升,所有應用的總體性能也得到提升。後面要介紹的異地多活架構就充分利用OceanBase這個特性,在數據庫層面将拆分的表的業務讀寫點盡可能分散到所有Zone的所有機器上。
除了表與表之間可能有聯系,業務模塊之間也可能有聯系。一個業務過程可能會橫跨多個業務模塊,前面這些模塊的數據被垂直拆分到多個租戶裡。OceanBase的Locality特性“租戶分組”(TenantGroup)還可以設置不同租戶之間的聯系。如下租戶交易訂單和支付訂單在業務上是先後發生。
create tenantgroup tgtrade tenant_array=('obtrade0', 'obpay0');
租戶分組的意義依然是為了在分布式架構下盡可能将一個業務流程内多次數據庫請求都約束在同一個Zone或者Region(注:OceanBase将地域相鄰的Zone定義為一個Region)裡。
OceanBase異地多活架構異地多活概念
異地多活的概念一直都有,隻是内涵不斷變化。以雙機房多活為例,應用通常都是無狀态的,可以多地部署。數據庫有狀态,傳統數據庫隻有主庫可以提供讀寫,備庫最多隻能提供隻讀服務(如ORACLE的Active Dataguard):
上面第1種情形,B地應用是跨地域遠程讀寫數據庫。兩地距離較大的時候性能會很不好。2的B地應用是本地訪問數據庫。3,4,5三種情形兩地數據庫都提供讀寫服務,對應用而言是本地訪問數據庫,但到分布式數據庫内部,其要讀寫的數據是否正好在本地就取決于業務和數據庫的拆分設計。有這麼一種情形,B地應用訪問B地數據庫實例,請求的數據的寫入點恰好是A地,這樣會走分布式數據庫内部路由遠程A地實例中拿到數據,性能上會有些下降,而業務可能不知道為什麼。
OceanBase水平拆分方案
為了避免在分布式數據庫OceanBase内部發生跨Zone請求,應用的請求流量的水平拆分規則和數據的水平拆分規則要保持一緻并聯動,就可以實現真正的應用向本地實例請求讀寫的數據恰好就是在本地實例種。這就是Locality的用途所在。
圖 6 OceanBase集群異地多活水平拆分示意圖
首先業務架構層面能根據用戶ID(uid)做拆分,将用戶拆分為100分。x和y是用戶直接相關的表,都根據uid拆分為100個分表,分布在5個不同的租戶裡。x[00-19]表示20個分表。每個租戶的Leader分别分布在不同的Zone。uid:00-19表示 分到這20個分片的用戶數據和用戶流量。
應用層面在某個環節能根據UID将用戶請求轉發到對應的機房(Zone),應用服務之間的請求信息都有這個UID信息,後面應用請求都在本機房流轉,并且訪問數據庫時通過分庫分表中間件(DBP)和OceanBase的反向代理(OBProxy)就路由到本機房的業務租戶上。
實際使用這個架構時,有幾個隐含的前提,Zone1和Zone2是同城雙機房,Zone3和Zone4是同城雙機房,兩個城市靠的比較近,Zone5 實際很遠,所以一般不提供寫入。為節省空間,Zone5裡的副本放的是日志副本。
應用異地多活架構
上面要實現OceanBase在每個Zone的應用寫入都是恰好是本地訪問,關鍵點就是應用流量水平拆分規則跟數據水平拆分規則保持一緻。而應用要維持這樣一個規則,需要很多産品都要支持水平拆分等。如下圖
圖 7 應用三地五中心多活解決方案
圖中流量接入層的“負載均衡”環節負責調整用戶流量到對應的機房(Zone),此後的應用之間的請求就都是本地訪問。
能使用這個解決方案的業務都是能按用戶維度做水平拆分。有些業務的拆分維度跟用戶維度是沖突的,或者有些業務的數據隻支持集中寫入等,不能做到上面這種多活,但也可以使用OceanBase,實現單點寫入,多點讀取的功能。
OceanBase在異地容災和多活架構方案中的價值就是支持水平拆分規則的定義、解決了多個機房間數據同步和一緻性問題、始終具備高可用和彈性伸縮能力等。
參考作者:mq4096
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!