Hi,我是空夜,又是一周没见了!

今天分享一下最近学习的分库分表技术,主要涉及两方面:

  • 分库分表的原因和基本概念,包括分库分表技术、策略、动态分库分表方案等;
  • 以 Sharding Sphere + Spring Boot 为例,展示分库分表技术的实际使用;

本节文章主要学习自 Advanced Java,会在表现手法上略有不同。


为什么会有分库分表的需求呢?

这次不是产品的锅了,我们先来看看单库单表的问题:

单库:支持的并发有限,数据库服务器磁盘容量不足

单表:单表数据量太大,SQL 执行越来越慢

针对单库单表的缺陷,可以将某些经常被检索的数据放到类似 ElasticSearch 的搜索引擎中。但这并不能解决全部问题。

如果业务并发量很高,达到 1000 qps,单库应该是扛不住了。这时候肯定要分库分表的。

果然,单恋一只花是不能解决单身问题的!要想脱单,还是得广...


分库分表后可以达到什么效果?

分库后:可承受的并发量增加,服务器得以扩充,磁盘容量不再紧张

分表后:单表数据量变少,SQL 执行速度提升

注意,分库和分表是两件事。你可以只分库,在不同的库中有一些相同结构的同名表,也可以只分表,一张表在一个库中有多个不同名的分表;

总而言之,按你的需求来。


数据拆分的方向

垂直拆分:将一个表的不同字段拆分到不同表中,尤其是将频率较高的单独拆出来。这样,对于访问频率较高的数据,数据库可以缓存更多的行。(这样分表感觉就是根据业务来拆了,在业务层做控制,比如用户订单表、订单支付信息表、订单商品表等)

水平拆分:同一个表的数据拆分到多个库的多个表中,这些表的结构都相同。利用多个库的容量来扩容和提高并发请求的承受能力。

如果真的采用了分库分表的话,我个人感觉还是更专注水平拆分;而垂直拆分,一般在定需求的时候就已经分好了。


分库分表技术方案

目前有以下两种主流的技术方案:

  • Sharding Sphere: 当当开源的分布式数据库中间件解决方案。由 Sharding JDBC、Sharding Proxy、Sharding Sidecar 三款相互独立的产品组成。

Sharding 是在业务层进行分库分表;对于每个项目来说,各自引入 shardsphere 的依赖,添加分库分表的配置(其实就是对分库分表下的数据库的访问、路由配置)

  • Mycat: 在 proxy 层进行分库分表,需要自己运维一套中间件

所以,中小型公司一般用 Sharding Sphere 就够了。有足够能力的公司可以用 mycat 自己搭一个中间件。

说到这,你们应该还是有点迷。光是讲理论,没有实操也不行啊!不要担心,这篇文章后面,老衲也会给你们介绍一下 Sharding Sphere 的使用应用示例。


分库分表后如何平稳过渡上线

分库分表方案设计好了,程序也改好了,如何将新版本项目上线呢?

  • 停机,部署:这是最简单的方法,但我想聪明的你应该已经发现了华生,啊不,盲点。凌晨1点停机发布,让整个组陪你一块熬夜到天明,还是你打算让用户等着你更新,你也真敢想啊!

就不能想想别的法子嘛!

  • 双写迁移:不停机,先上一套双写的版本,然后上一套最新的分库分表版本,最后,后台将老库的一些遗漏的数据刷到新库里。

这里的双写是什么意思呢?就是说,我上线一个新版本的代码,这个版本中对数据库的操作,是对原有的旧库旧表,以及废了老大劲设计好的分库分表,同时进行修改。总而言之,要保持新库新表的数据一定要是最新的!

等等,好像还有点问题。

如果我第一次分库分表上线了,解决了业务扩张的问题,用户越来越多,公司估值水涨船高,老板数钱数到手抽筋,放话要给项目组发奖金。

正当你得意的时候,运维告诉你一个惊天噩耗:由于公司业务发展迅速,每日新增用户几十万,数据库又扛不住了!

这下完犊子了!再重新设计分库分表方案,恐怕是很难了。你要同时关注几个数据库,几十个分表(甚至更多),要保证数据的一致性等等... 要秃了。

别急,这不都是老衲吓唬你的嘛?马上给你解决方案:在一开始,就设计一个支持动态扩容缩容的分库分表方案。


如何设计一个动态扩容缩容的分库分表方案

  • 一次性定好有多少个库,多少个表,比如 32 个库,每个库分 32 个表,那么一个表被分成了 1024 张分表;这样,可以提前做好分库分表的策略,扩容缩容时,程序就不用修改了。
  • 简单来说,开始可能是一台数据库服务器,上面放这 32 个库;扩容时,如扩容成 4 个数据库服务器,每个数据库服务器上放 32/4 = 8 个库,每个库里还是 32 个表;
  • 极限情况:扩容到 32 个服务器,每个服务器一个库,每个库 32 个表;更极限,扩容至 1024 个服务器,每个服务器只有一个库一张表
  • 缩容同理。
  • 这种情况下,扩容缩容可以由 DBA(数据库管理员) 用一些工具快捷完成,不需要修改程序。

最后,还有一个小问题,咳咳,真的是最后一个了:分库分表情况下,如何保证同类型表中数据的 ID 不会重复呢?这就涉及到分布式 Id 生成策略了。


分库分表方案下的 id 主键生成策略

利用数据库自增 id:由一个无用的表来生成自增的 id,然后插入到真正的分表中。缺点是:能承受的并发量低。

这个方法前两天我们组内技术分享会上有个小伙伴就提到了,在分布式系统中,利用 MySQL 的 Id 自增机制,来解决分布式系统中的 id 重复问题。想不到啊想不到。

这个方法不是最优解,但程序开发没有银弹,能解决我们需求痛点的就是好办法!

雪花算法 SnowFlake:64 位,分布式 id 生成算法。下一节的示例代码也用的雪花算法。

基于雪花算法,还有一些扩展优化的 ID 生成策略。具体你可以自行百度,再写下去我晚上没得空吃了。

好了,理论部分学习完毕。下一节我们进入正题:在 Spring Boot 中如何使用 Sharding Shpere 来进行分库分表。

这篇文章换了下风格,自己也感觉舒服了


更多请关注公众号:猿生物语(ID:JavaApes

Last modification:October 31st, 2020 at 11:23 pm
请作者喝杯肥宅快乐水吧!