分库分表
更新: 5/5/2025 字数: 0 字 时长: 0 分钟
分库分表也是近年来常常会出现的一个问题,这玩意一般只会在高并发,数据量大的情况才会使用,其实你想想也就明白了,为什么要分库分表,说明单库单表不够用了呗,那为啥单库单表不够用?还不是因为装不下或者请求相应时间太长了
分表
有的单表都干到千万级了,这破表还扛得住吗,一个SQL查询直接慢到死,一般单表数据量达到百万也就该分表了
分表就是将一个表里的数据分开来存放,一般会找一个字段来区分,比如将原表按照用户id区分,这样找这个表下这个id的用户的数据只需要找这个表就行
分库
一般一个库也就支撑的起2000的并发量,一般到达1000并发的时候就要分库了,分库就是将原本一个库的数据分到多个库,访问时访问某个指定的库就行
(现在的分布式设计也有这个感觉,一般一个模块一个单独的库,大家互不干扰)
常见的分库分表中间件
这里主要提两个
Mycat
基于老牌分库分表中间件Cobar进行改造,属于Proxy方案,也就是在应用服务器和数据库服务器中间单独架一个新的服务,由他来完成分发的功能
这个中间件曾经火过一阵子,但是我最近去查了一下好像又停止维护了,只能说大家相信老牌的开源方案不是没有理由的
或许有的公司还在使用这个方案并且在自己内部维护,但是如果公司能力不够,那还是选择一个持续维护的开源方案会比较好
Apache Sharding Sphere
那要说老牌谁能比得过Apache呢,这里就给大家推荐Apache开源项目Sharding Sphere,其中有Sharding-JDBC和Sharding-Proxy两种方案,其中Sharding-Proxy就是上面提到的Proxy方案,而Sharding-JDBC则是client方案,也就是将分库分表的逻辑集成到你的应用当中
如何对数据库进行水平/垂直拆分
水平拆分就是将一个表横着裁成多个,表的结构相同,但是数据不同,这样做最大的意义就是将数据分散开来,因此来扛住更高的并发量,同时也更容易的进行扩容
垂直才分就是根据字段的业务逻辑拆分成多个表,这个就算不是高并发设计也很常见,比如用户表,用户详情表等,这样做最大的意义就是限制表的字段数量,放置一个表的字段过多进而影响SQL的响应速度
那我问你,你是上来就分库分表的吗?如果不是怎么平稳过渡呢?
这个问题其实就是再问你是如何将原架构迁移为分库分表的,因为这种场景在一些老公司很常见,由于用户量和业务量不断地增加,早期的数据库设计方案不再适用,因此不得不切换为分库分表的方案,这个切换的过程如何能够平稳落地是公司格外在乎的
双写迁移
首先就是将新库上线,然后将老库的增删改操作全部在新库操作一遍(也就是所谓的双写),然后对原本存放的数据进行不停机的写入新库的操作,写的时候记得根据原本留底的时间戳进行操作,比如老的数据已经被覆盖掉了,也就不用更新到新库里了。
这样一轮下来,新老库的差距基本就很小了,然后再用程序自动做一遍校验,来查询新老库的不同,如果没有不一致的地方就是认为成功迁移
数据库如何平稳扩容
同样的问题,同样的需求,就是公司的老库撑不住了,现在继续换一个新库上来,这时候就需要来进行扩容
由于库和表不同,库中的数据比表多太多,可能一次扩容就要半天的事件,而这半天还有一大半的时间是在等自动化工具迁移完成,相当于全员便秘,怎么可能会容许这种事情发生,因此我们会推荐一次扩容就扩够,那什么是够呢?
一开始上来就是 32 个库,每个库 32 个表,那么总共是 1024 张表。一个库的正常承载的写入并发量是1000那32个库就是32000的并发量,这种情况再加上MQ的削峰和Sentinel的限流,很难不够用
所以一旦设计分库分表,就应该在第一次给他分够,防止后面出现的大量数据导入导出的便秘事件
一个简单的步骤
- 设定好服务器以及服务器上的表数
- 设计好路由的规则,比如id%32=表id
- 扩容的时候申请增加更多的服务器,整体成倍数扩容(2,4,8,16,32),当然,我们之前说了,最好起点就从32开始
- 然后由DBA进行迁移即可
主键ID如何处理?
这是分表后必然会带来的问题,由于你用到了多个表,而且这些表还都是表示的相同的业务,那么你再使用数据库自增Id就不合适了,会出现大量的重复
目前市面上的主流方案是雪花算法以及雪花算法的再改良,有很多的开源分布式方案,这里就放一个我最常用的在这里
为什么一定要选用自增Id
我们会发现不论是雪花ID还是Leaf,他们都有一个共同的特点,那就是自增。同样的,我们还知道一个全局唯一的Id生成策略——UUID,这个就不是自增的,为什么不用他来作为ID呢?
其实我们也不少发现使用UUID来作为标识的情况,比如文件名一类的,但很少会用他作为主键ID,主要考量就两个
- 太长了:占用空间大导致查询性能差
- 不自增:由于UUID无序,导致B+Tree在写入的时候会有过多的随机写操作,这对效率也是很大的影响