Doris的多租户和资源隔离方案,主要目的是为了多用户在同一Doris集群内进行数据操作时,减少相互之间的干扰,能够将集群资源更合理的分配给各用户。该方案主要分为两部分,一是集群内节点级别的资源组划分,二是针对单个查询的资源限制。本文介绍节点与资源划分。

Doris中的节点

Doris集群中有两类节点:Frontend(FE)和Backend(BE)。
  • FE主要负责元数据管理、集群管理、用户请求的接入和查询计划的解析等工作。
  • BE主要负责数据存储、查询计划的执行等工作。

FE不参与数据的处理计算等工作,因此是一个资源消耗较低的节点。而BE负责所有的数据计算、任务处理,属于资源消耗型的节点。因此,本文所介绍的资源划分及资源限制方案,适用于BE节点。FE节点因为资源消耗相对较低,并且还可以横向扩展,通常无需做资源上的隔离和限制,由所有用户共享即可。

说明 本文部分内容来源于Apache Doris,详情请参见多租户和资源划分

节点资源划分

节点资源划分,是指将一个Doris集群内的BE节点设置标签(Tag),标签相同的BE节点组成一个资源组(Resource Group)。资源组可以看作是数据存储和计算的一个管理单元。下面通过一个具体示例,来介绍资源组的使用方式。

  1. 为BE节点设置标签。例如当前Doris集群有6个BE节点。分别为host[1-6]。在初始情况下,所有节点都属于一个默认资源组(Default)。您可以使用以下命令将这6个节点划分成3个资源组group_a、group_b、group_c,其中将host[1-2]组成资源组group_a,host[3-4]组成资源组group_b,host[5-6]组成资源组group_c。
    alter system modify backend "host1:9050" set ("tag.location" = "group_a");
    alter system modify backend "host2:9050" set ("tag.location" = "group_a");
    alter system modify backend "host3:9050" set ("tag.location" = "group_b");
    alter system modify backend "host4:9050" set ("tag.location" = "group_b");
    alter system modify backend "host5:9050" set ("tag.location" = "group_c");
    alter system modify backend "host6:9050" set ("tag.location" = "group_c");
    说明 一个BE只支持设置一个Tag。
  2. 按照资源组分配数据。分布资源组划分好后,可以将用户数据的不同副本分布在不同资源组内。例如一张用户表 UserTable,在3个资源组内各存放一个副本,则可以通过如下建表语句实现。
    create table UserTable
    (k1 int, k2 int)
    distributed by hash(k1) buckets 1
    properties(
        "replication_allocation"="tag.location.group_a:1, tag.location.group_b:1, tag.location.group_c:1"
    )
  3. 使用不同资源组进行数据查询。

    在前两步执行完成后,您就可以通过设置用户的资源使用权限,来限制某一用户的查询。

    说明 只能使用指定资源组中的节点来执行。

    例如可以通过以下语句,限制user1只能使用group_a资源组中的节点进行数据查询,user2只能使用group_b资源组,而user3可以同时使用3个资源组。

    set property for 'user1' 'resource_tags.location' = 'group_a';
    set property for 'user2' 'resource_tags.location' = 'group_b';
    set property for 'user3' 'resource_tags.location' = 'group_a, group_b, group_c';

    设置完成后,user1在发起对UserTable表的查询时,只会访问group_a资源组内节点上的数据副本,并且查询仅会使用group_a资源组内的节点计算资源。而user3的查询可以使用任意资源组内的副本和计算资源。

    通过对节点的划分,以及对用户的资源使用限制,实现了不同用户查询上的物理资源隔离。可以给不同的业务部门创建不同的用户,并限制每个用户使用不同的资源组。以避免不同业务部分之间使用资源干扰。例如集群内有一张业务表需要共享给所有9个业务部门使用,但是希望能够尽量避免不同部门之间的资源抢占。您可以为这张表创建3个副本,分别存储在3个资源组中。然后为9个业务部门创建9个用户,每3个用户限制使用一个资源组。这样,资源的竞争程度就由9降低到了3。

    其次,针对在线和离线任务的隔离。您可以利用资源组的方式实现。例如可以将节点划分为Online和Offline两个资源组。表数据依然以3副本的方式存储,其中2个副本存放在Online资源组,1个副本存放在Offline资源组。Online资源组主要用于高并发低延迟的在线数据服务,而一些大查询或离线ETL操作,则可以使用Offline资源组中的节点执行。从而实现在统一集群内同时提供在线和离线服务的能力。

  4. 导入作业的资源组分配。导入作业(包括Insert、Broker Load、Routine Load、Stream Load等)的资源使用可以分为计算资源和写入资源两部分。所以对于导入作业的资源组的分配分成两个步骤。如果希望导入操作所使用的全部资源都限定在数据所在的资源组的话,只需将用户级别的Resource Tag设置为和副本的Resource Tag相同即可。
    • 计算资源:负责读取数据源、数据转换和分发。理论上可以选择任意节点完成。
    • 写入资源:负责数据编码、压缩并写入磁盘。必须是数据副本所在的节点。
    • 使用用户级别的Resource Tag来限定计算资源所能使用的资源组。
    • 使用副本的Resource Tag来限定写入资源所能使用的资源组。

单查询资源限制

