本文旨在为您介绍Hologres中Table Group和Shard Count选定的基本原则、适用场景、设置策略、操作指南以及常见问题,以助您获取更优的查询性能。

注意事项

推荐设置Table Group基本原则如下:
  • 如无必要,不要新建Table Group。
  • 数据量过大时,可新建独立的较大shard数的Table Group。
  • 如果有大量数据量很小的表,可独立出一个小shard数的Table Group,减小query启动开销。
  • 需要Join的表,尽量放在同一个Table Group。

背景信息

Hologres是一款高性能的、计算存储分离的分布式实时数仓引擎,数据存储在位于底层存储系统的数据分片上(又称shard)。Hologres拥有的灵活指定Shard和Table Group的特性,相比一些同类产品,具备更加灵活、易用而方便的根据具体场景定制化Schema的能力,更加灵活应对业务需求,加上用户对自身业务的理解,能够比较高效地、充分地利用好Hologres高性能。

在Hologres中,1个DB包含0个或多个Table Group,每个Table Group包含多个table,每个table只能属于一个Table Group。一个Table Group唯一对应一组shard,由这组shard来负责其中表的数据存储和查询,其包含的shard个数称为Shard Count,Table Group一旦建立,shard数不可调整。

合理的Table Group选择与Shard Count制定,是写入和查询效率的基石,能够从根本上改善数据的存储与计算效率;反之,如果Table Group和Shard Count制定不当,很容易出现性能不如预期的情况,且无法根本上调优到最佳性能。

说明 本文涉及到的Table Group、Shard Count等基本概念,请参见基本概念

适用场景

在Hologres实例中,一个DB默认一个Table Group,不同的实例规格默认Table Group配置不同的shard count数,详情请参见实例规格概述。这些默认Shard Count数,是经过大规模实验验证的最佳参数,能满足大部分场景,如果没有特殊需求,不建议新建Table Group以及修改Shard Count。

本文最佳实践适用于对Hologres原理、架构有一定了解,且编程开发经验较为丰富的用户,主要适用修改Table Group和Shard Count的场景如下:

  1. 在一些特殊需求下,例如写入数据量太大,或者数据量过小而分析发现Query启动开销太大(启动开销和shard数呈正相关关系)、或者Query shuffle开销太大等场景,建议您新建Table Group。
  2. Table Group一个非常关键的作用就是做Local Join从而大大提升Join效率,因此,当您有表需要互相Join,且Join Key为Distribution Key时,将Join的左右表放在同一Table Group即可获得Local Join的效果,产生比较大的性能提升。

Table Group规划

