简单分表场景下的业务发散思考:分表如何保证丝滑?

分表如何保证丝滑?------ 从一个「纯新增」场景聊到大厂主流方案

最近搞了个设备数据分表的需求,踩了点小坑,顺便思考了下大厂的主流玩法,整理记录一下。

一、 起因:一个「无删改」的简单分表需求

我们项目有个设备数据表,之前数据量不大,单表+索引+分区足以解决。 但随着设备数上去了,数据越堆越多。 某天一看已经2000w条设备数据了

领导一看,说做分表!

我稍加思索了下分表核心要保证的问题,一是保证数据不丢失,二是保证数据一致性,而我们的这个设备表,只做数据记录,没有修改,没有删除

那么这个场景就很纯粹了:

  • 设备表只有 新增 + 查询 操作,没有更新、没有删除,完美避开了最麻烦的数据变更问题
  • 要把老库的历史数据同步到新库分表,同时保证新数据双写不丢
  • 要求 零业务感知、零丢数、可重试

我的「丝滑」解决方案思路

既然是纯新增场景,那就没必要搞复杂的中间件,我直接用「双写 + 存量同步 + 灰度切换」,步骤简单直接:

  1. 分表规则:我们的数据表基于设备id划分,所以分表是采用业务id的方式,之前有了解过也可以按照日期规则来分表,具体可看业务需求选择合适场景
  2. 先上双写:core 业务包先升级,写入老库的同时,双写到新库的分表(新库只写不读,不影响业务)
  3. 存量同步 :写个定时任务,我们的id是自增 的,所以我采用了 ID 分页+创建时间过滤的方式同步历史数据。用 Redis 存同步断点 ID,支持断点续跑
  4. 灰度切换:存量同步完成后,先切测试账户查新库,验证数据一致;没问题再全量切换,最后删掉老库写入逻辑,完事
  5. 预建分表 + INSERT IGNORE 兜底 :同步前先统计老库的设备类型和 ID,提前建好新库的分表;批量插入用INSERT IGNORE,就算偶尔有重复数据也能自动忽略,不怕同步重试翻车。

这套方案的核心就是 「用时间戳来分别处理存量和增量数据」 ------ 双写启动时间点之前的走存量同步,之后的走业务双写,两者完全不重叠,理论上不会丢数据。

二、 踩坑:SUM (TABLE_ROWS) 真是个「坑货」

同步任务跑完,我信心满满去核对数据量,结果傻眼了:新库分表总和比老库筛选后的数据少了 6.5 万条

第一反应是:完了,同步漏数据了?赶紧去查代码日志,没报错啊,断点续跑也正常。折腾了半天,才发现是统计方式的锅!

我一开始统计新库数据量用的是这句 SQL:

sql

sql 复制代码
SELECT SUM(TABLE_ROWS) FROM INFORMATION_SCHEMA.TABLES  
WHERE TABLE_SCHEMA = 'gps_data' AND TABLE_NAME LIKE 'gps_data_%';

后来才想起来,INFORMATION_SCHEMA.TABLES 里的 TABLE_ROWSMySQL 的估算值,不是精准数!尤其是分表多、批量插入频繁的场景,误差能到 10%~30%,6.5 万的差距就是这么来的。

最终解决:UNION ALL 才是王道

想要精准统计分表总数,别偷懒,要么写个存储过程遍历所有分表 COUNT(*),要么直接用 UNION ALL 手动统计:

sql

sql 复制代码
SELECT COUNT(*) FROM (
    SELECT id FROM gps_data_1_1001 UNION ALL
    SELECT id FROM gps_data_2_1002 UNION ALL
    -- 把所有分表列出来
) AS temp;

这么一查,新库和老库的数据量就对上了。

三、 其他思考:如果有删改,又该如何解决?

这个场景虽然不算特别有深度,但是也比纯业务场景有其他值得思考的点。

更加复杂的业务场景靠我这个方案肯定是行不通的,于是去研究了下大厂的主流分表方案,发现核心都是 「存量同步 + Binlog 实时同步 + 业务双写兜底」

小场景 vs 大厂场景:核心差异对比

对比维度 我的纯新增小场景 大厂有删改复杂场景
核心难点 无删改,只需保证新增不丢 删改频繁,要保证数据实时一致
同步核心 业务双写 + 存量 ID 分页同步 Binlog 实时同步 + 存量同步 + 双写兜底
关键技术 Redis 断点、INSERT IGNORE 去重 Canal/Maxwell 解析 Binlog、最终一致性校验
数据一致性 绝对一致(纯新增无冲突) 实时一致(毫秒级延迟)
改造成本 低,复用现有代码 中,需要引入中间件

大厂方案的核心逻辑:Binlog 才是灵魂

大厂玩分表,很少只靠业务双写,核心是抓数据库的 Binlog 日志 ------ 这玩意儿相当于数据库的「操作流水账」,所有增删改操作都记在上面。

用 Canal 这类中间件伪装成 MySQL 从库,实时读取 Binlog,解析出操作内容,再同步到新库的对应分表。这种方式 零业务侵入,不用改一行业务代码,还能捕获所有数据变更,包括 DBA 手动改的数据。

当然,大厂也会保留业务双写作为兜底,万一 Binlog 同步出问题,双写能保证数据不丢,最后再用补偿任务做一致性校验,完美闭环。

五、 感受

  1. 分表/数据迁移是重中之重,测试用例,各种情况一定要考虑周全
  2. 提供灰度方案,在出问题时无缝回退,最大程度减少切换时对用户的影响
  3. 分析复杂问题,拆分简化,一步一步执行
相关推荐
凌览2 小时前
别再死磕 Nginx!http-proxy-middleware 低配置起飞
前端·后端
CryptoRzz2 小时前
印度尼西亚(IDX)股票数据对接开发
java·后端·websocket·web3·区块链
咕白m6253 小时前
通过 C# 快速生成二维码 (QR code)
后端·.net
踏浪无痕3 小时前
架构师如何学习 AI:三个月掌握核心能力的务实路径
人工智能·后端·程序员
小毅&Nora3 小时前
【后端】【SpringBoot】① 源码解析:从启动到优雅关闭
spring boot·后端·优雅关闭
嘻哈baby3 小时前
从TIME_WAIT爆炸到端口耗尽:Linux短连接服务排查与优化
后端
开心就好20254 小时前
iOS应用性能监控全面解析:CPU、内存、FPS、卡顿与内存泄漏检测
后端
问今域中4 小时前
Spring Boot 请求参数绑定注解
java·spring boot·后端
计算机程序设计小李同学5 小时前
婚纱摄影集成管理系统小程序
java·vue.js·spring boot·后端·微信小程序·小程序