直播回顧 | 揭祕OceanBase的彈性伸縮和負載均衡原理

OB君:本文整理自OceanBase技術直播間第二期,本期慶濤來為大家詳解OceanBase最獨特的彈性伸縮和負載均衡原理。

您可以關注“OceanBase”公眾號回覆“0530”獲取直播PPT和視頻回放

想不錯過下一場直播,歡迎加入OceanBase釘釘互動群:搜索群號21949783

直播回顧 | 揭秘OceanBase的彈性伸縮和負載均衡原理

概述

所有的分佈式數據庫都宣稱有彈性伸縮能力,具體實現機制不一樣,對業務的影響和風險也就不一樣。本文主要展示OceanBase在資源彈性伸縮和數據負載均衡方面獨特的原理。從資源的聚合和分配,以及後期資源的彈性伸縮,還有數據的分配以及負載均衡,都是OceanBase內部機制,自動化運行,極大的降低了運維成本和出錯概率。

相信你看過後還會意識到,OceanBase的架構設計天生就具備雲數據庫的特點。不過OceanBase跟雲並沒有必然聯繫,場景絕大部分是部署在企業內部機房的物理機上。

OceanBase如何做資源管理

如何聚合資源?

近幾年分佈式數據庫紛紛替換傳統IOE架構,其中一個原因是隨著業務增長傳統的小機和存儲擴容成本很高,並且還不一定滿足業務對性能的需求。分佈式數據庫方案都是架構在普通服務器上。單個服務器能提供的資源能力相比小機和存儲而言是很弱的,但多個服務器聚合在一起的資源能力就有可能超過小機和存儲。

直播回顧 | 揭秘OceanBase的彈性伸縮和負載均衡原理

如上圖是9臺服務器,每臺資源能力是32 CPU, 256G MEM, 5T DISK,如果能聚合在一起,這個資源總和可以到288 CPU,2304G MEM,45T DISK。OceanBase做到這點主要靠每個節點上的數據庫進程OBServer。

上一期直播《直播回顧 | 從0到1手把手教你搭建高可用的OceanBase數據庫集群》介紹瞭如何搭建OceanBase集群。其中OBServer進程啟動的時候指定了幾個跟資源有關的參數。

cd /home/admin/node1/oceanbase && /home/admin/node1/oceanbase/bin/observer -i eth0 -P 2882 -p 2881 -z zone1 -d /home/admin/node1/
oceanbase/store/obdemo -r '192.168.1.241:2882:2881;192.168.1.81:2882:2881;192.168.1.86:2882:2881' -c 20190423 -n obdemo -o "
cpu_count=24,memory_limit=100G,datafile_size=200G,config_additional_dir=/data/data/1/obdemo/etc3;/data/log/log1/obdemo/etc2"

參數中cpu_count, memory_limit和datafile_size就是跟資源有關的。如果這些參數不指定,OBServer進程就會默認取主機邏輯CPU個數減去2參數cpu_reserved默認值)、主機內存的80%(參數memory_limit_percentage默認值)以及數據目錄空間的90%(參數data_disk_usage_limit_percentage默認值)。

OBServer啟動成功後就擁有了主機的絕大部分資源。其中對內存和空間的佔有是排它的,對CPU的佔有是聲明式的(因為除了主機OS,沒有其他進程可以霸佔CPU)。然後9個OBServer節點組建為一個OceanBase集群。這個集群就擁有了很大的資源(270C 1800G 36T)。如下圖。

直播回顧 | 揭秘OceanBase的彈性伸縮和負載均衡原理

總結: 從上面過程可以看出OceanBase集群對機器資源的管理是在內部的,這點不同於其他分佈式數據庫中間件產品的方案。OceanBase集群這種管理方式極大降低了運維成本和出錯的概率。

如何分配資源?

OceanBase集群做了一個超級大的“資源蛋糕”,那麼後面就面臨一個分配的問題。通常不會把這麼大的資源全部給某一個業務用。OceanBase集群實行的是按需分配。每個業務申請數據庫的時候需要提供相應的業務數據量和訪問量的評估,運維人員然後給出一個相應規格的評估,然後從OceanBase集群資源裡切分出這個規格的資源,以租戶的形式給到業務方使用。這個租戶拿到手的感覺就是一個MySQL實例或者一個Oracle實例。如果是MySQL實例,業務可以在裡面建庫建表;如果是Oracle實例,業務可以在裡面建多schema(即多用戶)。