您可以根据以下Table Group规划的基本原则,来决定是否需要新建以及如何放置Table Group。

  • 规划一:使用默认Table Group

    如您使用Hologres满足下列条件,建议您直接使用默认Table Group即可。

    • 数据量:

      当前默认Table Group的Shard数,符合目前数据量大小的需求。可以使用默认Table Group直接建表。

    • 总体规模:

      全部表的数据量规模总和可控,可预估,使用方式没有大的变化。

    • Local Join:

      需要与已在默认Table Group的表,进行高效的Local Join。

  • 规划二:新建Table Group

    如果默认Table Group不能满足您的需求,那么您可能需要多个Table Group。通常在如下条件下,在您的实例中可能需要多个Table Group:

    • 数据量

      已有Table Group的Shard数不适合当前表的预估数据量,例如,太小的表一般不太适合放在大Table Group中,太大的表一般也不适合放在小Table Group中。这是最常见的需要划分多个Table Group的原因。

    • 负载分离

      已有的Table Group容纳的表数量很多,且大多数表需要同时写入,导致实例的负载很高,而即将创建的新表又需要较高的查询和写入吞吐,这时多个Table Group可以实现写入和查询一定程度上的独立,不受其他表写入查询影响。或者经过问题排查,确定是已有Table Group无法满足写入和查询需求时,也需要多个Table Group。

    • 表的相关性

      业务上有一系列具有独特写入或者查询模式的表,且这一系列表之间具有(或未来具有)Local Join的需求(Local Join需要左右表同在一个Table Group才能实现,并且Join Key是各自的分布列),同时这些表和其他Table Group的表具有很浅的联系或根本没有联系。这种情况下可以创建多个独立的Table Group。也就是说,如果您有一组表之间相关性很强的表,而这组表与其他表相关性很低、联合查询的概率很低,可以考虑创建多个Table Group。

    • 实例资源扩缩容

      如果实例进行过扩、缩容超过5倍以上,原来定的Shard数很可能不再满足需求,可以考虑更换默认Table Group。

  • 规划三:多个Table Group放置

    如果需要规划多个Table Group,那么最好是能够在压测和生产之前,提前规划好多个Table Group的作用与意义,以及每个表所属的Table Group。规划时可以考虑如下因素:

    • 数据量

      首先应该考虑的是数据量,也就是大表放更多的Shard,中小表放更少的Shard。

    • 写入性能需求

      Shard数和数据写入性能呈一定的正相关性,单个Shard的写入能力是有上限的。Shard越多,写入的并发越多,写入的吞吐越高。因此,如果表有较高RPS的写入需求,那么可能需要增大shard数。Hologres单Shard将单core打满时,写入RPS为3000-5000条/秒(1KB/条),可以据此估算所需Shard数。考虑到每个shard还需要进行查询等读操作,一般不能使写入打满CPU,因此可以说,使用1/3core的shard,写入RPS为1000条/秒(每条1KB)。因此,举例而言,如果您要求写入RPS 6W/s,每条1KB,则应该选择的Shard数约在60Shard之上,视情况增减。

    • Table Group负载

      在建立一个新的Table Group时,需要考虑当前Table Group需要承载的表数量。例如,如果未来放在此Table Group的表很多,并且多数表都需要经常访问,那么Shard数很小将会存在并发不够的风险。

Shard数规划

Shard数多的Table Group,其数据写入和查询分析处理可以得到更大的并行度。一定范围内,增大Shard数可以加快数据写入和查询分析的速度。但Shard数也并非越多越好,更多的Shard数需要更多的节点间通信资源、计算资源以及内存资源,在资源不满足的时候,或者Query很小时可能会导致适得其反的效果。

在Hologres中,Shard数下限是1,在数据量只有几百几千条等很小的情况下,可以设置shard数为1。Shard数上限原则上是实例的总计算Core数(实例总计算Core数约等于实例总Core数的60%,有一部分资源用在前端请求处理、外表查询、集群管理和元数据管理等进程上),这样是为了保证每个Shard在计算时,至少可以占据1个core用于计算。如果Shard数超过计算Core数,那么运行查询时,将有部分Shard无法一直分到CPU资源,可能带来长尾和切换开销。从磁盘上来看,Shard数越多,对于同样的一张表,数据会分的越散,越容易出现小文件,从而文件个数更多,如果表多,并且shard也多,那文件数量就会非常庞大。在查询时、failover时都需要更多的开销,造成查询IO增多,恢复时间变长。

除Shard数量外,Table Group本身的数量,也不是越多越好。每个Shard无论是否正在使用,都会占据一定的内存空间,用于存放MemTable,Schema等信息,在表有写入时,则会占据更多。因此,如果Table Group越多,则实例内总Shard数越多,内存空间占用越大。另外,多个表之间有一些特殊的关系(例如需要local join)时,这些表必须要处在同一Table Group下才行。

Shard Count的数据量测算法

在实践过程中存在数据量可预估,最适宜的Shard数区间应该设置为多少的问题,由于最适宜Shard数不仅和数据存储量有关,还和实际访问频率、实际数据访问量、计算负载的类型(点查、分析等)、写入吞吐、Table Group上表的个数等因素有关,该问题无法给出准确答案。您可参见下表中根据数据量估算的所需Shard数和实例规格的推荐数,选择适合您的参数配置。
数据规模 推荐Shard数 推荐规格
4000万行以下 10~20 32Core以上
4000万行~4亿行 20~40 64Core以上
4亿行~40亿行 40~80 128Core以上
40亿行~400亿行 80~240 256Core以上
400亿行~4000亿行 200~400 512Core以上
说明 上表根据数据量估算的所需Shard数和实例规格的推荐数不是唯一标准,小数据量的表也可以放在多的Shard Count之上,大数据量的表也可以放在单个Shard上。请您根据实际业务场景选择一个合适的Shard Count,既满足有较高的并发度,带来更高计算效率,又满足数据较集中,从而避免不必要的shuffle开销。

