这是我参与2022首次更文挑战的第16天,活动详情查看:2022首次更文挑战
背景
- 业务数据比较多,而且历史数据不能够直接删除
-
- 数据审查需要
- 业务场景可能会用到较为旧的数据(至少为1年)
- 数据较为敏感,尽可能地不接入公司内的其他数据平台
- 目前数据已经达到了单库的上限
- 业务场景分时严重
-
- 月末的时候产生、使用大量数据
- 峰值时,给服务以及数据库带来很大压力
-
- 数据库压力过大,出现invalid connection
- 业务大量重试给到数据库更大的压力
- 冷热数据分布明显
-
- 当月数据会大量访问,历史数据访问量很少
- 尽管已经按照月份的形式进行分表,但是对于冷热数据问题并没有很好的解决
-
- 依旧会集中打当前月表
因此我们需要一个方案来解决以上问题
- 数据量问题
-
- 需要更大的容量,并且可以随着业务发展、在业务无感知的情况下进行扩容
- 第二点和第三点都是数据访问上的问题,会给数据库带来比较大的读写压力
-
- 多点的方式分担数据读写压力
方案选型
存储方案选型
小结
通过上述比较,使用分片库能够带来的提升最大
- 两者虽然看上去都是无限容量的
-
- 但是冷热库增加的库对于业务并不是无感知的
-
- 每次增加新的冷热库都需要业务方手动加上新的库
- 业务需要自己实现路由到不同库的逻辑,当库发生变动的时候,需要自己进行路由适配
- 分片库在数据库侧做了封装
-
- 只要带上分库键,其实现的路由策略会自动路由到对应的库,当数据库进行扩容的时候对业务侧无感知
- 初次接入的业务方也有一定的改造量
-
- 需要确保查询语句带上了分库键以保证最高性能
- 更新、创建语句大多都已经带上了分库键
- 一旦数据写入,不允许修改分库键的值
- 部分问题以及限制在第二部分讲
- 性能方面
-
- 分片库由于是多库,在方案合理的情况下可以提升较多性能
-
- 不同库同表的并发写入
- 读也会分发到多个库,降低同库同表的读写锁冲突
- 两者都不需要对原有的mysql driver进行更新
从结论上来说选择分库方案:
- 更好的可扩展性
- 更好的性能
- 可接受的修改量
分片库方案设计
限制
从增删改查来说:
增:
- 单记录
-
- 需带上分库键
- 多记录
-
- 分片库之间没有实现分布式事务,不提供原子性,需要业务上来保证,使得批量新增失败后的结果是符合预期的
- 不支持跨分片库的prepare多行插入,支持同个分片库内的prepare多行插入
-
- 什么是prepare插入
- 不同分片库内的主键id并不能保证全局唯一,不同库同表的id会重复
删:
- 单记录
-
- 可不带上分库键,带上会有更好的性能
改:
- 单记录
-
- 不可修改分库键的值
- 多记录
-
- 同样不能保证跨库的事务,业务上需要自己实现对应的原子性保证逻辑
查:
- 单记录
-
- 不支持跨分片库的distinct操作
- 查询需要带上分库键
- 多记录
-
- 由于查询需要带上分库键,in查询需要拆分每次查询的分库键,由in变成==
总结
- 若一个SQL本身就只会在一个分片库内执行,且带上了分库键,那么不需要任何修改
- 跨多个库的操作得不到保障,需要业务上做处理
- 自增id在不同库同表中并不能保障全局唯一性
- 需要带上分库键
分库键设计
现状
可以看到目前的存储结构为
- 按月分表
- 当月数据操作量较大
- 每个表中的数据可以按活动维度进行划分
-
- 活动有多条数据
- 同活动内数据同时使用的概率较大,较少出现跨活动使用的情况
分库方案
按月分库
- 可以解决扩容问题
- 无法解决冷热数据访问问题
- 由于现在是按月分表,表字段中不存在月份字段,需要新增一个月份字段,用于分库
-
- 历史数据需要新增该字段,并刷上值
- 所有数据库操作均带上月份字段
按活动分库
- 可以解决扩容问题
- 通过hash活动ID的方式,将同表的不同活动数据分散到不同的库
-
- 流量更加均匀的打到不同库上,可以实现负载均衡
-
- 锁开销降低
- 读写吞吐增大
- 提高数据库缓存命中率
- 表需新增活动ID列
-
- 需要刷上新的列值
- 所有的操作需要带上分库键
- 同表的主键ID不能保证唯一性
-
- 不会影响业务
小结
使用按活动ID进行分库会更好
代码修改
上线以及回滚操作
部署过程
- 需要先在单库上新增活动ID字段
- 使用工具给活动ID字段刷值
- 申请分片库实例
- 分片库建表
- 使用数据同步工具全量+增量模式将单库数据全量同步到
- 将单库设置为只读
-
- 需要单库停写,需要和业务方对齐
- 调整代码数据库连接配置,部署服务
- 观察数据库读写流量
-
- 读写流量都在分片库
能否去除第6步?或者去除停机过程?这一步的目的是什么?
回滚方案
需要注意的是分库不能保证同表不同库的主键ID全局唯一,在回滚、同步分片库到单库的时候会出现主键ID冲突的问题,需要自己使用分布式ID生成工具生成ID,插入数据时显示声明ID值
- 使用分布式ID生成工具生成ID
- 配置分片库到单库的同步工具、同步规则
- 需要回滚时,直接回滚线上实例到上一个版本即可,重置为连接单库