租户隔离

更新时间:
复制为 MD 格式

在多租户业务场景下,部分“热点租户”因数据量或访问量过高,会抢占其所在节点的计算与存储资源,影响同一节点上其他租户的查询性能。PolarDB PostgreSQL分布式版提供租户隔离功能,允许您将指定租户的数据在线迁移至独立的节点,为其分配专用资源,从而彻底解决资源争抢问题,保障所有租户的性能与稳定性。

功能简介

在标准的多租户架构中,为最大化资源利用率,PolarDB PostgreSQL分布式版会将不同租户的数据均匀分布在集群的各个数据节点(DN)上。这意味着多个租户会共享同一个节点的存储和计算资源。

然而,当集群中出现“热点租户”(通常指数据量或访问负载远超其他租户的租户)时,这种共享模式会引发一系列问题:

  • 资源争用:热点租户的高频查询会过度消耗其所在节点的CPU、内存和I/O资源,导致同一节点上的其他邻居租户查询性能显著下降。

  • 性能抖动:热点租户的突发流量可能导致其他冷租户的查询延迟显著增加,影响体验。

  • 存储失衡:热点租户的庞大数据量可能导致部分节点的存储使用率远高于其他节点,造成资源浪费和管理复杂性。

租户隔离功能通过物理迁移数据的方式,为您提供解决上述问题的有效手段。您可以将热点租户的数据(分片或Schema)迁移到一个独立的、资源富余的节点上,实现资源隔离。

优势

  • 专用资源保障:将热点租户隔离到专属节点,避免其与其他租户争抢资源,确保核心业务的性能与稳定性。

  • 提升整体性能:通过均衡节点负载,消除资源瓶颈,从而提升整个集群的服务性能和稳定性。

  • 在线平滑迁移:租户隔离的数据迁移过程在线进行,对业务的读写操作(DML/DQL)无阻塞,不影响业务连续性。

  • 迁移策略灵活:您可以选择将热点租户迁移到新节点,也可以选择将节点上的其他冷租户迁出,以腾出整个节点专用于热点租户。

注意事项

  • 在执行数据迁移期间,源节点和目标节点的资源负载(如CPU、IO、网络)会升高。建议您在业务低峰期执行此操作。

  • 在执行迁移前,请确保目标节点有足够的存储空间来容纳待迁移的数据。

水平拆分(基于分片)

对于按租户ID(tenant_id)进行水平拆分的表,您可以先为热点租户创建一个专属分片,然后将该分片迁移至目标节点。

步骤一:创建租户专属分片

执行isolate_tenant_to_new_shard函数,为指定租户的数据创建一个新的独立分片。

语法

SELECT isolate_tenant_to_new_shard('<分布表名>', '<租户ID>', 'CASCADE');

示例

  1. 准备数据:

    CREATE TABLE orders (
        order_id     BIGSERIAL,          -- 订单ID,自增
        store_id     INT NOT NULL,       -- 店铺ID,将作为分布键(租户ID)
        product_name VARCHAR(255),       -- 商品名称
        amount       DECIMAL(10, 2),     -- 订单金额
        order_time   TIMESTAMPTZ DEFAULT NOW(), -- 下单时间
        PRIMARY KEY (order_id, store_id) -- 注意:分布键必须是主键的一部分
    );
    
    -- 将'orders'表定义为分布式表,并以'store_id'列进行水平拆分
    SELECT create_distributed_table('orders', 'store_id');
    
    -- 为店铺101插入5条订单
    INSERT INTO orders (store_id, product_name, amount)
    SELECT 101, '笔记本电脑 - ' || i, 4999.00 + i FROM generate_series(1, 5) i;
    
    -- 为店铺102插入5条订单
    INSERT INTO orders (store_id, product_name, amount)
    SELECT 102, '机械键盘 - ' || i, 899.00 + i FROM generate_series(1, 5) i;
  2. 执行命令:

    -- 示例:为分布表't'中的租户'101'创建隔离分片
    SELECT isolate_tenant_to_new_shard('orders', '102', 'CASCADE');
  3. 查看结果:
    函数会返回新创建的分片ID。

     isolate_tenant_to_new_shard
    -----------------------------
                          102108

    此时,ID102108的分片已创建,但它仍位于原始节点上,需要执行下一步才能完成隔离。