操作指南

下面简单介绍一下在Hologres中Table Group相关的操作和元信息表:

  1. 初次使用,获取Table Group元数据
    1. 查看默认Table Group
      SELECT * FROM hologres.hg_table_group_properties
      WHERE tablegroup_name IN (
        SELECT tablegroup_name FROM hologres.hg_table_group_properties
        WHERE property_key = 'is_default_tg' AND property_value = '1'
      );
      结果:
      说明 结果中is_default_tg代表为默认Table Group,shard_count代表Table Group对应的shard数。
      tablegroup_name |   property_key   | property_value
      -----------------+------------------+----------------
       test_tg_default | tg_version       | 1
       test_tg_default | table_num        | 1               
       test_tg_default | is_default_tg    | 1               
       test_tg_default | shard_count      | 3
       test_tg_default | replica_count    | 1
       test_tg_default | created_manually | 0
      (6 rows)
    2. 查看当前DB有哪些Table Group
      SELECT tablegroup_name
      FROM hologres.hg_table_group_properties GROUP BY tablegroup_name;
      结果:
      tablegroup_name
      -----------------
       test_tg_default
      (1 row)
    3. 查看某Table Group设置的shard数
      SELECT property_value AS shard_count
      FROM hologres.hg_table_group_properties
      WHERE property_key = 'shard_count' AND tablegroup_name ='<tg_name>';
      结果:
      shard_count
      -------------
       3
      (1 row)
    4. 查看某Table Group下有哪些表
      SELECT table_namespace AS schema_name, table_name
      FROM hologres.hg_table_properties
      WHERE property_key = 'table_group' AND property_value = '<tg_name>';
      结果:
      schema_name | table_name
      -------------+------------
       public      | a
      (1 row)
    5. 查看某张表所在的Table Group
      SELECT property_value AS table_group_name
      FROM hologres.hg_table_properties
      WHERE property_key = 'table_group' AND table_name = '<table_name>';
      结果:
      table_group_name
      ------------------
       test_tg_default
      (1 row)
  2. 新建Table Group
    若是有新上的业务,需要新建Table group,可以使用以下命令语句。
    CALL HG_CREATE_TABLE_GROUP ('<new_tg_name>', <shard_count>);
    参数说明如下:
    参数 类型 说明
    new_tg_name Text 新建的Table Group名。
    shard_count INT4 Table Group对应的shard数。
    使用示例:
    -- 新建一个shard数为8的新Table Group,命名为tg_8
    CALL HG_CREATE_TABLE_GROUP ('tg_8', 8);
  3. 修改默认Table Group
    若是DB中有多个Table Group,想要修改默认Table Group,使得后续新建的表存放于新的Table Group中,可以通过以下语句修改:
    • V0.9及以上版本执行以下命令语句修改默认Table Group。
      CALL HG_UPDATE_DATABASE_PROPERTY ('default_table_group', '<tg_name>');
      参数说明:
      参数 类型 说明
      tg_name TEXT 默认Table Group名称,设置后,其shard count为设置的Table Group的shard数。
      使用示例:
      -- 将新创建TG设为默认Table Group,后续新建的表,将默认使用新的Table Group (v0.9以上)
      CALL HG_UPDATE_DATABASE_PROPERTY ('default_table_group', 'tg_8');
    • V0.9以下版本通过新建Table Group来更改默认Table Group。执行以下命令语句可以新建一个指定shard数的Table Group,并把该Table Group设置为默认Table Group。
      CALL HG_UPDATE_DATABASE_PROPERTY ('shard_count', '<shard_count>');
      参数说明:
      参数 类型 说明
      shard_count TEXT 填写数字,新建的Table Group所对应的shard count数。
      使用示例:
      -- 对于0.9之前的版本,新建Table Group和设置默认Table Group是一个函数 (v0.9以下)
      CALL HG_UPDATE_DATABASE_PROPERTY ('shard_count', '8');
  4. 将新建表放入Table Group
    可以通过以下命令语句将新建表,显示放入指定的Table Group中。
    BEGIN;
    CREATE TABLE table_name (
        col type,
      ....
    );
    CALL SET_TABLE_PROPERTY('table_name', 'table_group', '<tg_name>');
    COMMIT;
    参数说明:
    参数 类型 说明
    table_name TEXT 新建的表名。
    tg_name TEXT 默认Table Group名称,设置后,其shard count为设置的Table Group的shard数。
    使用示例:
    -- 新建表tbl1并直接关联名为tg_8的Table Group
    BEGIN;
    CREATE TABLE tbl1 (
        col1 text
    );
    CALL SET_TABLE_PROPERTY('tbl1', 'table_group', 'tg_8');
    COMMIT;
  5. 迁移部分业务表到新建Table Group(v0.10以上)
    可以通过以下命令将业务的部分表迁移至新建的Table Group。
    -- 新建一个shard数为8的新TG,命名为tg_8
    CALL HG_CREATE_TABLE_GROUP('tg_8', 8);
    
    -- 迁移某个表到新的Table Group
    CALL HG_UPDATE_TABLE_SHARD_COUNT('TABLE_NAME', 'tg_8');
  6. 删除Table Group
    可以通过以下命令语句删除空的Table Group。如果Table Group有表存在,则无法删除。
    CALL HG_DROP_TABLE_GROUP('<tg_name>');
    使用示例:
    --删除名为tg_8的Table Group
    CALL HG_DROP_TABLE_GROUP('tg_8');

