This topic describes the multi-tenancy feature of PolarDB for PostgreSQL (Compatible with Oracle).
Terms
Tenant: In multi-tenancy, a tenant is a logical entity that represents a data and resource allocation unit. A tenant is at a higher level than a cluster and at a lower level than a user or a database. Multiple accounts or databases can correspond to one tenant. A tenant is different from a user or a database. Tenants are divided into two categories:
The system tenant is a special administrative entity. In general, only one system tenant is created. The system tenant can occupy the resources of common tenants. When a user of the system tenant connects to a database and if the user has the permissions to access clusters, the user can access the clusters of all tenants.
Common tenants: Their resources of a tenant are completely isolated from those of another tenant. Common tenants must be created by the system tenant.
Resource configuration: You can allocate resources such as CPU and memory resources for a tenant. The privileged account can specify resource limits for each tenant based on business requirements.
The tenant resource configuration feature is designed to limit the amount of resources used by a single process or multiple processes. In PolarDB for PostgreSQL (Compatible with Oracle), one session corresponds to one process. In one session, only one user can log on to one database. Processes, users, and databases are the basic elements of a tenant. Any process, user, and database can be mapped to a specified tenant. A process can belong to only one tenant, avoiding duplicate statistics of resource usage. The child processes of a parallel query belongs to the tenant that initiates the parallel query. Therefore, resources can be limited in three dimensions based on process attributes:
Process: the connection process (session process) initiated by a user. Such processes include parallel query processes, but do not include the system auxiliary processes.
User: all connection processes (session processes) initiated by a user. They include parallel query processes, but do not include the system auxiliary processes.
Database: all connection processes (session processes) to one database initiated by users. They include parallel query processes, but do not include the system auxiliary processes.
By default, no resource limit is imposed on system processes due to their special functionalities.
Prerequisites
Your PolarDB for PostgreSQL (Compatible with Oracle) cluster runs the following engine:
PolarDB for PostgreSQL (Compatible with Oracle) 2.0 (revision version 2.0.14.24.0 or later)
You can execute the following statement to view the revision version of your PolarDB for PostgreSQL (Compatible with Oracle) cluster:
SHOW polar_version; Parameters
Parameter | Description | Application mode |
polar_max_tenants | The maximum number of tenants. Valid values: 0 to 65536. Default value: 32. | The setting takes effect after the cluster restarts. |
polar_resource_manager.enable_resource_manager | Specifies whether to enable the resource manager process for memory limit and OOM prevention. Default value: on. | The setting takes effect after the cluster restarts. |
polar_resource_manager.database_name | The name of the database that stores the tenant metadata. Default value: | The setting takes effect after the cluster restarts. |
polar_resource_manager.stat_interval | The data collection interval. Unit: ms. Valid values: 10 to 10000. Default value: 500 ms. | The setting takes effect after the reload operation is performed. |
polar_resource_manager.total_mem_request_rate | The threshold for active eviction. Valid values: 50% to 100%. Default value: 80%. | The setting takes effect after the reload operation is performed. |
polar_resource_manager.total_mem_limit_rate | The threshold for forced conviction. Valid values: 50% to 100%. Default value: 95%. | The setting takes effect after the reload operation is performed. |
polar_resource_manager.total_mem_limit_remain_size | The size of reserved memory. Valid values: 131072 to INT_MAX (the maximum value of the integer data type). Unit: KB. Default value: 256000. | The setting takes effect after the reload operation is performed. |
polar_resource_manager.enable_log | Specifies whether to enable logs. Valid values:
| The setting takes effect after the reload operation is performed. |
Usage
To use multi-tenancy, you must create the polar_resource_manager extension in the database for which you specify the polar_resource_manager.database_name parameter.
If you modify the name of the polar_resource_manager.database_name database that stores tenant metadata, the existing multi-tenancy settings become invalid.
CREATE EXTENSION polar_resource_manager;Create a resource configuration
You can create a resource configuration by using the polar_create_resource_config function.
SELECT polar_resource_manager.polar_create_resource_config('resource_config_name');The resource_config_name parameter must meet the requirements for database names: They can be up to 64 characters in length. Otherwise, they are automatically truncated.
Delete a resource configuration
You can create a resource configuration by using the polar_drop_resource_config function.
SELECT polar_resource_manager.polar_drop_resource_config('resource_config_name');Modify a resource configuration
You can create a resource configuration by using the polar_alter_resource_config function.
SELECT polar_resource_manager.polar_alter_resource_config('resource_config_name', 'config_name', value);Valid values for the config_name parameter:
cpu_rate_limit: the CPU limit, in units of CPU cores.mem_limit, the memory limit, in bytes.
Create a tenant
You can create a tenant by using the polar_create_tenant function.
SELECT polar_resource_manager.polar_create_tenant('tenant_name', 'resource_config_name');
The
tenant_nameparameter must meet the requirements for database names: They can be up to 64 characters in length. Otherwise, they are automatically truncated.The
resource_config_namevalue must be of an existing resource configuration. Otherwise, the tenant cannot be created.
Delete a tenant
You can create a tenant by using the polar_drop_tenant function. After you delete a tenant, the resource configuration remains.
SELECT polar_resource_manager.polar_drop_tenant('tenant_name');Modify a tenant
You can create a tenant by using the polar_alter_tenant function.
SELECT polar_resource_manager.polar_alter_tenant('tenant_name', 'config_name', 'value');Valid values for the config_name parameter:
name: the tenant name.resource_config: the resource configuration.
Assign a database to a tenant
You can assign a database to a tenant by using the polar_tenant_add_database function. A database can be assigned to only one tenant. You cannot assign a database to multiple tenant.
SELECT polar_resource_manager.polar_tenant_add_database('tenant_name', 'database_name');View databases and their tenants
You can view databases and their tenants by using the polar_tenants_dbs function.
SELECT dbsname, tenantname FROM polar_resource_manager.polar_tenants_dbs;Assign a user to a tenant
You can assign a database to a tenant by using the polar_tenant_add_user function. A user can be assigned to only one tenant. You cannot assign a user to multiple tenant.
SELECT polar_resource_manager.polar_tenant_add_user('tenant_name', 'user_name');View users and their tenants
You can view users and their tenants by using the polar_tenants_users function.
SELECT username, tenantname FROM polar_resource_manager.polar_tenants_users;Assign a process to a tenant
You can assign a database to a tenant by using the polar_tenant_add_process function. A process can be assigned to only one tenant. If you assign a process to multiple tenant, only the last assignment is valid.
SELECT polar_resource_manager.polar_tenant_add_process('tenant_name', pid);View tenant resources
You can view tenant resources by using the polar_all_resource_configs_detail view.
SELECT * FROM polar_resource_manager.polar_all_resource_configs_detail;The following table describes the columns of the view.
Column name | Column type | Description |
tenantname | NAME | The tenant name. |
resource_config_name | NAME | The name of the resource configuration. |
num_processes | INTEGER | The number of the processes. |
num_idle_processes | INTEGER | The number of idle processes. |
num_active_processes | INTEGER | The number of active processes. |
cpu_rate_limit | DOUBLE PRESISION | The maximum CPU resources of the tenant. |
per_process_cpu_rate_limit | DOUBLE PRESISION | The maximum CPU resources of the process. |
mem_limit | DOUBLE PRESISION | The maximum memory resources. |
mem_usage | DOUBLE PRESISION | The memory usage. |
idle_processes_mem_usage | DOUBLE PRESISION | The memory usage by idle processes. |
active_processes_mem_usage | DOUBLE PRESISION | The memory usage by active processes. |
cpu_usage_rate | DOUBLE PRESISION | The CPU utilization (%). |
CPU resource management
After you add processes, users, and databases to a tenant, you can set the CPU limit in a resource configuration. If background child processes can be allocated, they are assigned to the tenant that initiates the parallel query, so that background child processes and session processes both are subject to the resources limit of the tenant. When the parallel query is completed, background child processes are removed from the tenant. This mechanism dynamically imposes and removes resource limits on the tenant.
CPU usage limit
You can set the maximum CPU usage for a tenant. If the CPU usage limit is exceeded in a tenant, the cluster lowers CPU consumption to make it fall within the limit.
You can set the cpu_rate_limit value (which is of the float data type) by using the polar_resource_manager.polar_alter_resource_config function.
The parameter value indicates the CPU usage over a period of time. For example, 0.3 indicates 30% usage of one core and 2 indicates full usage of 2 cores. Because you specify the maximum CPU usage values here, the sum of cpu_limit values can be greater than the cluster specification value T: cpu_limit_A + cpu_limit_B + cpu_limit_C + ... >= T.
Memory resource management
Memory is a rigid resource and cannot be dynamically limited in the same way as CPU. If the memory usage limit is exceeded, the system terminates processes to release memory resources. This mechanism is similar to how an operating system handles OOM issues, but this limit is set for a tenant instead of for the entire database.
Memory usage limit
You can set the mem_limit value (which is of the float data type) by using the polar_resource_manager.polar_alter_resource_config function. Similarly, because you specify the maximum memory usage values here, the sum of mem_limit values can be greater than the cluster specification value. The following two policies can be used:
Active threshold management: When the active eviction threshold (
total_mem_request_rate, which defaults to 80%) is exceeded and if the memory usage of the tenant is greater than the specified limit, the session is terminated to release memory resources. A memory overrun error is returned. The system continues this mechanism until the memory usage is smaller than the active eviction threshold.Forced threshold management: If the forced eviction threshold (
total_mem_limit_rate, which defaults to 95%) is exceeded, the system traverses all processes, releases the resources of the session, and returns a memory overrun error. This prevents OOM errors in the cluster.
During the eviction, the user session is terminated and the resources consumed by the process are released. The system terminates the session by sending the SIGUSR2 signal to the session process and returns a specified OOM error. If the memory usage of the background process of a parallel query exceeds the memory limit, the corresponding user process is terminated. Currently, only user processes can be terminated. System background processes belong to the system tenant and cannot be terminated to release memory resources.