直播回顧 | 揭秘OceanBase的彈性伸縮和負載均衡原理

由於OceanBase集群自己也要工作,所以會保留少量資源用於內部運行,這個內部資源是一個內部租戶sys。這個sys租戶非常重要,是集群的管理核心所在。sys租戶的管理員帳號也是整個集群的管理員帳號。從上圖可以看出為兩個業務分配了資源,其中交易業務租戶(tnt_trade)分得60C120G,支付業務租戶(tnt_pay)分得120C600G。注意,這裡我略去了空間資源,因為OceanBase當前的版本不對空間的內部使用做隔離。

細心的人會問,如果運維給的資源過小怎麼辦?這個不用擔心,如果業務運行一段時間發現租戶(實例)的性能瓶頸在資源,那麼運維可以很方便的對租戶資源進行擴容。當然前提是集群資源裡還有足夠的未分配的資源。同理,如果運維給的資源過大超出業務需求,就有點浪費。這個也可以隨時對租戶的資源進行相應的縮容。後面會介紹資源的彈性伸縮原理。

還有的人會問,上面租戶資源在哪個機器上?這個就是OceanBase獨特的地方,業務方不需要關心他的租戶在哪個機器上。實際上這些資源有可能是在不同的機器上,而這一切都對業務透明。

不過運維人員是能看到租戶資源在哪個機器上,並且還要關注這個業務租戶資源的分佈。因為深入的性能優化是需要了解租戶資源的分佈。

資源分配內部細節

首先運維人員是能夠看出集群資源是由各個節點的資源聚合而成。

select zone,concat(svr_ip,':',svr_port) observer, cpu_total,cpu_assigned,cpu_assigned_percent, round(mem_total/1024/1024/1024) mem_total_gb, round(mem_assigned/1024/1024/1024) mem_assigned_gb, mem_assigned_percent, unit_Num,round(`load`,2) `load`, round(cpu_weight,2) cpu_weight, round(memory_weight,2) mem_weight, leader_count
from __all_virtual_server_stat
order by zone,svr_ip
;
  • 定義資源規格

