螞蟻金服慶濤:OceanBase支撐2135億成交額背後的技術原理
現任螞蟻金服 OceanBase 團隊技術專家,曾經支持過阿裏雲數據庫和天貓雙 11 大促業務,在分布式數據庫的開發和架構上有著豐富的經驗。目前主要從事 OceanBase 對外輸出的解決方案設計和技術推廣工作。
本次直播視頻精彩回顧,戳這裏!以下內容根據演講嘉賓視頻分享以及PPT整理而成。本次的分享主要圍繞以下三個方面:
- OceanBase基礎概念
- OceanBase分布式設計
- OceanBase性能調優
一、OceanBase基礎概念
集群
OceanBase是一個通用的分布式關系型數據庫,也是螞蟻自主研發的數據庫,它是以集群形式呈現的。從外觀上來說,以三副本為例,它分為三個區域(Zone),三個區域(Zone)放在三個機房是最好的選擇。OceanBase集群的所有服務器是都普通的商用服務器,安裝RedHat或者CentOS的Linux系統,生產環境用普通的SSD盤。除此之外,OceanBase集群並不依賴共享存儲和光纖設備。
集群內部結構
下圖細化了上面集群的內部架構,9臺機器的角色基本相同。OceanBase數據庫集群搭建非常便捷,每個機器只需要安裝OBServer軟件。它是一個單進程的程序,內部分為幾個模塊,SQL引擎,存儲引擎以及總控服務(可選)。總控服務主要職責是負責整個集群的元數據管理和集群內部的調度管理。總控服務只需要在每個區域(Zone)的一臺機器上出現就可以,一共三個,其中一臺上面總控服務提供服務,另外兩臺機器上的是它的副本,這是為了保證當總控服務不可用時可以迅速另外兩臺機器上選舉一個新的總控服務提供服務。下圖還可以看到數據存在分區(Partition)內,可以通過存儲引擎訪問分區(Partition)。因為數據有三份,即分區(Partition)也有三份。三份數據必定會分在三個不同區域(Zone)裏面,不會在同一個區域(Zone)或同一個OBServer中。OBServer還有個特點。當OBServer進程在一臺機器上跑起來之後,會把機器上大部分的資源(如CPU、內存和磁盤空間)據為己有。這是為了將集群資源聚合在一起,成為一個大的資源池,再進行資源分配,做多租戶的管理。
多租戶管理資源
資源規格(ResourceConfig)。租戶是資源的抽象,整個集群可能有幾百個CPU,幾TB的內存,幾十TB的空間。一個應用在最開始上線時並不需要如此大的內存,可以分出一部分資源給租戶。分配資源前先定義資源規格,資源規格定義CPU的數量,內存的大小等等。定義資源規格後,創建資源池(resource pool),這時需要說明要用哪個規格以及數量。命令執行完之後就是真正把集群裏面的資源分出一部分了。
租戶(Tenant)。資源池分配之後還要關聯到租戶才可以被使用。租戶需要新建。租戶的概念與傳統數據庫裏的實例是一樣的。一個租戶給到研發人員可以理解為他拿到了一個數據庫實例。下圖右邊是資源的抽象圖,最大的框是集群資源的抽象,租戶是從大資源池裏面挖出一塊,租戶的大小各有不同,取決於不同的資源規格,這與酒店的房間規格是同理。如果租戶的規格在開始定好之後,後面調大小也是非常方便的。研發同學拿到租戶之後便可以在裏面創建數據庫。雖然目前OceanBase的實例與MySQL很相似,但是它絕不是MySQL,你可以看到它多了一個數據庫叫OceanBase。同樣,可以創建很多用戶數據庫,數據庫中可以建表。在OceanBase裏一個普通的表就是一個分區(Partition),一個分區表可以包含很多分區。
Unit均衡。下圖是研發同學拿到租戶之後可以看到的視圖,但是他看不到數據在哪臺機器上(也不需要知道)。這張圖從另外的角度解釋了資源是如何分配的,resource pool創建後,每個區域(Zone)裏面分配出兩個同樣大小的資源規格(因為unit_num=2)。那綠色的Unit應該從哪臺機器中選擇,下圖中每個區域(Zone)有四臺機器,OceanBase會選一個比較空閑的機器。這裏會涉及到負載均衡的概念,OceanBase在資源分配時(創建Unit時)會盡量維持各個機器的利用率保持均衡。租戶是資源的抽象,與實際的機器是解耦的,運維人員不需要關心數據具體在哪臺機器上,只需要保證機器上有空余的資源就可以。另外,租戶的設計機制裏Unit的分布和實際機器解耦,所以租戶有著很好的彈性伸縮能力。
分區(Partition)
表分組(Tablegroup)。研發同學拿到租戶之後會開始建表,OceanBase中非常重要的概念是分區(Partition)。分區是數據的最小粒度,它可以是一個普通表或者分區表的一個分區,它在租戶的Unit裏分配。當該租戶的資源池(Resource Pool)在該Zone裏有多個Unit的時候,創建分區時該選擇哪個Unit分配呢,這就是OceanBase負載均衡機制第二個場景。默認的策略是盡可能的讓每個Unit資源使用率做到均衡。分區不能跨節點,只能在一個Unit內部,但是分區表的多個分區是可以在不同Unit內部。這是OceanBase分布式的一個特點。有些業務會比較關心是不是在一個機器裏,如果業務上主表和子表要做連接(Join)的數據分布在不同的節點,那麽這個查詢的性能就不是最好。最好的情況是在同一臺機器,甚至同一塊內存裏面。這裏OceanBase提供的策略是允許設定兩個表有關系,這樣底層分配分區位置時會把有關系的表的分區聚合在一個Unit裏,這個策略就是通過表分組(Tablegroup)設定,類似與Hadoop裏面的Tablefamily,設計思想是一樣的。下圖把幾個表的Tablegroup設為同一個,Tablegroup還可以細分為Partitiongroup,一張分區表有兩個分區(Partition)的話,Tablegroup會分為兩個Partitiongroup,0號Partitiongroup和1號Partitiongroup。
分區組(Partitiongroup)。下圖橘×××虛線框是Tablegroup,黑色虛線框是Partitiongroup。Partitiongroup的作用是將這些分區(Partition)聚集在同一臺機器(同一個Unit)裏面,確保分區(Partition)不跨節點。雖然一個分區(Partition)不跨節點,但是分區表的不同的分區(Partition)是可以跨機器的。所以當一張表的容量在一臺機器上放不下的時候可以設分區(Partition)表,這樣便可以分在不同的機器上面。
值得註意的是,分區(Partition)還是數據遷移的最小單元。分布式系統默認不控制分區(Partition)的分布,可能導致機器資源利用率不均衡,OceanBase可能會把分區(Partition)從一個Unit裏面挪到另外Unit中,或者把一個Unit整體搬遷到另外一個機器內部。遷移數據時以分區(Partition)為單位,這種數據遷移完全是內部的邏輯,並且是在線遷移對業務讀寫影響很小。
三副本
下圖是三個節點的集群,三個機房是IDC1,IDC2,IDC3,每個區域(Zone)裏面有兩臺機器,Observer1-6。稱為222的集群結構。P1,2,…指的是分區(Partition),且每個分區都有三份,每份稱為一個副本,內容都是一樣的,業務應該訪問哪個副本呢?三副本有一個Leader副本和兩個Follower副本。粉紅色代表Leader副本,默認情況下業務會讀寫Leader副本。我們通常不叫主副本,因為OceanBase的Leader副本和Follower副本和傳統的主備的概念不完全一樣。每臺機器裏面,既有Leader也有Follower,所以無法說哪臺機器是主,哪臺機器是備,6臺機器都提供了訪問。對業務來說,不知道要訪問的數據的leader副本在哪臺機器上。這個通常靠OBProxy解決,它是分區(Partition)的反向代理,OBProxy知道業務要訪問的數據的Leader副本位置,業務只要訪問 OBProxy就可以了。
分區(Partition)還是高可用的最小單元。如果有一臺機器掛了,傳統場景下運維人員要把備庫切換為主庫。但是在OceanBase場景下並沒有傳統的主備的概念,機器掛了之後只有其中的Leader副本訪問受影響,Follower副本並不受影響(因為本來就不提供服務)。Leader副本不可訪問時,OceanBase會很快從其他兩個Follower副本中選舉出一個新的Leader繼續提供服務。
三副本作用
1.三副本強一致性。三副本可以做到Leader副本上的每一個修改在Commit的時候會同步到Follower副本上。正常情況下,傳統系統下業務要修改數據,在事務提交時事務日誌(Redo)需要落盤,OceanBase也同理,修改數據要生成事務日誌然後再修改數據。提交時,事務日誌除了本地要持久化一份,還會在其他Follower副本上也會持久化一份。傳統一主兩備強同步時,兩備中只要其中一個接受事務日誌並持久化,那麽主庫上面的提交就可以返回。OceanBase則選擇了另外一種策略,每個分區裏有三個副本,三個副本中有一半以上的成員成功接受並持久化事務日誌之後,Leader就會認為這份事務日誌是可靠的,便直接可以返回。兩個Follower接受事務日誌時會有先後順序,不需要等待所有的副本都確認成功,最終都是要成功的。這個策略,性能還算可以,事務日誌可靠性也得到了保障。
2.無需人為處理機器故障。當Leader不可用時重新選取新的Leader,而且以每個Partition為單位,每個Partition獨立選擇Leader,選出來時間大概在14-20秒之間。這種選取是自動的,不需要運維人員或外部工具介入。應用會通過OBproxy感知到Leader的切換,所以業務部分也不需要改連接字符串。整體效果上,OceanBase集群裏面任何一臺機器宕機時都不需要人去處理。
SQL兼容性
數據類型。OceanBase在起初兼容的是MySQL的連接協議,它實現了MySQL大部分的語法,也支持不同的數據類型。但是兼容MySQL並不是OceanBase主要目的,其主要目的是兼容Oracle。
SQL層功能。目前OceanBase支持Oracle的增刪改查,內部也已經實現了存儲過程,窗口函數,層次查詢。DB link和外鍵還在開發過程中。
事務層。OceanBase支持Read committed的隔離級別,正在做序列化隔離級別(Serializable),以及flashback的功能,另外OceanBase也支持分布式事務(XA協議)。
內部視圖。OceanBase實現了Oracle中的大部分內部視圖,包括部分ALL/DBA/USER_視圖。索引支持全局索引,函數索引。
分區(Partition)。OceanBase支持一級分區(Partition)和二級分區(Partition)。由於分區(Partition)組合的類型有很多,現在正在完善中,其中hash分區(Partition),range分區(Partition)和list分區(Partition)現在都是支持的。
偽列。 Oracle中有比較好的偽列,如rownum,sequence和virtual column等偽列OceanBase也正在開發。
存儲過程。這是最重要一點,很多傳統業務都是在存儲過程上面寫,如果要換OceanBase,可能不太想去改他們的存儲過程。客戶端可以連接OceanBase,一種方法是通過OBproxy,還有一種是Java程序可以提供Java驅動。
二、OceanBase分布式設計
拆分設計
一般做分布式設計,都會思考要不要做拆分,從什麽緯度拆分。拆分方法有幾種途徑。
1.垂直拆分。一個大的業務一般在一個庫上面,垂直拆分是按照業務模塊,將不同模塊放到不同的租戶裏面。
2.水平拆分。水平拆分有以下幾種方式。
分庫分表。分庫分表它通過中間件做拆分,能夠把業務上的表拆分到多個相同的物理結構中,從業務上看是在一個表Order裏,但是數據庫裏面是Order00,01...等多個物理表。中間件解決了SQL路由問題,數據的位置可以通過中間件得知,事先要按拆分件的條件通知中間件數據位置。假設SQL裏沒有拆分,中間件無法得知數據的去向,那它就會選擇從所有的物理表中尋找,這時性能便會大打折扣。
分區表。如下圖,Order00是存儲在數據庫裏面的表,OceanBase在存儲的時候會將表分為很多的小的Partition,然後Partition會分到不同機器上面。OceanBase選擇了分區表的方法,它的好處是業務可以控制拆分策略,可以決定按照什麽緯度拆分。
存儲層面按定長塊拆分。首先定義一張大表,然後在存儲級別按照固定大小的塊,切分很多小塊,將小塊分到不同機器上面存儲。按這種拆分方式的話業務是完全透明的,其好處是業務不需要關心產品規格,但壞處是由於不知道數據位置,後續會有很多跨機器的訪問。
Locality設置
由於分布式數據庫的分區(Partition)是隨機的,但從業務層面考慮是希望能夠控制分區(Partition)的分布。OceanBase也提供了一些策略來控制分區(Partition)的分布。
表分組Tablegroup。第一種策略是通過表分組Tablegroup,在建表時添加Tablegroup屬性,在不同表有關聯時將它們設到同一個Tablegroup中。這樣再下一層同號分區會在同一個PartitionGroup中,被約束在同一個Unit內部。
租戶的分組(TenantGroup)。更大範圍的控制就是租戶的分組(TenantGroup)。當業務量很大時,首先做垂直拆分,劃分為不同業務,不同業務分到不同租戶中。但在業務流程中,某些業務是有關系的,所以希望相關的業務能夠分在同一個機房內,通過租戶的分組便可以將所有業務的請求同在一個機房內完成。
Primary Zone。還有一種方法是設置不同業務的Primary Zone,Primary Zone可以控制Leader副本在哪個Zone裏面。
Locality詳細設置。下圖最後一條命令是Locality從上到下的詳細設置,其實用戶可以不用如此詳細。其中最大範圍是租戶Tenant,之後是數據庫,再下面是表。如果對租戶加了設置,數據庫和表可以不加設置,它們可以繼承上層的設置屬性。OceanBase裏面的Locality的概念主要用來設計單元化訪問,規避分布式事務以及跨地域SQL請求。
異地多活
異地多活是傳統數據庫中也會提到的概念。下圖中五條異地多活形式,從上到下難度變得越來越高。
·第一個是應用雙活,雙擊訪問,由於應用是無狀態的,其中給每個機房部署稱為應用雙活。但數據一邊可讀寫,另外一邊不可讀寫,這就是主備架構,無法做到兩邊都是主庫,這種稱為備份容災。
·第二個是應用雙活,數據庫還是一邊讀寫,但是另外一邊可以開一個只讀庫,如Oracle的active dataguard,做多個備戶,在另外的機房把主戶打開。這種稱為讀寫分離。
·第三個是應用雙活,數據庫多活,同時讀寫不同表。兩地機房都可以提供寫入,單從業務層面看是雙寫,但是寫的是不同的表,如此而來寫的數據便不會有沖突。
·第四個是應用雙活,數據庫多活,同時讀寫相同表。但是寫的記錄不同,這種多活采取了錯開寫的方式。
·最後一種形態是兩邊寫相同的記錄,出現沖突的時候會報錯。雖然設計時可以這樣寫,但是不可避免的會有數據沖突,這時要舍棄一方的寫入。
OceanBase做到了第三種錯開寫,借助分庫分表的方式,將業務的數據拆分到不同表中,不同的表在兩邊提供寫入,如1號表在A機房寫,2號表在B機房寫。
單元化指的是應用本地讀寫數據,但是更高的要求是兩邊機房要同時本地寫。沒有跨地域的請求,即自封閉。
單元化
下圖是三地五中心的多活容災解決方案,其中數據有五份,這個解決方案可以做到五個機房的應用同時寫五個機房的數據。其中應用無狀態,每個機房也都有數據,但是寫入點是不同的,走的是不同鏈路,這時需要依靠應用和數據庫的結合,要讓應用層的流量拆分規則和數據層的拆分規則保持一致。這是理解阿裏和螞蟻單元化的非常關鍵的地方。OceanBase可以幹預數據的拆分規則,可以設Leader副本分布在什麽位置。數據之間保持同步是數據庫內的行為,不需要外部的產品去做,所以不需要擔心數據丟失和數據一致性的問題,出現問題時也不需要擔心可用性的問題。
三、OceanBase性能調優
與Oracle相似,OceanBase的SQL執行計劃一樣用軟解析,硬解析等。OceanBase支持執行計劃及緩存,軟解析以及各種join語法.
另外,OceanBase支持非常復雜的Hints,如改變表連接順序的Hints,索引相關的Hints和調試的語句的Hints。在調試SQL的性能時,會有一些Hints必須調試。以及包括並行,SQL改寫之類的Hints。
Outline是Oracle特有的東西,它的作用是可以在線改變SQL執行計劃。如果SQL執行的計劃有問題,需要在線定義Outline來改變執行計劃,包括在前期上線前做測試時將執行計劃固定住,之後把執行計劃遷到線上。Outline更好的應用是做SQL限流,假設SQL業務上某個SQL性能非常不好,便可以通過Outline限制SQL的並行數量。
一般OceanBase性能調優有兩個策略.第一個是SQL響應時間調優,包括通過優化訪問路徑,優化排序或聚合操作,優化分區(Partition)裁剪,調整查詢並行度以及優化連接等策略。如果SQL響應時間調優方法達不到優化目的,就需要調數據庫吞吐量,主要是通過優化SQL的流量分布,優化分區(Partition)的均衡分布。
點擊 閱讀更多 查看更多詳情
螞蟻金服慶濤:OceanBase支撐2135億成交額背後的技術原理