分库分表的知识

Posted 我叫小八

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分库分表的知识相关的知识,希望对你有一定的参考价值。

简述

分库分表是数据量大的场景下的一种技术优化方案,当数据量逐渐增大,单库单表已经无法满足业务需求时,分库分表成为了一个必要的选项。
分库分表可以有效地缓解数据库的性能瓶颈,提高系统的稳定性和可扩展性。但是,也不是一旦数据量增大就直接分库分表一把梭的,还是得根据实际情况实际执行。一般我们认为,单表行数超过 500 万行或者单表容量超过 2GB之后,才需要考虑做分库分表了,小于这个数据量,遇到性能问题先建议大家通过其他优化来解决。

分库

分库主要解决的是并发量大的问题。因为并发量一旦上来了,那么数据库就可能会成为瓶颈,因为数据库的连接数是有限的,虽然可以调整,但是也不是无限调整的。
所以,当你的数据库的读或者写的QPS过高,导致你的数据库连接数不足了的时候,就需要考虑分库了。
那既然是分库,本质也是数据分片,根据业务选择垂直分库或者水平分库。
垂直分库是将数据库按照功能或业务模块进行分割,例如将订单相关的表存储在一个数据库中,将用户信息相关的表存储在另一个数据库中。垂直分库的优点是可以减少单个数据库的数据量和复杂度,降低单点故障的风险,并且更容易进行扩展和维护。但是,垂直分库可能会导致跨库查询和事务处理的复杂性增加,需要进行更多的数据同步和维护。
水平分库是将数据库中的数据按照某种规则(例如按照用户ID或时间范围)进行分割,并将每个分片存储在不同的数据库中。水平分库的优点是可以处理海量数据,并且可以更容易地进行扩展和负载均衡。

但是,水平分库需要更多的数据库实例和更复杂的数据同步和维护机制,而且在跨分片查询和事务处理方面也存在一些限制,所以一般情况下都会只采用垂直分库,而用分表来解决数据量大的问题。

分表

假如你的单表数据量非常大,因为并发不高,数据量连接可能还够,但是存储和查询的性能遇到了瓶颈了,你做了很多优化之后还是无法提升效率的时候,就需要考虑做分表了。
分表本质也是数据分片,根据业务选择垂直分表或者水平分表。
垂直分表就是把这张表中某一条记录的多个字段,拆分到多张表中,表中的数据的字段数会变少,使得每一个单表中的数据的存储有所下降。
水平分表就是把一张表中的不同的记录分别放到不同的表中,使得每一个单表中的数据的存储有所下降。那这种分表模式的话就得规划合适的分片键了,根据规划的分片键来决定数据落到哪张表里。

分片

分片算法

直接取模

在分库分表时,我们是事先可以知道要分成多少个库和多少张表的,所以,比较简单的就是取模的方式。
比如我们要分成128张表的话,就用一个整数来对128取模就行了,得到的结果如果是002,那么就把数据放到order_002这张表中。

Hash取模

那如果分表字段不是数字类型,而是字符串类型怎么办呢?有一个办法就是哈希取模,就是先对这个分表字段取Hash,然后在再取模。
但是需要注意的是,Java中的hash方法得到的结果有可能是负数,需要考虑这种负数的情况。

一致性Hash

前面两种取模方式都比较不错,可以使我们的数据比较均匀的分布到多张分表中。但是还是存在一个缺点。
那就是如果需要扩容二次分表,表的总数量发生变化时,就需要重新计算hash值,就需要涉及到数据迁移了。
为了解决扩容的问题,我们可以采用一致性哈希的方式来做分表。一致性哈希可以按照常用的hash算法来将对应的key哈希到一个具有2^32次方个节点的空间中,形成成一个顺时针首尾相接的闭合的环形。所以当添加新表时,只有增加表的位置和逆时针方向第一张表之间的键会受影响。
一致性Hash算法可参考另一篇博文,这里不做多解释。

全局ID

涉及到分库分表,就会引申出分布式系统中唯一主键ID的生成问题,因为在单表中我们可以用数据库主键来做唯一ID,但是如果做了分库分表,多张单表中的自增主键就一定会发生冲突。那就不具备全局唯一性了。
那么,如何生成一个全局唯一的ID呢?有以下几种方式:

UUID

很多人对UUID都不陌生,它是可以做到全局唯一的,而且生成方式也简单,但是我们通常不推荐使用他做唯一ID,首先UUID太长了,其次字符串的查询效率也比较慢,而且没有业务含义,根本看不懂。

雪花算法

雪花算法也是比较常用的一种分布式ID的生成方式,它具有全局唯一、递增、高可用的特点。
雪花算法生成的主键主要由 4 部分组成,1bit符号位、41bit时间戳位、10bit工作进程位以及 12bit 序列号位。
时间戳占用41bit,精确到毫秒,总共可以容纳约69年的时间。
工作进程位占用10bit,其中高位5bit是数据中心ID,低位5bit是工作节点ID,做多可以容纳1024个节点。
序列号占用12bit,每个节点每毫秒0开始不断累加,最多可以累加到4095,一共可以产生4096个ID。
所以,一个雪花算法可以在同一毫秒内最多可以生成1024 X 4096 = 4194304个唯一的ID

公共基因算法