然後運維人員先定義幾個不同的資源規格。每個規格代表了一定的資源(包括CPU、Mem、Disk、session、IOPS.當然實際上當前版本只對CPU和Mem資源進行分配。

create resource unit S2 max_cpu=20, min_cpu=20, max_memory='40G', min_memory='40G', max_iops=10000, min_iops=1000, max_session_num=1000000, max_disk_size='1024G';
create resource unit S3 max_cpu=20, min_cpu=20, max_memory='100G', min_memory='100G', max_iops=10000, min_iops=1000, max_session_num=1000000, max_disk_size='1024G';

然後使用這兩個資源單元規格分別創建兩個資源池(Resource Pool)。每個Resource Pool實際是由三個資源單元(Resource Unit)組成。如下圖。最後當Resource Pool創建成功後,還需要創建一個租戶並關聯這個資源池,租戶就有了這個Resource Pool的使用權。每個Resource Pool只能關聯到一個租戶。

直播回顧 | 揭秘OceanBase的彈性伸縮和負載均衡原理

在這個過程裡,Resource Unit從哪個節點上分配是有講究的。OceanBase會考慮每個節點的資源分配率以及各個節點的負載等情況。其中有一點內存的分配策略會受參數resource_soft_limit和resource_hard_limit影響。

關於Resource Unit,它是資源分配的最小單位。同一個Unit不能跨越節點(OBServer)。上面交易租戶(tnt_trade)在每個Zone裡只有一個Unit,而支付租戶(tnt_pay)在每個Zone裡有兩個Unit。在一個Zone裡有多個Unit的時候,就能發揮多個節點的資源能力。換句話說並不一定是整個分佈式數據庫集群的機器都能為這個租戶所用,這取決於Resource Pool裡的unit_num的數量。

Resource Unit是數據的容器,當資源分配到位後,接下來就要看看數據在OceanBase裡怎麼分佈。

OceanBase數據如何分佈

水平拆分方案

通常數據是存儲在表裡,在OceanBase裡更多的是說在分區(Partitioin)裡。通常一個表就一個分區,一個分區表有多個分區。分區(動詞)是水平拆分的一種途徑,另外一種是分庫分表。

在螞蟻業務裡,分庫分表和分區是搭配使用的。如下面例子,業務表先通過中間件拆分為百庫百表,然後每個表又變化為分區表(每個分區表包含一百個分區),這樣總體的業務數據就被拆分為100000個分片。每個分片就是一個分區(Partition)。

直播回顧 | 揭秘OceanBase的彈性伸縮和負載均衡原理

為什麼拆分為10000個分區呢?這跟分區的特性有關。我們先看看分區是怎麼分配出來的。

分區的分配(運維視角)

前面說了Unit是數據的容器,指的的就是Partition必須從Unit裡分配出來。每個業務的數據只能在該業務租戶相應的Resource Unit裡分配出來。

如下圖,是交易租戶(tnt_trade)的Resource Pool,由3個Resource Unit構成。然後創建了2個普通表,1個分區表(3分區)。普通表t1只有一個分區(p0),但是OceanBase會創建3個同樣的分區,這三個稱為分區(t1(p0))的三副本,三副本會分別位於三個Resource Unit裡,並且必須是三個不同Zone的Resource Unit裡。

三副本會有角色區分,其中藍色底色的副本是leader副本,默認leader副本提供讀寫服務,另外兩個follower副本不提供讀寫服務。所以,對於一份數據來說,其leader副本在哪個節點的Unit裡,業務讀寫請求就落在哪個節點上。leader副本默認位置由表的primary_zone屬性控制。這個設置也可以繼承自數據庫以及租戶(實例)的primary_zone設置。即使primary_zone設置為RANDOM,在只有三個Unit的情況下(即Resource Pool的unit_num=1的情況下),每個leader副本會默認在第一個Zone裡。除非是建表時明確指定它。

對於分區表t3而言,數據會在三個分區裡,分別是t1(p0)、t1(p1)和t1(p2)。每個分區也有三副本。

直播回顧 | 揭秘OceanBase的彈性伸縮和負載均衡原理

對於unit_num大於1的租戶,每個分區在分配時會多一些選擇,並且leader副本的位置也多一些選擇。OceanBase會考慮各個unit的使用率和負載等。也就是說在建表創建分區的時候,OceanBase已經考慮到負載均衡了。

直播回顧 | 揭秘OceanBase的彈性伸縮和負載均衡原理

分區的分佈以及leader的分佈是隨機的,這個對業務而言並不一定友好。在分佈式數據庫裡,跨節點的請求時性能會有下降。

如果業務層面t3和t4關係很密切,經常做表連接查詢和在同一個事務裡。為了規避跨節點請求以及分佈式事務,OceanBase提供了表分組(tablegroup)技術來干預有業務聯繫的多個表的分區分佈特點。如上圖示例,t3和t4都屬於同一個表分組(tgorder),則它們的同號分區屬於一個分區組(partition group),在穩定的狀況下,同一個分區組的分區一定在同一個Unit內部(即在同一個節點內部),並且它們的leader副本還要在同一個Unit內部。如圖中的t3(p0)和t4(p0)有個虛線連接,就是指在同一個分區組裡。

OceanBase的彈性伸縮和負載均衡

前面說了,當租戶不滿足業務性能需求時,可以做租戶資源擴容。擴容的前提是集群裡資源還有餘量。所以有時候還要先做集群資源擴容。

集群資源擴容

集群資源擴容就是加節點。因為每個節點(OBServer)代表了一定的資源能力。如下圖是一個2-2-2的集群,總資源能力是180C1200G。當前有三個業務租戶,每個Zone裡有4個Resource Unit。目前分佈基本平均。

直播回顧 | 揭秘OceanBase的彈性伸縮和負載均衡原理

集群的資源擴容就是為每個Zone增加相應的節點。

alter system add server '11.***.84.78:3882' zone 'zone1', '11.***.84.79:3882' zone 'zone2', '11.***.84.83:3882' zone 'zone3';

新節點加入後,由於資源利用率很低,整個集群負載就不均衡。OceanBase負載均衡的思路跟傳統負載均衡產品不一樣,OceanBase可以靠調整自己內部Unit的分佈來間接改變各個節點的負載。因為Unit內部有數據(Partition),其中leader副本集中的Unit就會有業務讀寫請求。我們可以看看上圖發生Resource Unit遷移後的結果,如下圖。

直播回顧 | 揭秘OceanBase的彈性伸縮和負載均衡原理

Resource Unit遷移的細節是在目標節點內部先創建Unit,然後再複製 Unit內部的Partition,最後做副本的角色切換(leader跟follower的切換),最後下線多餘的Partition和Unit。

集群資源擴容後,業務租戶的Unit所在節點負載可能會下降一些。如果業務還是有性能問題,此時就要繼續做業務租戶的資源擴容。

租戶資源擴容

租戶資源的擴容是通過調整其Resource Unit的規格和數量來完成。比如說從規格S2升級到S3。

alter resource pool pool_mysql unit='S3';

或者不調整規格,而是增加Unit的數量。

alter resource pool pool_mysql unit_num=2;

下圖演示了增加Unit數量後也觸發了負載均衡邏輯。OceanBase調整各個節點負載的另外一個辦法就是改變leader副本在其租戶多個Unit之間的分佈。

直播回顧 | 揭秘OceanBase的彈性伸縮和負載均衡原理

如上圖是擴容前的租戶的Resource Pool以及各個數據Partition的分佈。所有leader副本默認在Zone1。

當擴容後,部分partition的位置發生變化,同時leader副本也出現在其他Zone裡。

直播回顧 | 揭秘OceanBase的彈性伸縮和負載均衡原理

注意,在這個Partition遷移過程中,還有個特點就是同一個分區組內的Partition最終會遷移到同一個Unit內部。遷移期間有短暫時間可能出現分佈在兩個Unit裡,可能導致有跨節點查詢或者分佈式事務,性能會短暫下跌一些然後很快恢復。這個是業務需要承受的。一般業務壓力不大的時候是感知不到數據庫性能這細小的變化。

手動負載均衡

由上面可知,當集群資源擴容和租戶資源擴容的時候,都會觸發負載均衡機制。縮容同理。在特殊的時期,比如說類似雙11大促,為了防止負載均衡導致數據庫性能抖動引起業務的雪崩,OceanBase還可以關閉自動負載均衡機制。這個是通過參數enable_rebalance控制。同時為了控制負載均衡時Partition遷移的速度和影響,可以調整下面幾個參數

show parameters where name in ('enable_rebalance','migrate_concurrency','data_copy_concurrency','server_data_copy_out_concurrency','server_data_copy_in_concurrency');

下面SQL可以查看業務租戶內部所有leader副本的位置

select t5.tenant_name, t4.database_name,t3.tablegroup_name,t1.table_id,t1.table_name,t2.partition_id, t2.role, t2.zone, concat(t2.svr_ip,':',t2.svr_port) observer, round(t2.`data_size`/1024/1024) data_size_mb, t2.`row_count`
from __all_table t1 join gv$partition t2 on (t1.tenant_id=t2.tenant_id and t1.table_id=t2.table_id)
 left join __all_tablegroup t3 on (t1.tenant_id=t3.tenant_id and t1.tablegroup_id=t3.tablegroup_id)
 join __all_database t4 on (t1.tenant_Id=t4.tenant_id and t1.database_id=t4.database_id)
 join __all_tenant t5 on (t1.tenant_id=t5.tenant_id)
where t5.tenant_id=1020 and t2.role=1
order by t5.tenant_name, t4.database_name,t3.tablegroup_name,t2.partition_id
;

同時運維也可以手動發起Partition的遷移和切換。命令參考:

alter system move replica partition_id ='2%5@1121501860381523' source='11.166.84.79:2882' destination='11.166.84.79:3882';

無論是自動負載均衡還是手動負載均衡,所有的Unit遷移和Partition遷移的事件都可以在總控服務的事件日誌表(__all_rootservice_event_history)裡查詢。有關OceanBase總控服務請參見《OceanBase數據庫實踐入門——瞭解總控服務》。

OceanBase的異地容災和多活

OceanBase分區有三副本,分佈在三個Zone,這個Zone可以是三個機房,其中還可以有一個是異地機房。所以OceanBase架構天然就具備了異地容災的能力。至於異地多活的能力,就形態而言有很多種。

首先看下面這種異地多活形態。

首先,分佈式數據庫數據分佈特點通常是無規則的並且是業務無需感知的(注:分佈式數據庫中間件的數據分佈是有規則的,弊端是數據無法自由流動)。當三機房部署時,三個Zone的業務都可以本地寫數據庫這個很容易做到,因為業務不關心也無從知道數據訪問的內部路由。當數據的寫入點在分佈式數據庫內部是無規則的,分佈在所有機房時,會有很多內部請求跨機房,這個業務性能就很差。如上圖,每個Partition都只標識了其leader副本位置,業務通過OBProxy路由訪問其數據。這樣的多點寫入或者異地多活對業務的意義不大。

所以OceanBase為業務提供一些策略用於干預leader副本分佈位置。主要策略有:租戶/數據庫/表的primary_zone設置;租戶的locality設置;OBProxy的路由策略等等。業務稍加運用這些規則就可以得到下面這個部署形態。每個業務的數據的leader副本都被指定到跟業務應用相同的一個Zone,這樣業務都是本地同機房訪問其數據。這也算是一種異地多活。

直播回顧 | 揭秘OceanBase的彈性伸縮和負載均衡原理

不過有些場景業務還是希望所有機房部署的應用一樣,並且都要是同機房本地訪問數據。這個光靠OceanBase是做不到,還需要對業務數據做分庫分表的水平拆分,並且業務應用也支持流量按相同規則拆分。通常是按用戶請求拆分。這樣就做到一個用戶的流量請求被路由到某個機房的APP後,這個用戶的相關數據也在這個機房,那麼後面跟該用戶有關的數據請求就都是本機房的。

直播回顧 | 揭秘OceanBase的彈性伸縮和負載均衡原理

有關異地多活的架構經驗詳情請參見文章《如何基於OceanBase構建應用和數據庫的異地多活》。

試驗觀察OB彈性伸縮和負載均衡

觀察工具dooba

雖然每個分區的位置我們都可以查詢系統視圖確認,但那樣不夠直觀。所以我們需要一個好的工具來觀察到這個負載均衡過程。這個工具就是dooba,這是一個python腳本。運行命令如下:

$python dooba.py -h11.***.84.84 -uroot@sys#obdemo -P2883 -prootpwd

這個可以觀察每個租戶總的業務每秒讀寫請求量及其響應時間(RT)信息,同時還可以觀察到每個Unit內部發生的每秒讀寫請求信息。

指標說明:

SSC:sql select count
SSRT:sql select rt.
SIC: sql insert count
SIRT:sql insert rt.
SUC: sql update count
SURT:sql update rt.
SDC: sql delete count
SDRT:sql delete rt.
TCC: trans. commit count
TCRT:trans. commit rt.

由前面得知,leader副本在哪裡,業務請求就可能落在哪個節點。那反過來,如果我們通過工具觀察到某個節點上有讀寫請求,那就表示那個節點上有Unit內部有leader副本。

試驗內容

首先準備好業務租戶

create resource unit unit_demo max_cpu=25, min_cpu=20, max_memory='20G', min_memory='10G', max_iops=10000, min_iops=1000, max_session_num=1000000, max_disk_size='1024G'; 
create resource pool pool_mysql unit = 'unit_demo', unit_num = 1;
create tenant tnt_mysql resource_pool_list=('pool_mysql'), primary_zone='RANDOM',comment 'mysql tenant/instance' set ob_tcp_invited_nodes='%', ob_compatibility_mode='mysql';

然後準備好租戶裡的表,這裡使用sysbench初始化一個測試表,不過對sysbench腳本稍作改造,把建表語句改為分區表了。

CREATE TABLE `sbtest1` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `k` int(11) NOT NULL DEFAULT '0',
 `c` char(120) NOT NULL DEFAULT '',
 `pad` char(60) NOT NULL DEFAULT '',
 PRIMARY KEY (`id`, `k`),
 KEY `k_1` (`k`) LOCAL 
) partition by hash(k) partitions 5;

剛開始的數據分佈時,由於租戶只有3個Unit,所以5個partition都在同一個Unit內部,並且所有leader副本都集中在第一個Zone。從下圖也能看出這點。

直播回顧 | 揭秘OceanBase的彈性伸縮和負載均衡原理

然後模擬業務讀寫這個表,持續運行一段時間。

./sysbench --test=./oltp_read_write_ob.lua --mysql-host=11.***.84.84 --mysql-port=2883 --mysql-db=sysbenchtest --mysql-user="obdemo:tnt_mysql:demouser" --mysql-password=123456 --tables=1 --table_size=1000000 --threads=32 --time=600 --report-interval=10 --db-ps-mode=disable --skip-trx=on --mysql-ignore-errors=6002,6004,4012,2013,4016 run
 

然後進行租戶擴容

alter resource pool pool_mysql unit_num=2;

然後觀察一段時間。等OB做完負載均衡後,監控界面如下。其中有個節點沒有請求,因為整個租戶總共也只有5個分區。

下期直播預告:OceanBase的高可用和容災原理以及運維實踐。

想不錯過下一場直播,歡迎加入OceanBase釘釘互動群:搜索群號21949783


分享到:


相關文章: