34

数据库数据太多跑不动怎么办?

 4 years ago
source link: http://mp.weixin.qq.com/s?__biz=Mzg4NjA4NTAzNQ%3D%3D&%3Bmid=2247485589&%3Bidx=1&%3Bsn=107ed839dfd228a8e36a32baf7438fe5
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

| 作者: 董泽锋,腾讯云数据库研发工程师,主要负责腾讯云TDSQL数据库研发和运维工作。

随着业务的增长,MySQL中保存的数据会越来越多。此时,数据库很容易成为系统性能的一个瓶颈,单机存储容量、IO、CPU处理能力都有限,当单表的数据量达到1000W或100G以后,库表的增删改查操作面临着性能大幅下降的问题。

分库分表是一种解决办法。 分库分表实际上就是对数据进行切分。

我们一般可以将数据切分,分为两种方式: 垂直 (纵向)切分和 水平 (横向)切分。

1

垂直切分

垂直切分常见有 垂直分库 和 垂直分表 两种。

1. 垂直分库

垂直分库就是根据业务耦合性,将关联度低的不同表存储在不同的数据库。

思想与“ 微服务治理 ”类似,将系统拆分为多个业务,每个业务使用自己单独的数据库。


比如下图:

ZzauiiY.jpg!web

将应用拆分为客户、存款和贷款三个业务,每个业务使用自己单独的数据库。

2. 垂直分表

垂直分表是基于数据库中的表字段来进行的。业务中可能存在一些字段比较多的表,表中某些字段长度较大,这些长字段我们又只是偶尔需要用到,这时候我们就可以考虑将表进行垂直拆分了。

将某些不常用的,但是长度又很大的字段拎出来放到另外一张表。

MySQL底层是通过数据页存储的,一条记录占用空间过大会导致跨页,造成额外的性能开销。另外数据库以行为单位将数据加载到内存中,这样表中字段长度较短且访问频率较高,内存能加载更多的数据,命中率更高,减少了磁盘IO,从而提升了数据库性能。

垂直切分例子如下图:

iuQJvi6.png!web

我们将一张包含4个字段的表拆分为2张表,在业务代码里面,通过字段C1来进行关联。

3. 垂直切分优缺点

优点:

  1. 不同系统可以使用不同的库表,解决业务系统层面的耦合,业务清晰;

  2. 高并发场景下,垂直切分一定程度地提升IO、数据库连接数,缓解单机硬件资源的瓶颈。

缺点:

  1. 部分查询需要在业务代码逻辑里面做聚合,增加开发复杂度;

  2. 事务处理复杂,可能需要在业务代码层面做处理;

  3. 不能根本解决单表数据量过大的问题。

1

水平切分

当业务难以更细粒度地进行垂直切分,或者切分后单表数据依然过大,存在单库读写、存储性能瓶颈时候,这时候就可以考虑水平切分了。

水平切分又可以分为 库内分表 和 分库分表。

水平切分是根据表内数据的内在逻辑关系,将同一个表按不同的条件分散到多个数据库或多个表中,每个表中只包含一部分数据,从而使得单个表的数据量变小,达到分布式的效果。

1. 库内分表

库内分表就是在同一个DB上,将表按照某种条件拆分为多张表。

比如一张订单表,我们可以依据订单的日期,按月建表。一月份的订单放month_201901这张表,二月份的订单放month_201902这张表。

库内分表只解决单表数据量过大问题,但没有将表分布到不同机器上, 所有请求还是在一台物理机上竞争cpu、内存、IO ,对于减轻mysql负载压力来说帮助不大。

2. 分库分表

分库分表就是将表不仅拆分,而且拆分到不同机器上。

比如我们腾讯云上的DCDB就是这种处理方法。可以指定一张表的shardKey,然后对shardKey取hash,根据hash值将数据放到不同的数据库中, 可以解决单机物理资源的瓶颈问题

分库分表的示例如下:

bYBFNj2.jpg!web

上面示例先根据业务耦合性垂直分库,然后再针对单个库进行分库分表。

3. 分库分表优缺点

优点:

  1. 不存在单库数据量过大、高并发的性能瓶颈,提升系统稳定性和负载能力;

  2. 应用端改造较小,不需要拆分业务模块。

