OceanBase 原始碼解讀(五):租戶的一生

OceanBase資料庫發表於2021-11-10
厭離,畢業於西北工業大學,現主要負責 OceanBase-RS 有關工作。

原始碼是 OceanBase 的“方向盤”,本系列主要圍繞“原始碼解讀”,通過文章闡述,幫助大家理清資料庫的內在本質。本文為 OceanBase 資料庫原始碼解讀系列文章的第五篇,將介紹社群版中建立、刪除租戶、資源隔離的相關程式碼。

OceanBase 資料庫是支援多租戶的,這裡租戶的概念類似於傳統資料庫的資料庫例項。租戶下可以建立資料庫,在租戶的資料庫下可以建立表。

多租戶特性可以降低資源使用和維護成本。每個租戶可以被賦於一定的資源(比如 CPU、記憶體)。OceanBase叢集初始內建了一個系統租戶 sys,可以用來管理OceanBase 叢集。租戶的資源是分配在資源池上的,通過資源配置和設定資源池可以實現對租戶資源的控制。

在建立租戶之前,需要至少一個空閒的資源池;建立資源池需要先定義每個單元的規格。

我們稱一個資源單元為 UNIT,UNIT是最小的資源分割單位。一個資源池中包含若干 UNIT,一臺Observer 只能有一個資源池的一個 UNIT。一個資源池只能賦予給一個租戶,一個租戶可以包含多個資源池。

略過 SQL 的解析和處理,這部分的主體程式碼都是在 rootserver 目錄下,統一的入口請點選 閱讀原文檢視。大概涉及到以下介面:

OceanBase 原始碼解讀(五):租戶的一生

create resource unit

SQL參考:

1. CREATE RESOURCE UNIT unitname 
2. MAX_CPU [=] cpunum,
3. MAX_MEMORY [=] memsize, 
4. MAX_IOPS [=] iopsnum, 
5. MAX_DISK_SIZE [=] disksize, 
6. MAX_SESSION_NUM [=] sessionnum, 
7. [MIN_CPU [=] cpunum,]
8. [MIN_MEMORY [=] memsize,] 
9. [MIN_IOPS [=] iopsnum]

這部分程式碼比較簡單,建立一個 UNIT 規格,就是把這個規格記錄在內部表(__all_unit_config)。在沒有任何資源池引用這個規格時,它並沒有什麼用,可以隨意的修改或者刪除。

程式碼上可以從這個介面去閱讀:

int ObRootService::create_resource_unit(const obrpc::ObCreateResourceUnitArg& arg)

create resource pool

SQL參考:

1. CREATE RESOURCE POOL poolname 
2. UNIT [=] unitname, 
3. UNIT_NUM [=] unitnum, 
4. ZONE_LIST [=] (‘zone’ [, ‘zone’ …]);

建立資源池需要定義這個資源池引用的規格,這個資源處分佈在哪幾個 zone,每個 zone 存在幾個 UNIT,這裡的重點是要在哪些 server 上把這部分 UNIT 分配出來。

可以從這個介面去閱讀:

int ObRootService::create_resource_pool(const obrpc::ObCreateResourcePoolArg& arg)

這裡涉及到的內部表有:__all_resource_pool、__all_unit。

具體如何分配 UNIT 可以參考這個介面:

int ObUnitManager::allocate_pool_units(ObISQLClient& client, const share::ObResourcePool& pool)

create tenant

SQL參考:

CREATE TENANT [IF NOT EXISTS] tenantname      [tenant_characteristic_list] [opt_set_sys_var]tenant_characteristic_list: tenant_characteristic [, tenant_characteristic...]tenant_characteristic: COMMENT 'string'  |{CHARACTER SET | CHARSET} [=] charsetname |COLLATE [=]  collationname|REPLICA_NUM [=] num |ZONE_LIST [=] (zone [, zone…]) |PRIMARY_ZONE [=] zone  |DEFAULT TABLEGROUP [=] {NULL | tablegroup}|RESOURCE_POOL_LIST [=](poolname [, poolname…])|LOGONLY_REPLICA_NUM [=] num|LOCALITY [=] 'locality description'opt_set_sys_var:{ SET | SET VARIABLES | VARIABLES } system_var_name = expr [,system_var_name = expr] ...

資源池建立成功後,就可以引用這個資源池建立租戶。建立租戶分為三個事務,為什麼要分為三個事務呢?

我們可以帶著這個問題從這個介面開始閱讀程式碼

int ObRootService::create_tenant(const ObCreateTenantArg& arg, UInt64& tenant_id)

三個事務可以從這個介面閱讀:

int ObDDLService::create_tenant_env(share::schema::ObSchemaGetterGuard& schema_guard, const obrpc::ObCreateTenantArg& arg,
      const common::ObRegion& region, share::schema::ObTenantSchema& tenant_schema, const int64_t frozen_version,
      const common::ObString* ddl_stmt_str = NULL);

事務一

確定租戶使用的資源池,並把這些資源池都賦予給這個租戶。構建了ObTenanSchema,包括租戶的 locality,primary_zone等資訊。建立這個租戶的系統表的 Partition;

事務二

這個事務是構建了租戶內部的資料,例如系統表的元資訊,內部使用者,database 等。大概包括以下內容:

OceanBase 原始碼解讀(五):租戶的一生


這個事務結束後,實際上租戶已經建立完成,可以正常使用。

事務三這個事務就是修改了租戶的建立,從CREATING到NORMAL。給出一個建立租戶結束的標記。

為什麼建立租戶需要三個事務?因為事務不能跨租戶。

drop tenant

SQL參考:

DROP TENANT [IF EXISTS] tenant_name [FORCE];

刪除租戶實際上只刪除了租戶的ObTenanSchema。租戶刪除了,租戶引用的資源池還是存在的.

int ObRootService::drop_tenant(const ObDropTenantArg& arg)

drop resource pool

SQL參考:

DROP RESOURCE POOL poolname;

只有沒有租戶引用的資源池才可以被刪除

int ObRootService::drop_resource_pool(const obrpc::ObDropResourcePoolArg& arg)

drop resource unit

SQL參考:

DROP RESOURCE UNIT unitname;

只有沒有資源池引用的規格才可以被刪除,只涉及到內部表的修改,介面如下

int ObRootService::drop_resource_unit(const obrpc::ObDropResourceUnitArg& arg)

租戶隔離租戶的資源是互相隔離的,CPU 隔離和排程的程式碼位於 src/observer/omt。

OceanBase 原始碼解讀(五):租戶的一生

所有 OceanBase 的一級資料庫物件,如表,索引,database/schema,使用者等,在系統表和記憶體中都是用一個 uint64 作為 ID 標識的。為了實現方便,很多時候,在記憶體中這些 ID 裡編碼了租戶 ID,前 24bit是租戶ID。


如果大家有任何疑問,可以通過以下方式與我們進行交流:

微信群:掃碼新增小助手,將拉你進群喲~

釘釘群:33254054


github: github.com/oceanbase/oc

部落格問答: oceanbase.com/community

gitee: gitee.com/oceanbase


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70005215/viewspace-2795680/,如需轉載,請註明出處,否則將追究法律責任。

相關文章