?
熟悉或曾用過OceanBase的朋友,對于“多租戶”這一理念定不陌生。OceanBase的租戶概念,與我們熟知的傳統數據庫實例頗為相似。舉例來說,OceanBase的租戶支持MySQL兼容模式,對于用戶而言,選用一個MySQL兼容模式的租戶,就如同用一個MySQL數據庫實例。
OceanBase 4.3 版本在已有的多租戶架構基礎上,新增了功能——租戶克隆,本文將向大家介紹租戶克隆的應用場景和使用方法。
租戶克隆功能是什么?
當我們需要使用 OceanBase 數據庫時,會在一臺或多臺機器上拉起 OceanBase 進程,這些進程會組成 OceanBase 集群。在這個集群中,我們可以創建出需要的租戶。單個 OceanBase 集群中可以創建出多個租戶,租戶間互相隔離。
如下圖所示,在 OceanBase 的系統租戶下執行該克隆語句,就可以對指定的源租戶快速克隆出一個新租戶。新克隆租戶在初始時刻包含的數據,就是源租戶在語句執行時刻的一個快照。
租戶克隆操作可以快速把源租戶的元數據信息,拷貝一份,給到新克隆租戶來使用。初始時刻,新克隆租戶訪問的是和源租戶完全相同的物理宏塊。宏塊,就是上圖中畫的 Macro Block,是 OceanBase 中基礎的數據存儲單元。
因為克隆過程只拷貝了元數據,而不是拷貝數據,克隆操作可以快速完成。
該新克隆租戶與源租戶是兩個獨立的租戶,他們之間保持了 OceanBase 一直以來的租戶隔離特性,存在嚴格的數據隔離和資源隔離。新克隆租戶的任何數據改動,都不會影響到源租戶;源租戶的數據改動,也不會影響到新克隆租戶。新克隆租戶與源租戶具有自己獨占的 CPU、內存、IOPS 資源,不相互搶占。
租戶克隆功能可以做什么?
如果大家在使用OceanBase的過程中遇到以下六種場景,租戶克隆功能就會發揮它的價值。
場景一:報表任務。
業務正在大促,賣得非常好,數據庫運行平穩,但已處于滿載狀態。老板非常高興,走到值班室,問技術團隊要一個當前整體銷售情況的報表。這時候,是選擇冒著被“廣進”的風險跑這個報表任務呢?還是選擇對滿臉期待的老板進行下預期管理呢?如果最終決定運行這個報表任務,當前這種情況下,又該開多大的并發度來跑大查詢呢?
這時就可以利用租戶克隆技術,快速基于生產租戶克隆出一個新的報表租戶,用新克隆出來的報表租戶執行在線數據分析任務。
從 OceanBase 4.3 版本開始,支持行列混合存儲,如果源租戶是行列混存結構,克隆得到的新租戶也是行列混存結構,可以良好支持 AP 負載。
場景二:快彈只讀備租戶。
生產租戶壓力很大,同時內部運營系統,還會發送不那么確定的復雜查詢負載。我們希望將這些來自內部的復雜查詢負載,從生產租戶上快速移走。
這時就可以利用租戶克隆技術,快速基于生產租戶克隆出一個新租戶,讓這個新租戶作為生產租戶的備租戶。新租戶會主動去生產租戶上拉取日志,提供一個準實時的弱讀服務。
如此一來,我們就可以將內部運營系統的復雜查詢負載,快速轉移到這個新的只讀備租戶中。
場景三:應用版本發布。
不少應用的版本發布流程,都是先備份數據庫,再更新應用版本。若這次應用版本發布出現問題,就用發布前的那個數據庫備份,來還原數據庫,最終實現整體版本發布的回退。備份數據庫及用備份來恢復數據庫,在數據量增大后都變得特別慢,導致整個版本發布過程執行時間特別長。
為了最小化版本發布對生產經營的影響,版本發布大多選擇在凌晨進行,同時為了應對各類突發情況,整個版本發布過程時常需要相關同學現場值守。發版時間太長,一方面對業務生產經營產生影響,另一方面會讓參與同學倍感疲倦。
租戶克隆技術就可以在一定程度上解決這個問題。首先在版本正式發布前,可以基于生產租戶克隆出一個預發測試租戶,用這個預發測試租戶來做最后的版本預發驗證。版本發布的第一個流程,利用租戶克隆技術,對生產租戶克隆出一個小規格的臨時備份租戶。如果版本發布出現問題,就可以用這個臨時備份租戶,克隆出新的生產租戶,來將數據庫還原到版本發布之前。
因為租戶克隆過程執行得很快,可以大幅度減少版本發布需要的執行時間。
場景四:數據庫變更。
這是 DBA 同學經常遇到的場景。比如研發同學找到你幫忙調整一個索引,并且告訴你這個變更在測試環境已經驗證了很久了,絕對沒問題。結果你一執行完索引變更,數據庫 CPU 直接就飆到100%,同時你發現,如果要將之前的索引重新構建出來,至少要6個小時。
這時,租戶克隆機制就可以幫你解決這個問題,具體做法和應用版本發布的操作類似。
場景五:快速構建開發測試環境。
當前我們的代碼已經可以通過像 git 這樣的工具被分支化管理,比如:你要做一個 bugfix,你可以快速拉出一個 bugfix 分支并在分支上編寫代碼。但是整個研發過程,不光是編碼,還有測試驗證。測試驗證時常需要基于主干測試庫,構建出一個分支測試庫。主干測試庫可能很大,進而構建這個分支測試庫耗時很長,最終導致編碼 5 分鐘,搭建測試環境 5 個小時的情況。
租戶克隆技術就可以解決這個問題,快速從主干測試租戶中克隆一個分支測試租戶,以支持分支的測試驗證。
場景六:數據導出。
部分時候,我們需要將數據庫中大量的表數據按 csv 格式,導出到對象存儲中,以供下游的大數據分析系統使用。由于擔心影響線上生產服務,不敢開太大的導出并發,導致導出速度緩慢。
這時可以利用克隆功能,克隆出一個新的導出租戶,用這個新的導出租戶來執行數據導出任務,盡可能地減少對生產租戶的影響。
租戶克隆如何實現?
租戶克隆的過程大致分為兩個步驟。第一個步驟是對源租戶創建一個 crash-consistent snapshot;第二個步驟是基于 crash-consistent snapshot 拉起新克隆租戶。可以看到,整體的克隆流程都是圍繞著這個 snapshot 進行的。
下面依次介紹兩個步驟的執行。
如何在一個 shared-nothing 的分布式數據庫中,創建 crash-consistent snapshot?如下圖所示,在分布式數據庫基礎模型中,單個數據庫具有多個完全對等的節點。每個節點都有自己的內存緩存,持久化的日志文件及持久化的數據文件。正常更新的時候,數據修改都是在內存中進行,并在必要時,將日志持久化到日志文件中。后臺會有定時的checkpoint 任務,將內存中修改過的數據,刷寫到數據文件中,同時記錄下宕機重啟時,回放日志的起始位點,即 checkpoint 點。多個節點間,通常會有一個高可靠高可用的全局時間戳服務,用來保證分布式數據庫整體的外部一致性。
基于分布式數據庫中已有的這些組件和機制,快照創建的過程,大致分為如下三個步驟:
第一步,記錄下各個節點當前的 checkpoint 位點。
第二步,備份各個節點的數據文件的元數據,通過元數據,找到需要的數據。
第三步,通過全局時間戳服務,確定最終的一致性快照位點。
上述步驟執行完成后,各個節點保留下來的數據文件,加上各個節點從 checkpoint 位點到 snapshot 位點的日志文件,就構成了一個 crash-consistent snapshot。后續我們就可以基于這個 crash-consistent snapshot,拉起新的克隆租戶。
新克隆租戶的各個節點,會通過之前保留下來的數據文件,獲得到初始數據,同時每個節點會繼續回放從 checkpoint 位點到 snapshot 位點的日志,這樣所有節點在克隆執行完成之后,都會將自身的狀態準確的更新到 snapshot 位點。
整個租戶克隆的步驟都是非阻塞的,不會阻塞源租戶正常的SQL 執行。
下圖描述了租戶克隆在 OceanBase 中的具體實現。
日志部分:我們利用了 OceanBase 已有的歸檔日志機制,來實現克隆過程中日志數據的保留和管理。新克隆租戶的各個節點拉起之后,會訪問源租戶的歸檔日志,讀取并回放從 checkpoint 位點到 snapshot 位點的日志數據,從而將各個節點的狀態統一更新到 snapshot 位點。
數據部分:從 OceanBase 4.0 版本開始,數據以 Tablet 的形式來組織,Tablet 會引用自己需要的物理宏塊,數據最終存儲在各個物理宏塊中。克隆過程會拷貝源租戶各個 Tablet 的元數據,生成新克隆租戶的元數據,并且遞增各個關聯到的物理宏塊的引用計數。
一致性快照位點:通過 OceanBase 的全局時間戳服務 GTS,來生成一致性快照位點。
租戶克隆操作方法
- 前置準備。
租戶克隆功能依賴于日志歸檔,需要對源租戶開啟日志歸檔,才可以對該租戶執行租戶克隆。并且在租戶克隆語句的執行期間,不可以關閉源租戶的日志歸檔。
- 租戶克隆語句。
CREATE TENANT new_tenant_name FROM source_tenant_name WITHRESOURCE_POOL [=] resource_pool_name,UNIT [=] unit_config
new_tenant_name:新克隆租戶名;
source_tenant_name:源租戶名;
resource_pool_name:表示資源池的名稱,租戶克隆時將會自動根據源租戶的資源分布,為新租戶創建出資源池;
unit_config:新克隆租戶 resource pool 的 unit 規格;
可以在系統租戶下執行該語句,為指定租戶創建出一個新的克隆租戶。這個新克隆租戶的 unit 數量,以及 unit 在各個 observer 上的分布,均與源租戶保持一致。可以在語句中指定新克隆租戶單個 unit 的規格。
-- 基于 mysql 租戶當前狀態創建克隆租戶 clone_tenant
-- 該語句自動創建出的 resource pool 名為 clone_tenant_pool,其各個 UNIT 規格為 S1_unit_config
CREATE TENANT clone_tenant FROM mysqlWITHRESOURCE_POOL = clone_tenant_pool,UNIT= S1_unit_config;
- 租戶克隆速度。
源租戶 | 新克隆租戶 | 克隆租戶操作執行時間 |
8核64G,單日志流包含 50w tablet,數據量 1TB。 | 8核64G | 2min |
- 新克隆租戶使用。
租租戶克隆任務執行完成后,得到的新克隆出的租戶為只讀租戶。
既可以將該新克隆租戶繼續作為只讀租戶提供相關服務,又或者可以將該新克隆租戶設置為源租戶的備租戶,亦或者可以通過 ALTER SYSTEM ACTIVATE STANDBY TENANT new_tenant_name,將新克隆租戶轉為可讀可寫的主租戶提供服務。
如上文中提到的,該新克隆租戶與源租戶之間存在嚴格的數據隔離和資源隔離。
- 租戶克隆任務。
當在系統租戶下執行租戶克隆語句時,該語句會生成對應的克隆任務,clone job。可以通過 DBA_OB_CLONE_PROGRESS 和 DBA_OB_CLONE_HISTORY 視圖查看克隆任務的執行狀態;PROGRESS 表中包含當前正在執行的 clone job;HISTORY 表中包含執行完成的 clone job。
相關字段:
列名 | 類型 | 含義 |
CLONE_JOB_ID | bigint(20) | 主鍵,克隆任務 id |
TRACE_ID | varchar(64) | 克隆任務 Trace Id |
SOURCE_TENANT_ID | bigint(20) | 源租戶 id |
SOURCE_TENANT_NAME | varchar(128) | 源租戶名稱 |
CLONE_TENANT_ID | bigint(20) | 克隆租戶 id |
CLONE_TENANT_NAME | varchar(128) | 克隆租戶名稱 |
TENANT_SNAPSHOT_ID | bigint(20) | 快照 id |
TENANT_SNAPSHOT_NAME | varchar(128) | 快照名 |
RESOURCE_POOL_ID | bigint(20) | 克隆租戶資源池 id |
RESOURCE_POOL_NAME | varchar(128) | 克隆租戶資源池名 |
UNIT_CONFIG_NAME | varchar(128) | 克隆租戶 unit 配置名 |
RESTORE_SCN | bigint(20) unsigned | 克隆租戶的目標回放位點 |
STATUS | varchar(64) | 克隆任務的當前狀態 |
CLONE_JOB_TYPE | varchar(16) | 克隆任務的當前狀態RESTORE - 基于租戶歷史快照克隆租戶FORK - 基于租戶當前狀態克隆租戶 |
CLONE_START_TIME | timestamp(6) | 克隆任務開始時間 |
CLONE_FINISHED_TIME | timestamp(6) | 克隆任務結束時間 |
RET_CODE | bigint(20) | 克隆任務返回值 |
ERROR_MESSAGE | varchar(512) | 克隆任務失敗時的提示信息,允許為空 |
示例:
MySQL [(none)]> select * from oceanbase.DBA_OB_CLONE_PROGRESS\G
*************************** 1. row ***************************CLONE_JOB_ID: 1702211800546509768TRACE_ID: YA4740B7C050F-00060C210F4A4848-0-0SOURCE_TENANT_ID: 1004SOURCE_TENANT_NAME: mysqlCLONE_TENANT_ID: 1016CLONE_TENANT_NAME: clone_tntTENANT_SNAPSHOT_ID: 1702211800802135214
TENANT_SNAPSHOT_NAME: _inner_snapshot$1702211800702058206RESOURCE_POOL_ID: 1008RESOURCE_POOL_NAME: clone_tnt_poolUNIT_CONFIG_NAME: box8RESTORE_SCN: 1702211802014048020STATUS: CLONE_SYS_CREATE_TENANTCLONE_JOB_TYPE: FORKCLONE_START_TIME: 2023-12-10 20:36:40.551169CLONE_FINISHED_TIME: NULLRET_CODE: NULLERROR_MESSAGE: NULL
1 row in set (0.00 sec)MySQL [(none)]> select * from oceanbase.DBA_OB_CLONE_HISTORY where CLONE_JOB_ID = 1702211800546509768\G
*************************** 1. row ***************************CLONE_JOB_ID: 1702211800546509768TRACE_ID: YA4740B7C050F-00060C210F4A4848-0-0SOURCE_TENANT_ID: 1004SOURCE_TENANT_NAME: mysqlCLONE_TENANT_ID: 1016CLONE_TENANT_NAME: clone_tntTENANT_SNAPSHOT_ID: 1702211800802135214
TENANT_SNAPSHOT_NAME: _inner_snapshot$1702211800702058206RESOURCE_POOL_ID: 1008RESOURCE_POOL_NAME: clone_tnt_poolUNIT_CONFIG_NAME: box8RESTORE_SCN: 1702211802014048020STATUS: CLONE_SYS_SUCCESSCLONE_JOB_TYPE: FORKCLONE_START_TIME: 2023-12-10 20:36:40.551169CLONE_FINISHED_TIME: 2023-12-10 20:37:53.919247RET_CODE: 0ERROR_MESSAGE: NULL
1 row in set (0.01 sec)
- 取消租戶克隆任務。
可以通過執行 ALTER SYSTEM CANCEL CLONE new_tenant_name 語句,以取消一個正在執行的克隆任務;該語句會顯式的將對應的克隆任務切換到 CANCELING 的狀態(執行完成后置為CANCELED狀態),同時當該克隆任務被取消之后,其申請的各類資源都會被自動釋放。
若在該 ALTER SYSTEM CANCEL CLONE new_tenant_name 語句執行之前,新克隆租戶已經實際執行完成了克隆操作,切換到了正常服務狀態,則該 CANCEL 語句不會被執行。
示例:
MySQL [(none)]> alter system cancel clone clone_tnt;
Query OK, 0 rows affected (0.02 sec)MySQL [oceanbase]> create tenant clone_tnt from mysql with resource_pool="clone_tnt_pool",unit=box8;
ERROR 12004 (HY000): clone job has been canceledMySQL [(none)]> select * from oceanbase.DBA_OB_CLONE_HISTORY where CLONE_JOB_ID=1702212525544202404\G
*************************** 1. row ***************************CLONE_JOB_ID: 1702212525544202404TRACE_ID: YA4740B7C050F-00060C210F4A4859-0-0SOURCE_TENANT_ID: 1004SOURCE_TENANT_NAME: mysqlCLONE_TENANT_ID: 0CLONE_TENANT_NAME: clone_tntTENANT_SNAPSHOT_ID: 1702212525756306747
TENANT_SNAPSHOT_NAME: _inner_snapshot$1702212525656187169RESOURCE_POOL_ID: 1009RESOURCE_POOL_NAME: clone_tnt_poolUNIT_CONFIG_NAME: box8RESTORE_SCN: 18446744073709551615STATUS: CLONE_SYS_CANCELEDCLONE_JOB_TYPE: FORKCLONE_START_TIME: 2023-12-10 20:48:45.544031CLONE_FINISHED_TIME: 2023-12-10 20:48:51.070501RET_CODE: -4072ERROR_MESSAGE: clone job has been canceled
1 row in set (0.00 sec)
執行完“取消克隆租戶”命令后,該 clone_tenant 對應的克隆任務切換到 CLONE_SYS_CANCELED 的狀態,該克隆任務申請的各類資源(比如:租戶快照、資源池以及處于克隆狀態的租戶)都會被自動釋放。
- 注意事項。
源租戶和新克隆租戶,在初始狀態下是共享物理宏塊,后續隨著源租戶的寫入,新克隆租戶的寫入,以及二者的遷移調度和故障恢復等事件的發生,會使得兩個租戶共享的宏塊逐步減少,獨占宏塊逐步增多,存儲空間使用量逐步增加。
租戶克隆特點
租戶克隆功能加速了任務執行效率的同時降低了任務帶來的風險,總的來說,該功能具有以下4個特點。
特點1:快。租戶克隆過程中,只拷貝元數據信息,不拷貝數據信息,使得租戶克隆操作可以快速完成。在我們的測試環境中,8核64G 的源租戶,包含 50w tablet,1TB 數據,克隆出一個 8c64g 的新租戶,可以在 2min 內完成。
特點2:易。只需要在系統租戶中,執行一條租戶克隆語句,就可以完成租戶克隆操作。同時 OceanBase 的租戶克隆是完全實現在數據庫內核中,不需要外部存儲系統的支持,只需要在平時用的機器上,拉起OceanBase 4.3 版本的進程,就可以用上租戶克隆功能。
特點3:穩。租戶克隆過程,不會阻塞源租戶正常的 SQL 執行。克隆出的新租戶和源租戶是兩個完全獨立的租戶,存在嚴格的數據隔離和資源隔離,不會互相影響。
特點4:省。新克隆租戶會盡可能的和源租戶共享宏塊,最大限度的節省存儲資源。
更多關于租戶克隆的信息可參見官網文檔?,