Hologres是一款高性能的、计算存储分离的分布式一站式实时数仓引擎,数据存储在位于底层存储系统的数据分片(又称Shard)上。本文为您介绍Hologres中Table Group和Shard Count的概念。
Table Group和Shard
在Hologres中数据存储在Pangu系统上,Shard表示数据分片,Table Group则是用于管理这些Shard,类似于存储逻辑概念。一个表的数据将会存储在固定的一组Shard上,数据写入时会按照Distribution Key将数据分发到具体的Shard上。从创建表开始,负责存储表数据的这一组Shard就已经分配好了,Table Group则负责管理这一组Shard。
Table Group是Hologres特有的一个存储逻辑概念(PostgreSQL无此概念)。Table Group与PostgreSQL中的TABLESPACE是不一样的:TABLESPACE唯一标识了数据库对象的存储位置,类似一个目录的概念。而Table Group代表的是底层的逻辑Shard组。

- Table Group与Schema的区别
Schema是一个标准的数据库概念,而Table Group是一个逻辑存储概念,并非数据库标准。不同Schema下的表可以位于同一个Table Group,即底层使用同一组Shard存储。
- Table Group与数据库(DB)的关系
一个DB可以包含一个或者多个Table Group,但是一个DB只能有一个默认Table Group。在创建DB之后,系统会创建一个默认Table Group,可以根据业务情况增加Table Group或者修改默认Table Group。
- 不同Table Group的区别
一个DB可以存在多个Table Group,但Table Group之间的Shard互不相交,每个Shard在实例级别拥有单独的编号。
- Shard Count
一个Table Group中Shard的数量称为Shard Count。Shard Count在创建Table Group时指定,所以Table Group一旦建立,Shard Count就不能调整,如需调整Shard Count,需要重新创建Table Group并指定Shard数。
- Shard与Table的关系
- Shard负责表数据的存储和查询,系统根据Distribution Key决定表数据分布在哪些Shard,如果没有设置Distribution Key,那么数据就会被随机分配到各个Shard。
- 一个Table Group中可以有多个Table,即多个Table可以分布在同一组Shard上。但是一个Table只能属于一个Table Group,如果Table Group中没有Table,那么Table Group会被系统自动删除。
- 如果Table的数据要从一个Table Group迁移至另外一个Table Group,那么需要重新建表指定Table Group,或者通过迁移函数将数据进行迁移。
Shard与计算节点Worker的关系
在Hologres中存储引擎Storage Engine(SE)主要负责管理和处理数据,在DML的功能上,SE提供了单条或者批量的创建、查询、更新、和删除(CRUD操作)访问方法的接口,查询引擎(QE)可以通过这些接口访问Shard上的数据,从而实现数据的高性能写入或者读取。

- 当创建Table Group并设置Shard数后(如果没有显式设置Table Group和Shard数,那么Hologres会在创建数据库时创建一个默认Table Group并为其设置默认的Shard Count,详情请参见实例规格概述),每个计算节点Worker会在内部创建多个SE,一个SE负责一个Shard数据的读取和写入。
- 系统机制会尽量保证每个Worker中的SE数量均匀,这样能够让Worker计算资源均匀分配。
- 系统会保证一个Table Group内的Shard一定是分配给多个Worker,不会出现一个Table Group仅对应一个Worker,其余Worker空置的情况。但如果Table
Group的Shard数较少,但是实例规格较大即Worker较多,则会导致某些Worker无法分配Shard,导致某些Worker空置,因此在设计Shard数时一定要充分考虑业务情况,确保Worker的个数与实例总的Shard数有一定的均衡关系。
从上图中能很容易看出一个问题:假如Table Group的Shard数与Worker个数不成比例关系(如上图
Table Group 1
有3个Shard,但是只有2个Worker),那么就一定会存在某个Worker比其他Worker多分配一个SE给Table Group的情况,这样在计算时,就非常容易造成Worker资源倾斜,容易出现计算长尾。因此我们建议若是要修改Shard Count,建议Shard Count与计算Worker成一定的比例关系。如下图所示Table Group 1
和Table Group 2
的Shard数都与Worker个数存在倍数关系,计算资源能够均匀的分配。在实际业务中,可能会存在某个Worker因为OOM等原因出现Failover的情况,那么该Worker对应的Shard将会在Worker Failover之后自动挂载在其他Worker上,系统会保证每个Worker新分配得Shard均匀。如下示例,实例一共有4个Worker,2个Table Group共8个Shard,其中每个Worker有2个SE均匀对应Shard,当Worker 4
Failover后,假设Worker 4
对应Shard 7
和Shard 8
,那么Shard 7
和Shard 8
就会被快速分配给其他3个Worker,因为只有2个Shard,所以系统会随机选择2个Worker进行分配,尽量保证Worker的SE数量均匀。
总结
- 一定范围内Shard数多的Table Group,其数据写入和查询分析处理可以得到更大的并行度。但Shard数也并非越多越好,更多的Shard数需要更多的节点间通信资源、计算资源以及内存资源,在资源不满足的时候,或者Query很小时可能会导致适得其反的效果。
- Shard数下限是1,在数据量只有几百几千条等很小的情况下,可以设置Shard数为1。一个Table Group上,Shard数的上限建议是实例的总计算Core数,这样是为了保证每个Shard在计算时,至少可以占据1个Core用于计算。如果Shard数超过计算Core数,那么运行查询时,将有部分Shard无法一直分到CPU资源,可能带来长尾和切换开销。
- 除Shard数量外,Table Group本身的数量也不是越多越好。每个Shard无论是否正在使用,都会占据一定的内存空间,用于存放表元数据、Schema等信息,在表有写入时则会占据更多内存空间。因此如果Table Group越多,则实例内总Shard数越多,内存空间占用越大。另外多个表之间有一些特殊的关系(例如需要Local Join)时,这些表必须要处在同一Table Group下才行。
- 从磁盘上来看,Shard数越多,对于同样的一张表,数据会分的越散,越容易出现小文件,从而文件个数更多。如果表多并且Shard也多,那文件数量就会非常庞大。在查询时Failover时都需要更多的开销,造成查询I/O增多,恢复时间变长。