这些日子为了解决业务上的挑战,想要解决MySQL的性能提升方案。
目前找了主要有:
分库分表
读写分离
读写分离最简单,牺牲一点一致性能减少读的压力,分表也比较简单,但是目前没有特别合适的中间件,结合我们的业务场景,分库是目前最适合下点功夫的。(另外还需要做高可用,可以做双主,但是不需要我过多参与,因此这里不谈。)
背景介绍
MongoDB用来存储大部分非事务相关的业务
MySQL用来做电商相关业务,所有数据几乎都与账户ID相关
账户ID是MongoDB的ObjectId
对于普通用户来说没有关联到其他用户的操作
管理员需要统计以及查看所有的用户数据
分库算法
一致性hash
需要停机,遍历所有库,将需要移动的数据移动到新的库上。【1】【3】
具体步骤
停机 => 数据迁移(不删除旧数据) => 调整服务器配置 => 上线 => 遍历检查并删除各个库冗余的数据
优点
平滑提升性能,节约服务器
迁移过程中移动数据很少
缺点
线上迁移时间时间会比较久
计算速度没有取模快
取模
也算是一种一致性hash,只不过更简单;
拆库的方案是按2的倍数去拆,比如先拆成2个库,然后需要扩容的时候拆成4个,不然的话可能每次迁移都得全部重新迁移;
具体步骤
停机 => 所有的库复制一份 => 调整服务器配置 => 上线 => 遍历检查并删除各个库冗余的数据
优点
数据会非常均匀;
由于不用操作迁移数据库,直接使用备份恢复的方式,线上扩容速度会快很多;
一次拆库之后能坚持很长时间;
缺点
比较耗服务器,比如每个库最多放100W个用户的数据,那数据涨到150W左右的时候就应该拆分了;
无论怎么拆,性能都是跳跃性提升的,不能平滑提升;
由于我们使用的是mongodb的ObjectId,数据不均匀的可能性非常高;
好了,无论怎么分,都会涉及到停机升级的问题,但是停机意味着损失收入,那么为了解决停机的问题,我们找到了一个迁移方案:索引表。【2】
经过上面的比较,为了让数据库不停机以及迁移尽可能快,我们选择一致性hash方案再加上索引表:
每次根据用户ID取库的时候,先查索引表,如果没有,再计算;
开启定时任务,定期扫描,迁移数据,再更新索引表;
迁移需要注意一点就是需要锁住数据,手动进行两阶段事务,不然可能会造成数据不一致,然后这个迁移任务尽量在凌晨无人的时候进行,而且也只是单个用户,因此这样可以将对用户的影响减到最少。【2】
几个问题
是否需要公共库?
如果是公共库,很可能是跟事务不相关的,移到MongoDB即可。
MySQL ID自增怎么解决?
换成ObjectID,或者UUID之类的。
Node.js有没有相关的中间件?
可以看看TribeDB,但是不满足我们目前的需求。(蠢蠢欲动想要造轮子了
select *,order by之类的需要跨库,或者联合所有库的操作怎么办?
这些操作在我们这一般是管理后台才要用,所以可以放到其它工具去做,比如elasticsearch,而且这样的查询会影响数据库性能,我们巴不得砍掉这些查询
其他问题可以看看【2】,内容很详实。
Reference