×
Community Blog An Interpretation of the Source Code of OceanBase (5): Life of Tenant

An Interpretation of the Source Code of OceanBase (5): Life of Tenant

This article explains information related to the multi-tenant architecture of OceanBase.

By Yanli

The fourth article in this series (Interpretation of the Source Code of OceanBase (4): Life of Transaction) was about the external interface of transactions. This article describes the codes for creating and deleting tenants and isolating resources in Community.

OceanBase supports multi-tenancy. The concept of tenancy is similar to database instances of traditional databases. You can create a database under a tenant and create a table under the database.

The feature of multi-tenancy helps reduce resource usage and maintenance costs. Each tenant can be assigned certain resources (such as CPU and memory). A system tenant sys was originally built in the OceanBase cluster and can be used to manage the cluster. Resources in a tenant are allocated to resource pools. You can configure resources and resource pools to control the resources in a tenant.

Before creating a tenant, you need at least one empty resource pool. You need to define the specifications of each unit to create a resource pool.

We call a resource unit UNIT, which is the smallest resource unit. A resource pool contains several UNITs. An Observer only has one UNIT in one resource pool. A resource pool can only be assigned to one tenant, while a tenant can contain multiple resource pools. Skip the parsing and processing of SQL statements. The main code is in the rootserver directory. Click here for unified access.

The following interfaces are involved:

1

Create a Resource Unit

SQL Reference:

CREATE RESOURCE UNIT unitname 
MAX_CPU [=] cpunum, 
MAX_MEMORY [=] memsize, 
MAX_IOPS [=] iopsnum, 
MAX_DISK_SIZE [=] disksize, 
MAX_SESSION_NUM [=] sessionnum, 
[MIN_CPU [=] cpunum,]
[MIN_MEMORY [=] memsize,] 
[MIN_IOPS [=] iopsnum] ;

These codes are simple. Creating a UNIT specification is to include the specification in an internal table (__all_unit_config). When the specification is not referenced by a resource pool, the specification is useless and can be modified or deleted at will. You can read codes through this interface:

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

Create a Resource Pool

SQL Reference:

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

You need to define the specifications referenced by the resource pool to create a resource pool. Specifically, you need to specify the zones where the resource pool is located and the number of UNITs in each zone to clarify servers that denote where these UNITs are allocated.

You can read through this interface:

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

The internal tables involved here are: __all_resource_pool,__all_unit. Please see this interface for information about how to allocate UNITs:

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

Create a Tenant

SQL Reference:

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] ...

After a resource pool is created, you can reference this resource pool to create a tenant. You need three transactions to create a tenant. Why? You can read the code through this interface to find the answer:

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

You can read the three transactions through this interface:

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);

Transaction One

This is to determine the resource pool used by the tenant and assign these resource pools to the tenant. ObTenanSchema is constructed, including information about a tenant (such as a locality and primary_zone). Create partitions for the system table of the tenant.

Transaction Two

This is to construct the data inside the tenant, such as the metainformation of system tables, internal users, and databases. This includes the following content:

2

After the transaction ends, the tenant is created and can be used.

Transaction Three

This is to modify the creation of the tenant from CREATING to NORMAL. Mark the end of the creation of the tenant. Why are three transactions needed to create a tenant? It is because transactions cannot be conducted among different tenants.

Drop a Tenant

SQL Reference:

DROP TENANT [IF EXISTS] tenant_name [FORCE];

When a tenant is deleted, only the ObTenanSchema of the tenant is deleted. Resource pools referenced by the tenant still exist.

int ObRootService::drop_tenant(const ObDropTenantArg& arg)

Drop a Resource Pool

SQL Reference:

DROP RESOURCE POOL poolname;

Resource pools not referenced by the tenant can be deleted.

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

Drop a Resource Unit

SQL Reference:

DROP RESOURCE UNIT unitname;

Specifications not referenced by the resource pool can be deleted. Only the modification of internal tables is involved. The interface is listed below:

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

When a tenant is isolated, the resources of the tenant are isolated from each other. The code for CPU isolation and distribution is located in src/observer/omt.

3

All first-level database objects in OceanBase (such as tables, indexes, database/schema, and users) are identified by a uint64 as an ID in system tables and memory. For convenience, tenant IDs are often encoded in these IDs in memory. The first 24 bits are tenant IDs.

0 0 0
Share on

OceanBase

16 posts | 0 followers

You may also like

Comments