【Java架构师】分库分表看这一篇就够了

目录

一、什么是分库分表?

二、怎么分库?

三、什么时候分表?

四、横向拆分和纵向拆分

五、分表字段如何选择?

六、分表算法

直接取模

按照关键字

Hash取模

一致性Hash

七、全局ID的生成

八、分库分表的工具

Sharding-JDBC

TDDL

Mycat


一、什么是分库分表?

分库分表,是企业里面比较常见的针对高并发、数据量大的场景下的一种技术优化方案。所谓“分库分表”,根本就不是一件事儿,而是三件事儿,他们要解决的问题也都不一样。

这三个事儿分别是“只分库不分表”、“只分表不分库”、以及“既分库又分表”。

分库主要解决的是并发量大的问题。 因为并发量一旦上来了,那么数据库就可能会成为瓶颈,因为数据库的连接数是有限的,虽然可以调整,但是也不是无限调整的。所以,当你的数据库的读或者写的 QPS 过高,导致你的数据库连接数不足的时候,就需要考虑分库了,通过增加数据库实例的方式来提供更多的可用数据库链接,从而提升系统的并发度。

分表主要解决的是数据量大的问题。 假如你的单表数据量非常大,因为并发不高,数据量连接可能还够,但是存储和查询的性能遇到了瓶颈了,你做了很多优化之后还是无法提升效率的时候,就需要考虑做分表了。

那么,当你的数据库链接也不够了,并且单表数据量也很大导致查询比较慢的时候,就需要做既分库又分表了。

二、怎么分库?

分库主要解决的是并发量大的问题。比较典型的分库的场景就是我们在做微服务拆分的时候,就会按照业务边界,把各个业务的数据从一个单一的数据库中拆分开,分别把订单、物流、商品、会员等数据,分别放到单独的数据库中。

还有就是有的时候可能会需要把历史订单挪到历史库里面去,这也是分库的一些具体做法。

三、什么时候分表?

一般我们认为,单表行数超过 500 万行或者单表容量超过 2GB 之后,才需要考虑做分库分表了,小于这个数据量,遇到性能问题建议大家通过其他优化来解决。

PS:以上数据,是阿里巴巴 Java 开发手册中给出的数据,偏保守。根据实际经验来说,单表抗 2000 万数据问题不大,但具体的数据量还是要看记录大小、存储引擎设置、硬件配置等。

那如果,既需要解决并发量大的问题,又需要解决数据量大的问题的时候。通常情况下,高并发和数据量大的问题都是同时发生的,所以,我们会经常遇到分库分表需要同时进行的情况。

所以,当你的数据库连接也不够了,并且单表数据量也很大导致查询比较慢的时候,就需要做既分库又分表了。

四、横向拆分和纵向拆分

谈及到分库分表,那就涉及到该如何做拆分的问题。

通常在做拆分的时候有两种分法,分别是横向拆分(水平拆分)和纵向拆分(垂直拆分)。假如我们有一张表,如果把这张表中某一条记录的多个字段,拆分到多张表中,这种就是纵向拆分。那如果把一张表中的不同的记录分别放到不同的表中,这种就是横向拆分。

横向拆分的结果是数据库表中的数据会分散到多张分表中,使得每一个单表中的数据的条数都有所下降。比如我们可以把不同的用户的订单分表拆分放到不同的表中。

纵向拆分的结果是数据库表中的数据的字段数会变少,使得每一个单表中的数据的存储有所下降。比如我可以把商品详情信息、价格信息、库存信息等等分别拆分到不同的表中。

还有我们谈到的针对不同的业务做拆分成多个数据库的这种情况,其实也是纵向拆分的一种。

五、分表字段如何选择?