缺点:

  1. 跨分片的事务一致性较难保障,一般需要一层中间件,介于业务和DB之间。对应腾讯云上的DCDB数据库所包含的Proxy层;

  2. 跨库的join关联查询性能较差。

1

分库分表带来的问题

分库分表能有效地缓解单机和单库带来的性能瓶颈和压力,突破网络IO、磁盘存储、CPU处理能力的瓶颈,同时也带来了一些问题。

1. 事务一致性问题

当更新内容同时分布在不同库中,不可避免会带来跨库事务问题。跨分片事务也是分布式事务,没有简单的方案,一般可使用”XA协议”和”两阶段提交”处理。

分布式事务能最大限度保证数据库操作的原子性,但在提交事务时需要协调多个节点,推后了提交事务的时间点,延长了事务的执行时间。导致事务在访问共享资源时发生冲突或死锁的概率增高。随着数据库节点的增多,这种趋势会越来越严重,从而成为系统在数据库层面上水平扩展的枷锁。

2. 跨节点关联查询 join 问题

切分之前,系统中很多列表和详情页所需的数据可以通过sql join来完成,而切分之后,数据可能分布在不同的节点上,此时join带来的问题就比较麻烦了,考虑到性能,尽量避免使用join查询。

解决这个问题的一些方法:

2.1)全局表:

全局表,也可看做是”数据字典表”,就是系统中所有模块都可能依赖的一些表,为了避免跨库join查询,可以将这类表在每个数据库中都保存一份。这些数据通常很少会进行修改,所以也不担心一致性的问题。比如腾讯云上的DCDB,可以创建广播表,其实就是全局表。每个节点都有该表的全量数据,该表的所有操作都将广播到所有物理分片(set)中。

2.2)字段冗余

一种典型的反范式设计,利用空间换时间,为了性能而避免join查询。例如:订单表保存userId时候,也将userName冗余保存一份,这样查询订单详情时就不需要再去查询”买家user表”了。

但这种方法适用场景也有限,比较适用于依赖字段比较少的情况。而冗余字段的数据一致性也较难保证,就像上面订单表的例子,买家修改了userName后,是否需要在历史订单中同步更新呢?这也要结合实际业务场景进行考虑。

2.3)数据组装

在系统层面,分两次查询,第一次查询的结果集中找出关联数据id,然后根据id发起第二次请求得到关联数据,最后将获得到的数据进行字段拼装。

3. 跨节点分页、排序、函数问题

跨节点多库进行查询时,会出现limit分页、order by排序等问题。分页需要按照指定字段进行排序,当排序字段就是分片字段时,通过分片规则就比较容易定位到指定的分片。

当排序字段非分片字段时,就变得比较复杂了。需要先在不同的分片节点中将数据进行排序并返回,然后将不同分片返回的结果集进行汇总和再次排序,最终返回给用户。显然这个过程是会降低查询的效率,对IO,CPU也会增加额外负担。

如下图所示:

RzemEvf.jpg!web

上图中只是取第一页的数据,对性能影响还不是很大。但是如果取得页数很大,情况则变得复杂很多,因为各分片节点中的数据可能是随机的,为了排序的准确性,需要将所有节点的前N页数据都排序好做合并,最后再进行整体的排序,这样的操作是很耗费CPU和内存资源的,所以页数越大,系统的性能也会越差。

在使用Max、Min、Sum、Count之类的函数进行计算的时候,也需要先在每个分片上执行相应的函数,然后将各个分片的结果集进行汇总、再次计算,最终将结果返回。

4. 全局主键避重问题

在分库分表环境中,由于表中数据同时存在不同数据库中,主键平时使用的自增长将无用武之地,某个分区数据库自生成的ID无法保证全局唯一。 因此需要单独设计全局主键,以避免跨库主键重复问题。

1

分库分表可以解决一些问题(比如单机的IO,CPU、磁盘瓶颈问题),但也增添了一些新问题(比如事务一致性问题,跨分片join问题)。 当然随着一些新的NewSQL技术的成熟,分库分表这一方案也不再是业务扩张后的最优选择了,腾讯自研云原生数据库 CynosDB就给出了更优的解决方案。

往期推荐

veQFrij.jpg!web

(点击图片即可跳转阅读)

6bYJjyY.jpg!web

开年大礼包 

baaMvyN.jpg!web

↓↓更多惊喜优惠请点这儿~


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK