当前位置: 首页 > article >正文

数据分库分表和迁移方案

在我们业务快速发展的过程中,数据量必然也会迎来突飞猛涨。那么当我们的数据量百倍、千倍、万倍、亿倍增长后,原有的单表性能就不能满足我们日常的查询和写入了,此时数据架构就不得不进行拆分,比如单表拆分成10张表、100张表、单个月分多张表等等。下面我们针对具体案例分析下这种情况。

一、现状分析

直播签到业务中,有如下两张表,签到表和用户签到记录表。其中用户签到记录表t_sign_in_record现有数据量达到了18亿,数据占用空间为233G,索引占用空间为310G,总占用空间为543G。单表数据量太大,导致数据查询和写入性能过低。如果某条sql查询未使用到索引,很容易就会将数据库打挂。所以对t_sign_in_record的单表拆分很迫切

CREATE TABLE `t_sign_in` (
  `id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT '主键自增id',
  `sign_in_id` varchar(64) NOT NULL DEFAULT '' COMMENT '签到id',
  `shop_id` varchar(64) NOT NULL DEFAULT '' COMMENT '商家id',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  KEY `idx_shop_sign` (`shop_id`,`sign_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='签到表';

CREATE TABLE `t_sign_in_record` (
  `id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT '主键自增id',
  `sign_in_id` varchar(64) NOT NULL DEFAULT '' COMMENT '签到id',
  `shop_id` varchar(64) NOT NULL DEFAULT '' COMMENT '商家id',
  `user_id` varchar(64) NOT NULL DEFAULT '' COMMENT '用户id',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  KEY `idx_shop_sign_user` (`shop_id`,`sign_id`,`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='用户签到记录表';

二、数据库设计

1、分表实例:依现有的存储空间做10倍的余量参考,所需空间大小为5.3T左右。而腾讯云MySQL最高支持存储空间上限是6TB,所以原有的腾讯云MySQL实例能满足需求。如果数据量更大,超过6TB的话,可以考虑将数据库迁移至TDSQL-C MySQL 版,最高支持至400TB。参考文档:https://cloud.tencent.com/document/product/1003/30488

2、分表数量:按照业务增长规模,每个月增量7千万-1亿,预计分10张表,平均单表数量在700万-1000万左右

3、分表算法:根据签到表t_sign_in的created_at中的年月日做如下算法,能让数据较均匀的落入每个月的10个分表中。分表的10张表名为t_sign_in_record_0、t_sign_in_record_1…t_sign_in_record_9
在这里插入图片描述

三、迁移方案

1、第一阶段:
双写数据,即将数据同时写入旧表t_sign_in_record和分表t_sign_in_record_0、t_sign_in_record_1、t_sign_in_record_2…中,此时需要去代码层创建和更新t_sign_in_record表的地方做处理,写入旧表的同时,写一份数据到新的分表。

2、第二阶段:
双写数据一致性校验,经过第一阶段的双写后,我们的新数据已经同时存在于新表和旧表中了,这个时候需要去check一下数据在旧表t_sign_in_record和分表t_sign_in_record_0…中是不是保持一致。有两个常用的检验方法:
(1)第一种是人工校验,即随机挑选一些签到,去check对应的签到记录条数和数据记录是否一致;
(2)另一种是写脚本去校验(全量数据或部分数据),将其中新老表中数据不匹配的记录输出到日志中,再去排查。

3、第三阶段:
写脚本,将旧表t_sign_in_record的存量数据都刷到分表t_sign_in_record_0…中。

4、第四阶段:
跟第二阶段的方式一样,去check第三阶段刷入的分表存量数据是否和旧表一致

5、第五阶段:
切读,将现网读 t_sign_in_record 表的地方都改为读新分表 t_sign_in_record_0、t_sign_in_record_1、t_sign_in_record_2…

6、第六阶段:
确认旧表 t_sign_in_record没有新的读请求。可通过DBA审计的方式。

7、第七阶段:
停止双写,即将代码改为只往新分表 t_sign_in_record_0、t_sign_in_record_1、t_sign_in_record_2… 里面写数据。

如上所述,迁移方案大概分为7个阶段,其中有三个阶段都是check数据一致性,在实际迁移时可以和其它步骤同时进行。拆分的整体时间周期一般为半个月到一个月之间,主要是其中为了确保数据一致性,需要灰度比较久

上面就是我们工作中常用的数据库表迁移方案了,有同学可能会甩锅给最初设计库表的同学,为啥当初设计的时候不考虑下分表呢?其实,这个是很难预估的,谁能知道最初一年只有几万数据的签到业务,现在每年会新增十来亿呢?这个主要取决于公司的发展了。


http://www.kler.cn/a/515088.html

相关文章:

  • 构建高效稳定的网络环境
  • 【组件库】使用Vue2+AntV X6+ElementUI 实现拖拽配置自定义vue节点
  • C#深度神经网络(TensorFlow.NET)
  • 2D 超声心动图视频到 3D 心脏形状重建的临床应用| 文献速递-医学影像人工智能进展
  • java开发,IDEA转战VSCODE配置(mac)
  • Java 8 实战 书籍知识点散记
  • 利用ML.NET精准提取人名
  • PyQt5之QCalendarWidget
  • python-leetcode-逆波兰表达式求值
  • jenkins平台使用Login Theme、Customizable Header插件定制修改登陆页图片文字及首页标题
  • 【Let‘s do第四期】DIY液体流量检测仪
  • Apache Hive3定位表并更改其位置
  • 【计算机网络】NAT应用
  • 如何保护 Flask API 的安全性?
  • javaSE.浮点类型
  • 生成对抗网络(GAN)入门与编程实现
  • LeetCode:53. 最大子序和
  • 初始Transformer
  • C++ STL(8)map
  • 正则表达式的艺术:轻松驾驭 Python 的 re 库
  • 智能鞋利用机器学习和深度学习技术进行患者监测和步态分析的演变与挑战
  • Roland 键盘合成器接声卡(福克斯特/雅马哈)声音小/音质异常的问题
  • insight在线需求分析系统概要介绍
  • redis离线安装部署详解(包括一键启动)
  • 为什么要申请专利
  • LiveBench:AI 模型基准测试与评估工具解析与实战指南