为什么要分库分表
在之前的文章中也说了,当一个系统想要支撑高并发高性能,那么数据库就必然会成为增加QPS的瓶颈。哪怕是你用上了redis缓存,MQ消息队列,但是写的请求最终还是要落在数据库中。
刚开始的时候小项目也许是可以的,10万用户,100万用户,那怕1000万用户,用缓存和队列削峰之后,数据库性能好点,其实也还是可以抗住的,但是想再优化的话,就必须要优化数据库,进行分库分表。
这时候我们要知道,分库和分表是两个概念,有可能分库不分表,有可能分表不分库。
什么是分库?
一个库的并发一般只能2000左右,并且健康状态下最好是1000,那么想要支撑高并发,就可以将数据拆分。比如将原本的数据拆分为3个不同的库,将数据分为3份拆分到不同的库中,这样一个库肯定并发量不到1000了。
什么是分表?
顾名思义,一个表的数据分成多份放在不同的表中,、。可以按照用户id来分,这样每个表承受的压力就会小一些,并且可以限制一下每个表的请求量
常用的分库分表中间件
在我们真正使用分库分表的时候,并不是我们的系统主动获取数据到底存在哪个库中哪个表中,这些动作都是交给分库分表中间件来做的。
一般常用的有下面这些,当然并不全面。只是列举一些:
cobar:阿里b2b团队开发和开源的,属于proxy层方案。早几年还可以用,最近几年没更新了,也很少再有人用,基本属于被抛弃状态。而且不支持读写分离,存储过程,夸库join和分页的操作。
TDDL:淘宝团队开发的,属于client层面方案。不支持join和多表查询等语法。基本的crud语法是OK的,而且支持读写分离。但是目前使用的也不多,因为要依赖淘宝的diamond配置管理系统。
atlas:360开源的,属于proxy层方案,以前有公司再用,但是进5-6年都没有更新了。所以现在也很少有公司用。
sharding-jdbc:当当开源的,属于client层方案。之前确实用的比较多,因为sql语法支持的比较多,没有太多限制,目前推出了2.0版本。支持分库分表,读写分离,分布式id生成,柔性事务(最大努力送达型事务,TCC事务)。确实之前用的公司比较多一些,个人认为是一个现在也可以选择的方案。
mycat:基于cobar改造的,属于proxy层面方案。支持功能非常完善,现在是属于比较火,并且是流行中的中间件,社区很活跃,但是相对于sharding-jdbc确实年轻一些,锤炼少一些。
PS备注:
proxy层方案意思是该中间件是需要独立部署在一个主机上, 与业务进行通信。
client层方案意思是该中间件嵌入在业务系统中,通过一个jar引用,直接调用方法来实现与数据的的通信。
如何选型
个人建议,中小型公司使用sharding-jdbc,因为它是直接嵌入在项目中,方便维护,运维成本低,不用额外增派人手。而mycat是一个独立式的中间件,中大型的公司可以使用这个,派专人专门维护,因为大型公司业务本来就复杂,可以专人研究运维这个东西,后面有其他业务需要直接使用就好。
如何拆分数据库
总的来说分为水平拆分和垂直拆分。
水平拆分
把一个表中的数据拆到多个库的多个表中,每个库中表结构都是一样的,但是存储的数据不同,所有库中的数据合在一块才是完整的数据。水平拆分的意义就是将数据均匀的分布,用更多的库来扛更高的并发量,同时也是使用多个库来进行扩容。
垂直拆分
把原本一个很多字段的表,拆分成很多的表,或者是分布到多个库上去。每个库的表结构都不一样,也就说每个库的表都包含一部分字段。一般来说会将较少、访问频率高的字段放到一张表中;将较多、访问频率低的字段放到另一张表中。因为数据库是有缓存的,访问频率高的字段量越少,那么缓存的数据就越多,那么性能就越好。
表层面的拆分
就是分表,将一个表中的数据分为N个表,结构都是一样的,让每个表的数据量控制在一定的范围内,来保证sql的性能。因为一个表的数据越多,那么sql性能就越低下。
分库分库数据迁移
1、停机迁移
很简单,就是在请求低谷期的时候发个公告,比如0-6点的时候,说系统升级不支持访问。然后我们就写个工具将老数据库中的数据,按照分库分表的规则一张张的导入到新表就是了。
假如说有600万的数据,那么开20个线程,基本上一个小时就可以搞完,但是如果中间出现了问题,凌晨4点还没解决,就要考虑先恢复系统原本正常的功能,基于单库单表正常运行,第二天凌晨时候再重新搞。
这个缺点就是比较low,系统会出现几个小时的停滞,并且凌晨一群人通宵肯定吃不消。
2、双写方案
首先修改当前程序中的写数据库代码,让它同时写老库和新库,这样新的数据就会在新库中存在。
然后开一个后台工具,去将老库中的旧数据慢慢同步到新库中,但是要注意,旧数据绝对不可以覆盖新库中的新数据。这样更新完一轮之后,需要核对两个库的数据是否一致,如果确认两个库的数据一致了,那么就可以考虑将读写请求完全切换到新库。
如何动态扩容分库分表
假如说当前系统运行的分库分表结构性能已经快要拉满了,那么就需要更好性能的分库分表,分更多的库更多的表,那么这时候数据如何迁移呢。
1、停机扩容
这个和停机迁移一样,就是停止系统的运行,然后对数据进行迁移。但是一般不要这么搞,因为既然分库分表了,说明肯定数据量不会小,那么迁移用的时间会很长,并且容易出问题。一般没有人会真的这么用,太low了
2、优化扩容
这个意思是将原本在同一个主机上的数据库,分别放在不同的主机上。
比如,现在我们现在有4台数据库服务器,每个主机8个库。想要扩容的话,可以再增加4台数据库服务器,一共8台主机,每个服务器4个库,表呢都是同样的数量。这样容量不就增加了吗,只需要由dba将数据库整体迁移到另一个数据库。
如果说32个库放在8台主机上容量还是不够,那么可以一个库一个服务器,也就是32个服务器。
分库分表如何管理主键id
一个表的数据拆分之后分布到多个库中,id是不能重复的。
1、数据库自增id
这时候新增数据时,就需要在一个专门的库里面建立一个自增序列。每次插入数据的时候,无论是插那个表,都需要先到这个库中获取自增序列值,然后再将数据插入相应的库中。缺点就是单库中获取自增序列会成为并发量的瓶颈。
2、本地生成uuid
好处就是本地生成,可以不用基于数据库了。但缺点就是uuid太长,作为主键id的话会影响性能。
3、获取系统当前时间
这个如果是和数据中其他字段拼接的话还可以,但是如果单独用它作为主键的话基本是不行的,因为并发量高的情况下肯定会重复。
4、snowflake算法
twitter开源的算法,就是把一个64位的long型id,1个bit是不用的,41个bit作为毫秒数,10个bit作为工作机器id,12个bit作为序列号。

1290

被折叠的 条评论
为什么被折叠?