这个算法来源于对于基因的分类的计算,可以把一个自定义的Id 加上 期望根据 某个字段来分片查询的hash值来组成新的Id,这样这个作为分片id的话就很方便的处理额外的查询字段了。

分库分表的工具

在选定了分表字段和分表算法之后,那么,如何把这些功能给实现出来,需要怎么做呢?
我们如何可以做到像处理单表一样处理分库分表的数据呢?这就需要用到一个分库分表的工具了。
目前市面上比较不错的分库分表的开源框架主要有三个,分别是sharding-jdbc、TDDL和Mycat

Sharding-JDBC

现在叫ShardingSphere(Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar这3款相互独立的产品组成)。它定位为轻量级Java框架,在Java的JDBC层提供的额外服务。它使用客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的JDBC驱动,完全兼容JDBC和各种ORM框架。
开原地址:https://shardingsphere.apache.org

TDDL

TDDL 是淘宝开源的一个用于访问数据库的中间件, 它集成了分库分表, 读写分离,权重调配,动态数据源配置等功能。封装 jdbc 的 DataSource给用户提供统一的基于客户端的使用。
开源地址:https://github.com/alibaba/tb_tddl

Mycat

Mycat是一款分布式关系型数据库中间件。它支持分布式SQL查询,兼容mysql通信协议,以Java生态支持多种后端数据库,通过数据分片提高数据查询处理能力。
开源地址:https://github.com/MyCATApache/Mycat2

存在问题

分库分表之后,会带来很多问题。
首先,做了分库分表之后,所有的读和写操作,都需要带着分表字段,这样才能知道具体去哪个库、哪张表中去查询数据。如果不带的话,就得支持全表扫描。
但是,单表的时候全表扫描比较容易,但是做了分库分表之后,就没办法做扫表的操作了,如果要扫表的话就要把所有的物理表都要扫一遍。
还有,一旦我们要从多个数据库中查询或者写入数据,就有很多事情都不能做了,比如跨库事务就是不支持的。
所以,分库分表之后就会带来因为不支持事务而导致的数据一致性的问题。
其次,做了分库分表之后,以前单表中很方便的分页查询、排序等等操作可能就都失效了,因为我们不能跨多表进行分页、排序。
总之,分库分表虽然能解决一些大数据量、高并发的问题,但是同时也会带来一些新的问题。所以,在做数据库优化的时候,还是建议大家优先选择其他的优化方式,最后再考虑分库分表。

带你整理面试中数据库分库分表的相关知识点

文章目录

一、为什么要进行数据库分库分表?

主要是为了提升数据库的性能,因为当数据库中的数据量达到1000w或者100G以后,由于查询维度比较多,此时像添加优化索引之类的操作对于数据库的性能提升很小,所系需要对其进行分库分表,目的就是减小数据库的负担,将数据分散到多个数据库中,提升性能。

分库分表有垂直切分和水平切分两种

二、垂直切分

垂直分库:将表按照功能模块、关系密切程度划分并部署到不同的库中。

例如,我们会创建定义数据库workDB、商品数据库payDB、用户数据库userDB、日志数据库logDB等,分别用于存储项目数据定义表、商品定义表、用户数据表、日志数据表等,如图7-6所示。


垂直分表:是基于数据库中的"列"进行,某个表字段较多,可以新建一张扩展表,将不经常用或字段长度较大的字段拆分出去到扩展表中。在字段很多的情况下(例如一个大表有100多个字段),通过"大表拆小表",更便于开发与维护,也能避免跨页问题,MySQL底层是通过数据页存储的,一条记录占用空间过大会导致跨页,造成额外的性能开销。另外数据库以行为单位将数据加载到内存中,这样表中字段长度较短且访问频率较高,内存能加载更多的数据,命中率更高,减少了磁盘IO,从而提升了数据库性能。


优点:

1-解决业务系统层面的耦合,业务清晰
2-与微服务的治理类似,也能对不同业务的数据进行分级管理、维护、监控、扩展等
3-高并发场景下,垂直切分一定程度的提升IO、数据库连接数、单机硬件资源的瓶颈

缺点:

1-部分表无法join,只能通过接口聚合方式解决,提升了开发的复杂度
2-分布式事务处理复杂
3-依然存在单表数据量过大的问题(需要水平切分)

三、水平切分

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


库内分表:只解决了单一表数据量过大的问题,但没有将表分布到不同机器的库上,因此对于减轻MySQL数据库的压力来说,帮助不是很大,大家还是竞争同一个物理机的CPU、内存、网络IO,最好通过分库分表来解决。

优点:

不存在单库数据量过大、高并发的性能瓶颈,提升系统稳定性和负载能力
应用端改造较小,不需要拆分业务模块

缺点:

跨分片的事务一致性难以保证
跨库的join关联查询性能较差
数据多次扩展难度和维护量极大

水平切分的方法:

  1. 可以根据ID区间或者时间区间
  2. hash取模

以上是关于分库分表的知识的主要内容,如果未能解决你的问题,请参考以下文章

大厂必考:MySQL 分库分表

题库分库分表架构方案

太完整了!一个亿级分库分表项目的实战全过程解析

使用Sharding-JDBC实现分库分表

使用Sharding-JDBC实现分库分表

使用Sharding-JDBC实现分库分表