在系统上线后,由于业务的变动或者业务的激增, 会面临需要进行分表的情况;
如何才能提供完整的分表的方案, 需要进行一些思考; 本文结合自己负责的项目, 记录一次分表操作。
背景: 系统中存在一个历史记录表T1, 存储不同用户的活动历史, 活动类型有多种,记为N种, 每种活动类型的玩法不同。 用户也分为不同渠道的用户,记为M种用户。 用户历史记录只保留用户最近3个月数据。 由于每天新增数据量太多。 保留太多会增加数据库压力。
在此背景下,产品提出某几类活动的用户历史需要长期保存, 方便用户查看。 A类用户,没有对应的活动历史需要保留, A类用户数据量庞大, B类用户需要保留部分活动历史, B类用户数据量较小。
方案1: 按照活动类型分表, 需要保留活动历史的为一个表,不需要保留活动历史的为一个表,但是当用户查询自己的活动历史时, 需要查询多个表
方案2: 按照用户类型来分表, A 类用户所有的活动存储一个表, 只保留几个月;B类用户所有活动存储一个表, 因为数据量小,可以长期保留;用户查询活动历史时,只需要查询一个表,减少数据库压力。但是部分活动历史不需要长期保留也保留下来了。
最后选择了方案2, 总体来说,方案2的改造成本是要低于方案1。 代码实现还是以后的维护。
还有难题,如何在不停服的情况下灰度上线呢?是否可以做到呢?
答案是可以的, 需要分步上线,先上线查询功能, 之前从A表中查询,变成从A 和 B 表中同时查询, 查询到的记录进行去重, 等所有机器上线完成查询分表功能, 再继续上线插入和更新到新表的功能。 由于不能停服, 在上线的过程中, 用户还会不断的去插入和更新, 这个时候,没有更新最新版本的服务,继续往老表中插入和更新, 更新了最新版本的服务,插入和更新分开处理:
插入: 往新表中插入
更新: 先尝试更新新表,更新失败更新老表, 更新老表的同时将老表中的数据删除, 插入到新表中。
等到插入和更新分表也上线后, 将老表中的B类用户的历史数据导出来, 然后导入到新的B类用户的B表中。可能会问,在导出和导入的间隙, B类用户的A表数据完成了更新,再导入到B类用户的B表中还是更新前的数据,这样更新就会丢失。 其实可以避免,因为一旦更新了老表就会将老表中的数据删除并更新到新表, 那么导入操作相同的id 数据会导入失败,这样就可以避免间隙期间,更新丢失的问题。 B类用户数据量不大,导出和导入的间隙不超过10 分钟, 这样等导出和导入完成,就可以开始删除A 表中的几个月前的数据,保持A表的数据量在一个健康的量级