随着近些年来,数据规模的爆炸式增长(参见下图),如何存储、处理海量数据成为企业不得不面临的问题。作为数据的主要载体,数据库首当其冲面临这个挑战。于是近些年来,以分布式数据库为代表的产品不断涌现,正是为应对这种状况。本文尝试从分布式数据库最为基础的能力—数据分片,谈谈当前现状及各家实现情况如何。下述内容,仅代表个人观点,仅供参考。
* 来自IDC的预测报告
1. 数据分片功能说明
人生基本上就是两件事,选题和解题。最好的人生是在每个关键点上,既选对题,又解好题。人生最大的痛苦在于解对了题,但选错了题,而且还不知道自己选错了题。正如人生最大的遗憾就是,不是你不行,而是你本可以。
何为“数据分片”,通俗来讲就是将数据分散到多个物理节点的一种技术。通过拆分到更多节点,可利用更多资源,有效应对海量数据存储、计算压力。
1).数据分片优势
通过数据拆分,可享受到以下能力:
❖ 无限扩展
通过引入数据分片能力,可实现存储与计算能力的扩展,来满足用户的更高要求。理论上来说,是可以无限扩展,当然分布式数据库具体实现上,有些会加以限制。
❖ 性能提升
数据通过拆分后,单个分片上数据集变小,数据库的处理压力变小、查询更快,性能更好。数据被切分成多个部分后,还可实现查询并发执行,增加了系统的吞吐量。
❖ 高可用
当部分分片出现问题时,不会影响到全局,仅涉及这几个分片的数据,不会造成整个系统的瘫痪,提高了数据库的可用性。
2).数据切分方式
❖ 垂直(纵向)切分
这种方式顾名思义,就是将数据集垂直方向进行拆分。所谓垂直,就是按数据业务意义进行归类拆分。有两种典型的垂直拆分方式:
- 垂直分库 在库级别上,根据业务类别进行拆分,例如客户、存款、贷款、支付等划分为不同的库。这是一种相对轻量、且风险低、收益高的拆分方式。现有的微服务改造,更是加剧了这一趋势。有种业务场景,可能需要将不同业务类别的数据聚合在一起进行查询,这种情况一般建议将其汇聚在大数据平台进行处理。
- 垂直分表 在表级别,以字段为依据,按照字段的活跃性、业务特点等,将表中字段拆到不同的表中(主表和扩展表)。在字段很多的情况下(例如一个大表有100多个字段),通过"大表拆小表",更便于开发与维护,也能避免跨页问题。这种拆分优化方式,是一种容易被忽视的方法。很多系统中字段较多的表,深究起来都是可以拆分的。研发人员,不做拆分的理由往往是需要关联过多,处理比较麻烦等等。这里要掌握一种平衡,不一定非要按照所谓范式要求来做,但也不能为图方便都定义成大宽表。
优缺点
优点,垂直拆分,可解决业务系统层面的耦合,让业务变的更清晰。这与微服务治理的思想类似,可对不同业务的数据进行分级管理、维护、监控、扩展等。通过拆分,可降低SQL返回的数据规模,在高并发场景下,能在一定程度上提升IO、数据库连接数、解决单机硬件资源的瓶颈,支持更大的吞吐量。
缺点,在于拆分后会出现数据需要汇聚查询的问题。如果在表级别拆分还好,可通过关联查询解决;如果在库级别已进行拆分的话,要么通过汇聚到大数据平台查询而得,要么在应用层通过接口聚合方式解决,但这显然提高开发的复杂度。另一方面,如果涉及到跨库的事务问题,处理起来也是比较复杂的。此外,如果表的记录数过多,依然会存在单表数据量过大的问题,垂直拆分方式不能彻底解决,这就需要后面谈到的水平拆分了。
❖ 水平(横向)切分
这种方式是将数据集水平方向进行拆分。所谓水平,就是将数据以字段为依据,按照一定能策略将表中的数据拆分到多个表中。这种拆分方式适合当业务快速发展,单表数据量过大,当性能出现瓶颈时进行拆分。
优缺点
优点,水平拆分可以有效的解决数据集规模过大的问题,让数据处理效率更高。
缺点,拆分后会出现数据需要汇聚查询的问题。通常可在大数据平台汇聚完成,但这显然没有库内查询来的方便。此外,如果涉及到跨片的事务操作成本代价也较高。
3).数据拆分策略
如何将数据进行有效拆分,可以有多种方式。常见的有以下几种:
- 范围(RANGE)
最为常用,基于属于一个给定连续区间的列值,把多行分配给分片。常用于时间字段上,比如数据按照自然月或天来分布存储。范围分片允许出现的值个数比列表分片更多,列表类型可以通过枚举值转换为对应的整数值,通过整数值转换成范围分片。
create table demo_table(ddate date, value numeric)
distributed by range(ddate)
(g1 values less than('20180200'),
g2 values less than('20180300'),
g3 values less than maxvalue);
- 列表(LIST)
LIST分片和RANGE分片类似,区别在于LIST是枚举值列表的集合,RANGE是连续的区间值的集合。适用于含有一系列限定性值的场景。列表分片适合枚举类型字段的分片键,比如:银行法人。可以根据不同的法人将表数据分布在不同的分片上。这种方式是有一定缺点,其要求列表类型数据较少并且固定、不同枚举值里的数据分布不均衡。
create table demo_table(col1 varchar(4), col2 varchar(30), col3 numeric)
distributed by list(col1)
(g1 values in('HK1'),
g2 values in('CN1'),
g3 values('ER1'));
- 哈希(HASH)
基于用户定义的字段或表达式返回值进行哈希函数计算后选择分片。这种分片策略适用于大多数分布式表,可以将数据均匀地分布到预先定义的数据节点上,保证各数据节点的数据数量大致一致,一般情况下不需要关心分发字段值的具体含义。对于等值操作的表特别适合。例如在银行业务中,常按客户号对账号主档表进行哈希分片。
create table demo_table(col1 int, col2 int, col3 varchar(20))
distributed by hash(col1);
一致性哈希:
普通的哈希算法,虽然能将大规模的数据均匀地打散到多个节点上,但节点扩容时所有数据要重新打散,存在大量的数据搬迁。此时刻考虑一致性哈希
- 对分片键计算哈希值,该哈希值落到0到N的封闭圆环中。
- 按分片数量(M,M远小于N)将哈希结果均分为M段,确定每个分段的值范围。
- 落入同一分段的哈希值划分在同一分片上。
- 复制(DUPLICATE)
复制表,将表中所有数据全量分布各分片上。适用于小表、数据不经常变化且读多写少的表,或者JOIN和子查询中使用的表,例如配置表等。主要目的是减少节点间网络数据的传输,以提高查询的性能。复制表可以指定保留全量数据副本的数据分片数目,可以是一个(单节点复制表),也可以是若干个数据分片,甚至在所有分片均保留一份全量数据(多节点复制表)。
create table demo_table(col1 varchar(10), col2 numeric)
distributed by duplicate(g1,g2,g3);
- 多级/组合
通过多个字段或单个字段的部分信息进行多层次分片,适用于通过多维属性对数据分布精确控制的场景。如以银行核心应用为例,法人、集团、公/私属性的客户信息精确管理的场景:不同法人的客户可以在物理上分开、对公和对私客户分开、对公客户可能属于不同的集团,可以按照集团属性分开。
creaet table demo_table(
title_id int not null,
cust_id int not null,
pub_id int not null,
PRIMARY KEY (title_id)
)
distributed by
case pub_id
when 1 then
case
when cust_id<100 then subdistributed by hash(title_id)(g1);
else subdistributed by hash(title_id)(g2);
end case;
when 2 then subdistributed by hash(title_id)(g3);
else subdistributed by hash(title_id)(g4);
end case;
4).数据分布能力
关于数据分布的情况,可分为多种情况:
- 分片表 数据分布在全部数据节点。
- 单/指定分片表 数据分布在指定一个或某几个数据节点。
- 广播表/复制表/全局表 数据全量副本会存在多个数据节点。
- ER/父子表 数据表间存在父子关系,即数据存在关联关系。数据可以天然组织在一起,这样在关联分析时效率更高。
5).其他分片能力
除上述分片策略外,针对分片还有以下一些情况。
- 分片键为函数
create table test(a int, b int, c varchar(20))
distributed by range(year(a))
(g1 values less than(1991),
g2 values less than(1995),
g3 values less than maxvalue);
- 分片键为表达式
create table test(a int, b int, c varchar(20))
distributed by list(a*2 b-1)
(g1 values in(1,4,8),
g2 values in(10, 100),
g3 values in(20, 200));
- 分片键含多字段
create table test(a int, b int, c varchar(20))
distributed by hash(a,b) (g1, g2, g3));
- 分片 分区组合
create table test(a int, b int, c varchar(20))
partition by range(b)(
partition p0 values in(1,2,3),
partition p1 values in(4,5,6)
)
distributed by range(a)
(g1 values less than(1991),
g2 values less than(1993));
2. 数据分片能力对比
人生基本上就是两件事,选题和解题。最好的人生是在每个关键点上,既选对题,又解好题。人生最大的痛苦在于解对了题,但选错了题,而且还不知道自己选错了题。正如人生最大的遗憾就是,不是你不行,而是你本可以。
下面收集了国内主流的数据库产品,针对分片能力做了对比。分为两个部分,一是对分片方式的支持,如哈希、范围、列表、组合及自定义;一是对数据分布方式的支持,如单分片或指定分片表、广播表或复制表、ER表或父子表的支持情况。表中Y表示支持,N表示不支持,空白表示未知。以下数据仅是自己观察收集到的情况,可能有所偏颇,欢迎指正。
从上面支持情况,可分为几种情况:
- 分布式中间件 单机数据库
此类产品以MyCAT、ShardingSphere、DBLE为代表,其分片能力最为灵活。不仅支持了多种分片策略,支持多种分布方式,同时也支持自定义扩展能力。如果应用需要对数据分布有充分掌控、数据分布需求与业务有亲和性,这种方式无疑非常合适。当然这种方式的弊端在于,中间件与数据库组合方案来实现,非统一标准产品化能力,存在一定维护成本。
- “分库分表型”分布式数据库
此类产品以GoldenDB、TDSQL、PolarDB-X、HotDB为代表,分片能力中等。从原理上来说,这种产品与前一种是类似的,只不过产品化程度更高。从客户侧来看,就是一个标准数据库服务。其损失了在分片上的部分能力及灵活度。如果应用需要一定灵活度或数据规模过大,这种产品更为适合。
- ”原生”分布式数据库
此类产品以TiDB、Oceanbase、CockroachDB为代表。此类分片能力被弱化,更多依靠自身分片能力解决问题。客户可干预度更低,但产品自动化程度更高,提供“标准品”的服务。如果应用需要一个all in one的架构,这种产品比较合适。