0

什么,你还不知道什么是分库分表?

 3 years ago
source link: http://www.eknown.cn/index.php/default/distributed-databse.html
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.

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

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

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

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

image-1604138204446.png


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

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

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

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

image-1604138242717.jpeg

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

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

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

image-1604138270077.jpg

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

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

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

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

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

image-1604138297471.jpeg

数据拆分的方向

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

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

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

image-1604138345060.jpeg

分库分表技术方案

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

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

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

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

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

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

image-1604138395252.gif

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

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

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

就不能想想别的法子嘛!

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

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

等等,好像还有点问题。

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

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

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

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


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

  • 一次性定好有多少个库,多少个表,比如 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 生成策略。具体你可以自行百度,再写下去我晚上没得空吃了。

image-1604138499227.jpeg

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

image-1604138527619.jpg

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

image-1604138546802.jpeg

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK