能力 | PostgreSQL 版本 | 支持版本 |
自定义开启多租户能力 | PostgreSQL 17 | v17.11_r1.26及以上 |
SHOW tencentdb_version; 查看当前实例的内核版本。shared_preload_libraries 参数中勾选 tencentdb_serverless,保存后重启实例。tencentdb_multi_tenant_mode 参数设置为 on。参数 | 级别 | 默认值 | 说明 |
tencentdb_multi_tenant_mode | postmaster | off | 多租户模式总开关,在控制台参数设置中修改,修改后需重启实例。 |
shared_preload_libraries | postmaster | - | 需勾选 tencentdb_serverless,在控制台参数设置中修改,修改后需重启实例。 |
tencentdb_multi_tenant_role_prefix | sighup | tencentdb_ | 多租户模式:管理角色的名称前缀,只有以该前缀开头的角色被视为管理身份(可远程登录、可持有 REPLICATION 权限、可行使 tencentdb_superuser 的权限),不受租户库视图隔离限制影响。 |
tencentdb_serverless.throttle_replay_database | postmaster | postgres | 资源隔离:限制配额回放工作进程读取限制配置的数据库,默认为 postgres 库。 |
min_cpu_cores/max_cpu_cores 参数,全部通过 tencentdb_serverless 的 SQL 接口按库设置。root(tencentdb_superuser 成员)、租户角色 tenant_a 及其数据库 tenant_a_db、公共只读角色 proxy_ro。pg_database、pg_roles 等系统视图看到全实例的库名、角色名等信息。视图隔离功能在共享系统表上启用行级安全(RLS)策略,让每个租户只能看到与本库相关的信息。被隔离的系统表 | 租户可见范围 |
pg_database(pg_database 视图) | 仅当前数据库 |
pg_authid(pg_roles、pg_user 等视图) | 本库属主角色及参数配置的额外角色 |
pg_auth_members(pg_auth_members 视图) | 可见角色之间的成员关系 |
pg_db_role_setting(pg_db_role_setting 视图) | 仅当前数据库的参数设置 |
pg_shdepend(pg_shdepend 视图) | 仅当前数据库的依赖关系 |
pg_shdescription(pg_shdescription 视图) | 仅当前数据库及可见角色的注释 |
pg_shseclabel(安全标签视图) | 仅当前数据库及可见角色的安全标签 |
pg_subscription(pg_subscription 视图) | 仅当前数据库的订阅 |
pg_tablespace(pg_tablespace 视图) | 仅当前数据库使用的表空间 |
postgres=# \\c tenant_a_db rootYou are now connected to database "tenant_a_db" as user "root".root=> CREATE EXTENSION tencentdb_serverless;CREATE EXTENSIONroot=> SELECT tencentdb_serverless.enable_system_view_isolation();NOTICE: policy "p_pg_database" for relation "pg_catalog.pg_database" does not exist, skippingNOTICE: policy "p_pg_authid" for relation "pg_catalog.pg_authid" does not exist, skippingNOTICE: policy "p_pg_auth_members" for relation "pg_catalog.pg_auth_members" does not exist, skippingNOTICE: policy "p_pg_db_role_setting" for relation "pg_catalog.pg_db_role_setting" does not exist, skippingNOTICE: policy "p_pg_shdepend" for relation "pg_catalog.pg_shdepend" does not exist, skippingNOTICE: policy "p_pg_shdescription" for relation "pg_catalog.pg_shdescription" does not exist, skippingNOTICE: policy "p_pg_seclabel" for relation "pg_catalog.pg_shseclabel" does not exist, skippingNOTICE: policy "p_pg_subscription" for relation "pg_catalog.pg_subscription" does not exist, skippingNOTICE: policy "p_pg_tablespace" for relation "pg_catalog.pg_tablespace" does not exist, skippingenable_system_view_isolation------------------------------(1 row)
DROP POLICY IF EXISTS,属正常提示。proxy_ro),由超级用户或管理员配置库级参数,多个角色以逗号分隔:postgres=# ALTER DATABASE tenant_a_db SET tencentdb_multi_tenant_visible_roles = 'tenant_a,proxy_ro';ALTER DATABASE
tenant_a=> SELECT datname FROM pg_database ORDER BY 1;datname-------------tenant_a_db(1 row)tenant_a=> SELECT rolname FROM pg_roles WHERE rolname NOT LIKE 'pg\\_%' ORDER BY 1;rolname----------proxy_rotenant_a(2 rows)tenant_a=> SELECT spcname FROM pg_tablespace ORDER BY 1;spcname------------pg_default(1 row)
root=> SELECT tencentdb_serverless.disable_system_view_isolation();disable_system_view_isolation-------------------------------(1 row)tenant_a=> SELECT datname FROM pg_database ORDER BY 1;datname-------------postgrestemplate0template1tenant_a_dbtenant_b_dbtenant_c_db(6 rows)
tenant_a_db。示例表 big_table(800万行)为租户库中的业务表,在租户库中创建:postgres=# \\c tenant_a_db rootYou are now connected to database "tenant_a_db" as user "root".root=> CREATE TABLE big_table AS SELECT g FROM generate_series(1, 8000000) g;SELECT 8000000root=> ANALYZE big_table;ANALYZE
set_database_cpu_limit 的参数依次为:数据库名、CPU 下限(预留下限,当前版本暂不启用)、CPU 上限。以下将租户库限制为最多0.5核:root=> SELECT tencentdb_serverless.set_database_cpu_limit('tenant_a_db', 0.1, 0.5);set_database_cpu_limit------------------------(1 row)
root=> SELECT * FROM tencentdb_serverless.resource_limit_view;database_name | min_cpu_cores | max_cpu_cores | min_mem_kilobytes | max_mem_kilobytes---------------+---------------+---------------+-------------------+-------------------tenant_a_db | 0.1 | 0.5 | |(1 row)
min_mem_kilobytes、max_mem_kilobytes 为预留列,当前版本不使用。root=> SELECT * FROM tencentdb_serverless.get_cpu_throttle_usage('tenant_a_db');cpu_limit | cpu_usage_rate | throttled_count | throttled_time_ms-----------+----------------+-----------------+-------------------0.5 | 0 | 0 | 0(1 row)
cpu_limit:当前生效的 CPU 上限(核)。cpu_usage_rate:近5秒观测窗口内该库的 CPU 平均使用核数。throttled_count:该库自首次设置限制以来累计触发限流的次数。throttled_time_ms:该库自首次设置限制以来累计因限流而等待的毫秒数。root=> EXPLAIN (ANALYZE, COSTS OFF) SELECT count(*) FROM big_table;QUERY PLAN----------------------------------------------------------------------------------------------------Finalize Aggregate (actual time=409.405..410.836 rows=1 loops=1)-> Gather (actual time=409.301..410.824 rows=3 loops=1)Workers Planned: 2Workers Launched: 2-> Partial Aggregate (actual time=407.081..407.083 rows=1 loops=3)-> Parallel Seq Scan on big_table (actual time=0.033..247.186 rows=2666667 loops=3)Planning Time: 0.212 msExecution Time: 410.958 ms(8 rows)
root=> SELECT tencentdb_serverless.set_database_cpu_limit('tenant_a_db', 0.1, 0.1);set_database_cpu_limit------------------------(1 row)root=> EXPLAIN (ANALYZE, COSTS OFF) SELECT count(*) FROM big_table;QUERY PLAN------------------------------------------------------------------------------------------------------Finalize Aggregate (actual time=10422.597..10424.092 rows=1 loops=1)-> Gather (actual time=10422.498..10424.083 rows=3 loops=1)Workers Planned: 2Workers Launched: 2-> Partial Aggregate (actual time=10420.262..10420.264 rows=1 loops=3)-> Parallel Seq Scan on big_table (actual time=0.030..10276.123 rows=2666667 loops=3)Planning Time: 0.215 msExecution Time: 10424.213 ms(8 rows)
root=> SELECT * FROM tencentdb_serverless.get_cpu_throttle_usage('tenant_a_db');cpu_limit | cpu_usage_rate | throttled_count | throttled_time_ms-----------+---------------------+-----------------+-------------------0.1 | 0.09571135357027115 | 328 | 46545.3(1 row)
cpu_usage_rate 针对该库全部会话统一记账,因此整体被压在上限附近。root=> SELECT tencentdb_serverless.reset_database_limit('tenant_a_db');reset_database_limit----------------------(1 row)root=> SELECT * FROM tencentdb_serverless.resource_limit_view;database_name | min_cpu_cores | max_cpu_cores | min_mem_kilobytes | max_mem_kilobytes---------------+---------------+---------------+-------------------+-------------------(0 rows)
tencentdb_serverless.reset_all_database_limit() 一次性删除实例内所有限制。root=> SELECT tencentdb_serverless.set_database_cpu_limit('db_not_exists', 0.1, 0.5);ERROR: Database db_not_exists does not exist.CONTEXT: PL/pgSQL function tencentdb_serverless.set_database_cpu_limit(text,numeric,numeric) line 9 at RAISE
root=> SELECT tencentdb_serverless.set_database_cpu_limit('tenant_a_db', 0.5, 0.1);ERROR: max_cpu_cores should larger than min_cpu_cores.CONTEXT: PL/pgSQL function tencentdb_serverless.set_database_cpu_limit(text,numeric,numeric) line 28 at RAISE
ALTER DATABASE ... SET tencentdb_multi_tenant_visible_roles,将角色加入列表,租户重连后生效。get_cpu_throttle_usage 确认是否发生了限流。throttled_count 与 throttled_time_ms 为该库自首次设置限制以来的累计值,删除限制不会清零。文档反馈