常见问题

  • 我有512Core规格实例,主要针对一张实时事件表进行OLAP分析,表规模约200~400亿,该怎么设计Table Group和Shard Count?

    计算负载比较单一,可以使用一个Table Group。512的默认Shard数为160,如果事件表列比较多,例如达到数百列,那么为了加强OLAP分析的并发度,可以适当增大Shard数。例如更改DB的默认Table Group的Shard数为200,或200以上,以放置事件表。

  • 我有256Core规格实例,有很多张列存表,主要进行毫秒级快速OLAP分析,每张表数据量千万条级别,主要场景为group by多个字段,以及按条件查明细,该怎么设计Table Group和Shard Count?

    计算负载比较单一,可以一个Table Group解决。256Core规格实例,默认Table Group的Shard数为120,而对于千万级别的表,我们的建议是10-20shard,尤其对于group by等聚合操作,shard越多会有更多的shuffle开销,无法应对毫秒级分析。因此,默认Table Group可能无法应对我们的需求,可以视具体情况,更改DB的默认Table Group的Shard Count为16~40之间,并进行压测,效果会更好。

  • 通过哪些手段排查慢Query是否为Shard Count不合适的原因?
    Shard数不合适分为过多和过少两种情况。
    • Shard数过多,一般会表现为:start query cost高,可以通过explain analyze后的start query cost行看出来;或者表现为shuffle开销大,这点可以通过explain analyze后,查看Redistribution Motion的Max_GetNext_Time的大小来判定。v0.10以上,可以通过慢查询日志查看历史Query的这些开销。
    • Shard数过少,一般会表现为:长时间计算时CPU也无法打满;或者scan数据的开销比较大(因为并发度不足),这点可以通过explain analyze后,查看Scan Node的Max_GetNext_Time大小来判定;或者数据写入的性能不足,上文提到Hologres单shard打满单core时,写入RPS为3000-5000,可据此估算Shard数是否过少。
  • 我是点查的服务场景,我的QPS还不够高,是不是Shard不够的原因?

    首先要判断是不是别的原因引起的,例如并非点查而是分析查询、未走索引、未做Shard裁剪以及CPU已经打满等原因。当排查完后,不属于上述情况,且单SQL性能达到极致后,如果QPS仍不满足要求,则考虑增大shard数,以增大点查的后端并发。

  • 如何排查Shard倾斜?
    Hologres提供了内部字段,hg_shard_id,即数据所在的Shard编号。可以通过SQL查看Shard倾斜情况。
    SELECT hg_shard_id, COUNT(1) FROM tbl1
    GROUP BY hg_shard_id ORDER BY COUNT(1) DESC;
    如果有Shard上的数据量显著高于其他Shard,则存在数据倾斜,可能需要调整分布列。