上面的资源组方法是节点级别的资源隔离和限制,但在资源组内也可能发生资源抢占问题。例如,上面所述的将3个业务部门安排在同一资源组内的示例,虽然该方法降低了资源竞争程度,但是3个部门的查询依然有可能相互影响。

因此,除了资源组方案外,Doris还提供了对单查询的资源限制功能。目前Doris对单查询的资源限制主要分为CPU和内存限制两方面。

  • 内存限制:Doris可以限制一个查询被允许使用的最大内存开销,以保证集群的内存资源不会被某一个查询全部占用。
    可以通过以下方式设置内存限制:
    # 设置会话变量exec_mem_limit,则之后该会话内(连接内)的所有查询都使用这个内存限制。
    set exec_mem_limit=1G;
    # 设置全局变量exec_mem_limit,则之后所有新会话(新连接)的所有查询都使用这个内存限制。
    set global exec_mem_limit=1G;
    # 在SQL中设置变量exec_mem_limit,则该变量仅影响这个SQL。
    select /*+ SET_VAR(exec_mem_limit=1G) */ id, name from tbl where xxx;

    Doris的查询引擎是基于全内存的MPP查询框架。当一个查询的内存使用超过限制后,查询会被终止。因此,当一个查询无法在合理的内存限制下运行时,您需要通过一些SQL优化手段或集群扩容的方式来解决。

  • CPU限制:

    您可以通过以下方式限制查询的CPU资源。

    # 设置会话变量cpu_resource_limit,则之后该会话内(连接内)的所有查询都使用这个CPU限制。
    set cpu_resource_limit = 2
    # 设置用户的属性cpu_resource_limit,则所有该用户的查询情况都使用这个CPU限制。该属性的优先级高于会话变量cpu_resource_limit
    set property for 'user1' 'cpu_resource_limit' = '3';

    cpu_resource_limit的取值是一个相对值,取值越大则能够使用的CPU资源越多。但一个查询能使用的CPU上限也取决于表的分区分桶数。通常一个查询的最大CPU使用量和查询涉及到的Tablet数量正相关。特殊情况下,假设一个查询仅涉及到一个Tablet,则即使cpu_resource_limit设置一个较大值,也仅能使用1个CPU资源。

通过内存和CPU的资源限制,可以在一个资源组内,将用户的查询进行更细粒度的资源划分。例如可以让部分时效性要求不高,但是计算量很大的离线任务使用更少的CPU资源和更多的内存资源;而部分延迟敏感的在线任务,使用更多的CPU资源以及合理的内存资源。

最佳实践和向下兼容

Tag划分和CPU限制是v0.15版本中的新功能。为了保证可以从老版本平滑升级,Doris做了如下的向下兼容:
  • 每个BE节点会有一个默认的Tag:"tag.location": "default"
  • 通过alter system add backend语句新增的BE节点也会默认设置Tag"tag.location": "default"
  • 所有表的副本分布默认修改为"tag.location.default:xx”。其中xx为原副本数量。
  • 您依然可以通过"replication_num" = "xx"在建表语句中指定副本数,这种属性将会自动转换成"tag.location.default:xx,从而保证无需修改原建表语句。
  • 默认情况下,单查询的内存限制为单节点2 GiB,CPU资源无限制,和原有行为保持一致。且resource_tags.location属性为空,即默认情况下,您可以访问任意Tag的BE,和原有行为保持一致。

例如,从原集群升级到v0.15版本后,您可以参考如下步骤开始使用资源划分功能。

  1. 关闭数据修复与均衡逻辑。

    因为升级后,BE的默认Tag为"tag.location": "default",而表的默认副本分布为"tag.location.default:xx。所以如果直接修改BE的Tag,系统会自动检测到副本分布的变化,从而开始数据重分布,这可能会占用部分系统资源。您可以在修改Tag前,先关闭数据修复与均衡逻辑,以保证在规划资源时,不会有副本重分布的操作。

    ADMIN SET FRONTEND CONFIG ("disable_balance" = "true");
    ADMIN SET FRONTEND CONFIG ("disable_tablet_scheduler" = "true");
  2. 设置Tag和表副本分布。

    通过alter system modify backend语句进行BE的Tag设置,以及通过alter table语句修改表的副本分布策略。

    alter system modify backend "host1:9050, 1212:9050" set ("tag.location" = "group_a");
    alter table my_table modify partition p1 set ("replication_allocation" = "tag.location.group_a:2");
  3. 开启数据修复与均衡逻辑。

    在Tag和副本分布都设置完毕后,可以开启数据修复与均衡逻辑来触发数据的重分布。

    ADMIN SET FRONTEND CONFIG ("disable_balance" = "false");
    ADMIN SET FRONTEND CONFIG ("disable_tablet_scheduler" = "false");

    该过程根据涉及到的数据量会持续一段时间,并且会导致部分Colocation Table无法进行Colocation规划(因为副本在迁移中)。可以通过show proc "/cluster_balance/" 来查看进度,也可以通过show proc "/statistic"UnhealthyTabletNum的数量来判断进度。当UnhealthyTabletNum降为0时,则代表数据重分布完毕。

  4. 设置用户的资源标签权限。

    数据重分布完毕后,可以开始设置用户的资源标签权限。默认情况下,用户的resource_tags.location属性为空,即可以访问任意Tag的BE。所以在前面步骤中,不会影响到已有用户的正常查询。当resource_tags.location属性非空时,用户将被限制访问指定Tag的BE。