步骤二:迁移分片至目标节点

执行polar_cluster_move_shard_placement函数,将上一步创建的专属分片迁移至资源富余的目标节点。您可以根据实际情况选择以下任一策略。

语法

SELECT polar_cluster_move_shard_placement(
    <分片ID>, 
    '<源节点IP>',
    <源节点端口>, 
    '<目标节点IP>', 
    <目标节点端口>
 );

迁移策略

迁移热点租户分片

这是最直接的方式。将热点租户的专属分片从当前节点移动到目标节点。

  1. 查询热点分片当前位置:

    -- 将102108替换为您在上一步获取的分片ID
    SELECT nodename, nodeport FROM pg_dist_shard_placement WHERE shardid = 102108;

    查看结果:

    nodename  | nodeport
    ----------+----------
    10.0.0.1  |     5432
  2. 执行迁移命令:

    -- 示例:将分片10210810.0.0.1:5432迁移到10.0.0.2:5432
    SELECT polar_cluster_move_shard_placement(102108, '10.0.0.1', 5432, '10.0.0.2', 5432);

迁移非热点租户分片

如果您希望将当前节点完全释放给热点租户,也可以将该节点上的其他所有非热点分片迁移出去。

  1. 查询热点节点上的所有非热点分片:

    -- 将102108替换为热点分片ID,'10.0.0.1'和5432替换为热点节点信息
    SELECT shardid, shard_size
     FROM polar_cluster_shards
     WHERE table_name::text = 't' AND
           shardid <> 102108 AND
           nodename = '10.0.0.1' AND nodeport = 5432
     ORDER BY shard_size ASC, shardid ASC;

    查看结果:

     shardid | shard_size
    ---------+------------
      102104 |       8192
      102105 |      16384
      102106 |   83820544
      102107 |  256344064
  2. 逐个迁移非热点分片:
    根据查询结果,依次将这些分片迁移到目标节点。

    SELECT polar_cluster_move_shard_placement(102104, '10.0.0.1', 5432, '10.0.0.2', 5432);
    SELECT polar_cluster_move_shard_placement(102105, '10.0.0.1', 5432, '10.0.0.2', 5432);
    ...

垂直拆分(基于Schema)

对于每个租户的数据存储在独立Schema的垂直拆分场景,隔离操作更为简单。您只需将热点租户对应的整个Schema迁移到目标节点即可。

语法

SELECT polar_cluster_schema_move(
    '<Schema名称>', 
    '<目标节点IP>', 
    <目标节点端口>
);

示例

  1. 准备数据:

    -- 新的SCHEMA company1
    CREATE SCHEMA company1;
    
    -- 定义一个分布式Schema
    SELECT polar_cluster_schema_distribute('company1');
    
    -- 创建测试表
    CREATE TABLE company1.users (id SERIAL, name TEXT);
  2. 从以下SELECT语句查询计划示例可以看出,特定租户的查询只会访问特定节点(计划中表明,唯一要访问的DN节点为10.0.0.1:5432):

    EXPLAIN SELECT * FROM company1.users WHERE id = 1;
                                       QUERY PLAN
    --------------------------------------------------------------------------------
     Custom Scan (PolarCluster Adaptive)  (cost=0.00..0.00 rows=0 width=0)
       Task Count: 1
       Tasks Shown: All
       ->  Task
             Node: host=10.0.0.1 port=5432 dbname=postgres
             ->  Seq Scan on users_102010 users  (cost=0.00..25.88 rows=6 width=36)
                   Filter: (id = 1)
  3. 使用polar_cluster_schema_move函数执行迁移。

    -- 示例:将Schema 'company1'迁移到节点10.0.0.2:5432
    SELECT polar_cluster_schema_move('company1', '10.0.0.2', 5432);