分布式数据库下数据是如何进行水平切分的?
说明:之前对分布式数据库接触的比较少,近期学习了两周Gbase 8a MPP Cluster ,由于个人知识有限,只记录下对分布式数据库数据切分浅显的理解。
首先GBase 8a MPP Cluster ,全称:南大通用大规模分布式并行数据库集群系统,它是在 GBase 8a 列存储数据库基础上开发的一款 Shared Nothing 架构的分布式并行数据库集群。

数据库环境如下:
管理节点 :192.168.38.10 、 192.168.38.20
计算节点:192.168.38.10 、 192.168.38.20 、 192.168.38.30
其中管理节点由多台服务器组成一个管理集群,计算节点由多台服务器组成一个计算集群。
[root@cjcos0 1 ~]# gcadmin

数据库分布情况如下:
每台计算节点服务器上有两个主分片,一个副本分片
[gbase@cjcos01 gcinstall]$ gcadmin showdistribution node

当然,主分片个数和备份分片个数可以根据实际情况进行调整,例如:
[gbase@cjcos01 gcinstall]$ gcadmin distribution gcChangeInfo.xml p 2 d 1 pattern 2
在如上这种架构和分片结构下,表数据是如何分布的?
例如有一张表 t1 ,因为一共有 6 个分片, t1 表的数据会被切分成 6 份,也就是 t1_n1,t1_n2,t1_n3,t1_n4,t1_n5,t1_n6 ,按照上面的分布情况,会将 t1_n1,t1_n4 主分片数据存储在 192.168.38.10 服务器上,将 t1_n2,t1_n5 主分片数据存储在 192.168.38.20 服务器上,将 t1_n3,t1_n6 主分片数据存储在 192.168.38.20 服务器上。
某台计算节点服务器发生故障,如何实现故障转移?
例如 192.168.38.10 服务器故障,那么当有应用需要访问这台服务器上的 t1_n1 、 t1_n4 数据时,可以将查询指向 t1_n1 、 t1_n4 的副本数据里,既 192.168.38.20 副本集里的 t1_n1 、 t1_n4 ,还可以通过将高可用模式改成负载均衡模式,将 192.168.38.10 主分片对应的副本分片指定分布到多台服务器上,降低木桶效应的产生。
在插入或加载数据时,这条数据应该存储到哪台服务器的哪个分片上?
具体新数据应该存储到哪个上,和表分布方式有关,常见分布表有随机分布表和HASH 分布表。
(1) 随机分布表 : 将数据平均分布到各个节点各个分片上,优点是看上去表的数据是被均匀打散到各个节点各个分片上的,减少了木桶效应的产生,但是在进行大表关联或 group by 等操作时,可能会因为拉复制表或 HASH 动态重分布导致性能下降。
(2)HASH 分布表 : 提前将表的某一列选为 HASH 分布列,对该列进行 HASH 运算生成 HASH 值,而在数据库内部提前创建好了一张 nodedatamap 表,这张表记录了具体的 HASH 值对应到哪个具体节点的分片上,而 nodedatamap 表的数据又是根据之前创建好的 distribution 分布生成的。这样会将 HASH 值相同的数据存放到一个分片上,优点是在进行大表关联或 group by 等操作时,可以实现静态减少拉复制表或 HASH 动态重分布操作,缺点是数据可能分布不均匀,一定要选取合适的 HASH 分布列。
首先看下各个节点对应的HASH 值数量基本是相同的。
gbase> select count(hashkey),nodeid,data_distribution_id from gclusterdb.nodedatamap group by nodeid,data_distribution_id order by 2;

创建表 t1 和 t2 ,实际看下数据是如何分布的。
gbase> create table t1(id int,name varchar(10)) distributed by ('id');
gbase> create table t2(id int,cname varchar(10)) distributed by ('id');
gbase> insert into t1 values(1,'A'),(2,'B'),(3,'C'),(4,'D'),(5,'E'),(7, ’ FFF ’ );
gbase> insert into t2 values(1,'AA'),(2, ’ XX ’ ),(3,'BB'),(5,'CC'),(7,'DD'),(9,'EE');
先看下id=1,2,3,4,5,6,9 时对应的 hash 值是多少,应该存储在哪个分片上。
select * from gbase.nodedatamap where hashkey=(crc32( '1' )) mod 65536 and data_distribution_id= 4 ;

select * from gbase.nodedatamap where hashkey=(crc32( '2' )) mod 65536 and data_distribution_id= 4 ;

select * from gbase.nodedatamap where hashkey=(crc32( '3' )) mod 65536 and data_distribution_id= 4 ;

select * from gbase.nodedatamap where hashkey=(crc32( '4' )) mod 65536 and data_distribution_id= 4 ;

select * from gbase.nodedatamap where hashkey=(crc32( '5' )) mod 65536 and data_distribution_id= 4 ;

select * from gbase.nodedatamap where hashkey=(crc32( '7' )) mod 65536 and data_distribution_id= 4 ;

select * from gbase.nodedatamap where hashkey=(crc32( ' 9 ' )) mod 65536 and data_distribution_id= 4 ;


可知:id=1,2,3,4,5,7,9 数据分别分布在 nodeid4,5,4,3,4,0,2(segments 5,6,5,4,5,1,3) 上,例如 id=1,3,5 存储在 192.168.38.20 服务器是上 t1 、 t2 的第 5 个分片上,既 t1_n5 、 t2_n5 表上。
以单机模式连接到192.168.31.20 ,验证一下上面的理论是否正确。
[gbase@cjcos02 ~]$ gncli
gbase> show tables;

其中 n2,n5 是主分片数据, n1,n4 是备份分片。
查看 id=1,3,5 确实分布到了 t1 表第 5 个分片上,既 t1_n5;
gbase> select * from t1_n5;

gbase> select * from t2_n5;

同理,我们知道, t1 和 t2 表 id 数据分布如下:
|
|
ip=192.168.31.10 |
p=192.168.31.20 |
p=192.168.31.30 |
|
id=1 |
|
t1_n5,t2_n5 |
|
|
id=2 |
|
|
t1_n6,t2_n6 |
|
id=3 |
|
t1_n5,t2_n5 |
|
|
id=4 |
t1_n4 |
|
|
|
id=5 |
|
t1_n5,t2_n5 |
|
|
id=7 |
t1_n1,t2_n1 |
|
|
|
id=9 |
|
|
t1_n3,t2_n3 |
可以看到,t1 和 t2 表的数据通过 HASH 算法存储到了 192.168.31.10,20,30 三台服务器上,每个服务器节点下有 2 个分片,既 1 张表数据理论上被分成 6 份存储到 3 台服务器上。例如 t1 表被切分成 t1_n1,t1_n2,t1_n3,t1_n4,t1_n5,t1_n6 ,数据是按照 nodedatamap 表里 hash 值和分片对应关系对应写入到各个分片上的,从而实现了表数据的水平切分。
具体过程:
1 先根据实际情况,通过 gcadmin distribution 命令定义了每个节点上的主分片和副本分片的个数和分布,以及负载或高可用模式等,
2 使用 initnodedatamap 命令,同时根据第一步制定的分布规则,将hash 值和分片对应关系写入到 nodedatamap 表里。
3 HASH 分布表在写入数据时,根据 nodedatamap 表里hash 值和分布对应关系,将数据写入到指定节点的指定分片上。
那么在分布式数据库下,SQL 优化需要考虑哪些因素呢?
在分布式数据库下, 多表 join 操作, group by , order by 是如何实现的?
下一节在具体说明下优化相关内容。
欢迎关注我的微信公众号"IT小Chen",共同学习,共同成长!!!