这里参考我另一篇文章:https://blog.csdn.net/qq_38196449/article/details/141528400?ops_request_misc=%257B%2522request%255Fid%2522%253A%25227ca6128406c7f8750b4a0000de944c2c%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=7ca6128406c7f8750b4a0000de944c2c&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-141528400-null-null.nonecase&utm_term=%E5%88%86%E8%A1%A8%E5%AD%97%E6%AE%B5&spm=1018.2226.3001.4450https://blog.csdn.net/qq_38196449/article/details/141528400?ops_request_misc=%257B%2522request%255Fid%2522%253A%25227ca6128406c7f8750b4a0000de944c2c%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=7ca6128406c7f8750b4a0000de944c2c&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-141528400-null-null.nonecase&utm_term=%E5%88%86%E8%A1%A8%E5%AD%97%E6%AE%B5&spm=1018.2226.3001.4450

六、分表算法

如何基于这个分表字段来准确地把数据分表到某一张表中?

这就是分表算法要做的事情了,但是不管什么算法,我们都需要确保一个前提,那就是同一个分表字段,经过这个算法处理后,得到的结果一定是一致的,不可变的。

通常情况下,当我们对 order 表进行分表的时候,比如我们要分成 128 张表的话,那么得到的 128 张表应该是:order_0000、order_0001、order_0002……order_0126、order_0127。

通常的分表算法有以下几种:

直接取模

在分库分表时,我们是事先可以知道要分成多少个库和多少张表的,所以,比较简单的就是取模的方式。

比如我们要分成128张表的话,就用一个整数(可以是你的某个业务单据号的值或者它的hashcode的值,比如用户id,或者订单号之类的)来对128取模就行了,得到的结果如果是0002,那么就把数据放到order_0002这张表中。

按照关键字

有的时候,我们在分表的时候,可以给予一定的关键字做拆分,比如按照时间,比如某个月份或者年份的数据单独放在某一个表中,或者可以按照地区分表也比较常见。

Hash取模

那如果分表字段不是数字类型,而是字符串类型怎么办呢?有一个办法就是哈希取模,就是先对这个分表字段取Hash,然后再取模。

但是需要注意的是,Java中的hash方法得到的结果有可能是负数,需要考虑这种负数的情况。

一致性Hash

前面两种取模方式都比较不错,可以使我们的数据比较均匀地分布到多张表中。但是还是存在一个缺点。

那就是如果需要扩容二次分表,表的总数量发生变化时,就需要重新计算 hash 值,就需要涉及到数据迁移了。

为了解决扩容的问题,我们可以采用一致性哈希的方式来分表。

一致性哈希可以按照常用的 hash 算法来将对应的 key 哈希到一个具有 2^32 次方个节点的空间中,形成一个顺时针首尾相接的闭合的环形。所以当添加一台新的数据库服务器时,只有增加服务器的位置和逆时针方向第一台服务器之间的键会受影响。

七、全局ID的生成

这里参考我另一篇文章:

https://blog.csdn.net/qq_38196449/article/details/141558758?ops_request_misc=%257B%2522request%255Fid%2522%253A%252215b882dfead0fd3ca843041502729600%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=15b882dfead0fd3ca843041502729600&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-141558758-null-null.nonecase&utm_term=%E5%88%86%E8%A1%A8%E7%AE%97%E6%B3%95&spm=1018.2226.3001.4450https://blog.csdn.net/qq_38196449/article/details/141558758?ops_request_misc=%257B%2522request%255Fid%2522%253A%252215b882dfead0fd3ca843041502729600%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=15b882dfead0fd3ca843041502729600&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-141558758-null-null.nonecase&utm_term=%E5%88%86%E8%A1%A8%E7%AE%97%E6%B3%95&spm=1018.2226.3001.4450

八、分库分表的工具

在选定了分表字段和分表算法之后,那么,如何把这些功能给实现出来,需要怎么做呢?

我们如何可以做到像处理单表一样处理分库分表的数据呢?这就需要用到一个分库分表的工具了。

目前市面上比较不错的分库分表的开源框架主要有三个,分别是 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Calvad0s

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值