文章来源:https://c1n.cn/dPgm1

前言

笔者是在两年前接手公司的财务系统的开发和维护工作。在系统移交的初期,笔者和团队就发现,系统内有一张 5000W+ 的大表。

跟踪代码发现,该表是用于存储资金流水的表格,关联着众多功能点,同时也有众多的下游系统在使用这张表的数据。

进一步的观察发现,这张表还在以每月 600W+ 的数据持续增长,也就是说,不超过半年,这张表会增长到 1 个亿!

笔者内心(麻了)

这个数据量,对于 MySQL 数据库来说是绝对无法继续维护的了,因此在接手系统两个月后,我们便开起了大表拆分的专项工作。(两个月时间实际上主要用来熟悉系统、消化堆积需求了)

拆表前系统状态

拆表前系统状态如下:

  • 涉及到流水表流水的接口超时频发,部分接口基本不可用

  • 每日新增流水缓慢,主要是插入数据库的时候非常慢

  • 单表占用空间过大,DBA 的数据库监控经常报警

  • 无法对表进行变更,任何 alter 操作都会引起主从的高延迟和长时间锁表

拆表的目标

拆表的目标如下:

  • 将流水大表数据拆分至各个分表,保证每张分表数据在 1000W 左右(经验上看单表 1000W 的量对 MySQL 来说没啥压力)。

  • 在拆表的前提下,针对不同接口的查询条件进行优化,保证各个对外、对内接口的可用性。彻底杀死 MySQL 慢查询。

难点分析

难点如下:

  • 该表的数据可以说是整个财务系统最基础的数据,相关功能和下游系统非常多。这要求开发、测试和上线流程必须极其严密,任何小失误都会引起大问题。

  • 涉及的场景非常多。统计下来,一共有 26 个场景,需要改造 32 个 mapper 方法,具体需要改造的方法就更加无计其数了。

  • 数据量非常大,迁移数据的过程必须保证系统稳定。

  • 用户较多且功能重要。分表功能上线时,必须尽量压缩系统无法使用时长,同时需要保证系统可用性。这要求团队必须设计完整可靠的上线流程、数据迁移方案、回滚方案、降级策略。

  • 上文提到,表的拆分势必带来部分接口的变化,接口的变化又会带来其他系统的改造。如何推动其他系统进行改造,如何协调多方合作的开发、测试和上线是另一个难点。

整体过程

整体过程如下图:

具体细节

| 分表中间件调研

分表插件:采用 sharding-jdbc 作为分表插件。

其优势如下:

  • 支持多种分片策略,自动识别 = 或 in 判断具体在哪张分表里。

  • 轻量级,作为 maven 依赖引入即可,对业务的侵入性极低。

为提升查询速度,在整个项目的初期,团队成员考虑引入 ES 存储流水以提升查询速度。

经过与 ES 维护团队的两轮讨论,发现公司提供的 ES 服务对于我们的业务场景并不匹配,见下表:

经过反复考量,最终我们放弃了引入 ES 的计划,直接从数据库查询数据,采用每张表设置一个查询线程的方式提升查询效率。

| 分表依据的选择

分表的方式有很多种,有纵向分表,有横向分表,有分为固定的几个表存储然后取模进行表拆分等等。总的来说,适合我们具体业务的分表方式只有横向分表。

因为对于资金流水这种特殊数据来说,是不能清理数据的,那么纵向分表和拆成固定的几个表都不能解决单表数据无限膨胀的问题。而横向分表,可以把每张表的数据量恒定,到一定时间后可以进行财务数据归档。

分表的依据一般都是根据表的某个或者某几个字段进行拆分,最终其实是对数据和业务分析综合出来的结果。

总的来说,原则有这几个:

  • 尽可能选择查询条件里最常出现的字段,这样能够减少方法改造的工程。

  • 需要考虑根据某个字段拆分数据是否能够均匀分布,是否能够满足单表 1000W 左右的要求。

  • 该字段必须是必现字段,不允许出现空值。

综合分析我们的数据以及业务需要,“交易时间”这个分表依据就呼之欲出了。

首先,这个字段作为流水最重要的字段之一一定会出现;第二,如果按照交易月份进行拆表,每张表大概也就是 600W-700W 的数据;最后,有 70% 的查询都附带“交易时间”作为查询条件。

| 技术难点

①多数据源事务问题

sharding-jdbc 在使用的时候是需要用自己的独立数据源的,那么就难免出现多数据源事务问题。

这个我们通过自定义注解,自定义切面开启事务,通过方法栈逐层回滚 or 提交的方式解决的。出于保密原则,具体代码细节不再展开。

②多表的分页问题

拆表一定会引起分页查询的难度增加。由于各个表查出来的数据量不等,原始的 sql 语句 limit 不再适用,需要设计一个新方法便捷的获取分页信息。

在此介绍一个分页的思路供大家参考(团队共同的成果,笔者不敢私自占有):综合考虑业务实际与开发的复杂程度,项目团队决定在出现跨表查询的情况下,每一张表采用一个线程进行查询,以提高查询效率。

这个方案的难点在于分页规则的转换。例如,页面传入的 offset 和 pageSize 分别为 8 和 20。各分表中符合条件的数量分别为 10,10,50。

那么我们需要将总的分页条件转化为三个分表各自的分页条件,如下图:

通过上图可以看到,大分页条件(offset=8,pageSize=20),转换为(offset=8,pageSize=2),(offset=0.pageSize=10),(offset=0,pageSize=8)三个条件。

整个计算过程如下:

  • 多线程查询各个分表中满足条件的数据数量

  • 将各个表数量按照分表的先后顺序累加,形成图 8 的数轴

  • 判断第一条数据和最后一条数据所在的表

  • 除第一条和最后一条数据所在表外,其他表 offset=0,pageSize=总数量

  • 计算第一条数据的 offset,pageSize

计算最后一条数据的 pageSize,同时将该表查询条件的 offset 设置为 0。

| 数据迁移方案

在数据迁移前,团队讨论过两套迁移方案:

  • 请 DBA 迁移数据

  • 手写代码迁移数据

他们各有自己的优缺点,如下图:

综合考虑时间成本和对线上数据库的影响,团队决定采用两种方案结合的方式:

  • 交易时间为三个月前的冷数据,由于更新几率不大,采用代码的方式迁移,人为控制每次迁移数量,少量多次,蚂蚁搬家。

  • 交易时间为三个月内的热数据,由于会在上线前频繁出现更新操作,则在上线前停止写操作,而后由 DBA 整体迁移。这样将时间成本平摊到平时,上线前只有约2个小时左右迁移数据时系统无法使用。

  • 同时,除了最后一次 DBA 迁移数据外,能够人为控制每次迁移的数据量,整体避免数据库实例级别的高延迟。

| 整体上线流程

为保证新表拆分功能的稳定性和大表下线的稳定,团队将整个项目分为三个阶段:

  • 第一阶段:建立分表,大表数据迁移分表,线上数据新表老表双写,所有查询走分表(验证观察)

  • 第二阶段:停止写老数据表,其他业务直连数据库改为资金提供对外接口(验证观察)

  • 第三阶段:大表下线

总结

总结如下:

  • 应再进一步调研分表相关中间件。由于项目分表依据的特殊性,导致 sharding-jdbc 的很多功能无法利用,其对于简化查询逻辑的帮助低于预期。并且 sharding-jdbc 独立数据源的特性,引发了多数据源事务问题,反而增加了开发的工作量。

  • 多线程需要仔细分析线程池核心线程的大小,同时分析多线程池同时存在的时候是否会引起核心线程数过多,避免机器线程打满。

  • 如果是一个已有的项目,在进行分表改造时,一定要将各种场景都罗列清楚,将各个场景细化到程序中的每个类、每个方法中,将所有业务场景都覆盖到。

  • 在迁移历史数据时,一定要做好迁移数据方案,以及应对出现数据不一致时的处理方案。要综合考虑时间成本、数据准确性、对线上功能的影响等诸多因素。

  • 在上线一个比较复杂的方案时,一定要提前设计好回滚方案和降级措施,能够极大保证稳定性。

说点题外话

为啥说想说点儿题外话呢,主要是对这次延续了 5 个多月的项目有感而发。项目进行过程中,难免会与其他系统的维护团队有工作上的交集,有需要其他团队配合的地方。

这个时候非常考验程序员的沟通能力,最优秀的程序员能够通过话术把对方拉到自己的阵线当中,让对方感到这项工作对自己也是有好处的。这样能够让对方心甘情愿的配合你的工作,达到双赢的目的。

如果程序设计和学习能力是程序员的硬实力,那沟通技巧就是程序员的软实力,硬实力能够保障你的下线,而决定上线的恰恰是软实力。

因此很多程序员不注重沟通技巧的培养,其实是相当于瘸腿的,毕竟现在凭单打独斗是不大可能做出事情的。

另外,至少对于我们单位来说,对后端程序员的综合素质其实要求最高。后端程序员集业务、技术于一身。需要有比较强的业务把控能力,还要有过硬的技术素质。

同时,大多数工作的主 owner 是后端,一般都是后端程序员把控前端、后端、QA 的开发节奏,协调好各个时间点,做好风险反馈。

这就要求后端程序员既要懂业务,还要懂技术,还需要有一定的管理能力。这其实对人的锻炼还是很可观的。

强势开源一款小程序!
2021-11-07
强力推荐一个完善的物流(WMS)管理项目(附代码)
2021-10-23
推荐一个 Spring Boot + MyBatis + Vue 音乐网站
2021-10-19
分享一套家庭理财系统(附源码)
2021-09-20
推荐一个互联网企业级别的开源支付系统
2021-09-04
推荐一套开源通用后台管理系统(附源码)
2021-08-21
一款神仙接私活儿软件,吊到不行!
2021-07-31
基于 SpringBoot 的仿豆瓣平台【源码分享】
2021-07-18
干掉 Wordpress!这个开源建站神器有点吊!
2021-06-18
从朋友那里搞了 20 个实战项目,速领!
2021-06-12

如有收获,点个在看,诚挚感谢

这下真麻了!亿级别大表拆分心路历程!相关推荐

  1. 亿级大表分库分表实战总结(万字干货,实战复盘)

    亿级大表分库分表实战总结(万字干货,实战复盘) 以下文章来源于阿丸笔记 ,作者阿丸笔记 阿丸笔记 分库分表的文章网上非常多,但是大多内容比较零散,以讲解知识点为主,没有完整地说明一个大表的切分.新架构 ...

  2. 亿级大表在线不锁表变更字段与索引

    摘要:在业界中有一个比较成熟的工具,针对大表的场景,可以在线进行Alter变更,且不会出现锁表的风险.除此之外,它还有其他的一些优点,让我们开始探索吧. 背景 大家在日常工作中,往往需要对数据库的表结 ...

  3. 一入职!就遇到MySQL亿级大表优化....

    作者丨jia-xin 出处: https://www.cnblogs.com/YangJiaXin/p/10828244.html "前段时间刚入职一家公司,就遇到了 MySQL 亿级大表优 ...

  4. MariaDB 10的复制 集群 高可用搭建 大表拆分【持续更新中】

    视频地址 http://edu.51cto.com/course/course_id-1691.html MariaDB 10培训课程 第一部分 复制 1.基于GTID方式复制配置及注意事项 2.基于 ...

  5. MySQL把一个大表拆分多个表后,如何解决跨表查询效率问题

    MySQL把一个大表拆分多个表后,如何解决跨表查询效率问题 参考文章: (1)MySQL把一个大表拆分多个表后,如何解决跨表查询效率问题 (2)https://www.cnblogs.com/lili ...

  6. MariaDB 10.3 instant ADD COLUMN亿级大表毫秒级加字段

    加字段是痛苦的,需要对表进行重建,尤其是对亿级别的大表,虽然Online DDL可以避免锁表,但如果在主库上执行耗时30分钟,那么再复制到从库上执行,主从复制就出现延迟.使用instant ADD C ...

  7. 100G内存下,MySQL查询200G大表会OOM么?

    文章来源:https://sourl.cn/vwDNzn 我的主机内存只有100G,现在要全表扫描一个200G大表,会不会把DB主机的内存用光? 逻辑备份时,可不就是做整库扫描吗?若这样就会把内存吃光 ...

  8. MySQL千万级别大表如何优化?

    当MySQL单表记录数过大时,增删改查性能都会急剧下降,可以参考以下步骤来优化: 单表优化 除非单表数据未来会一直不断上涨,否则不要一开始就考虑拆分,拆分会带来逻辑.部署.运维的各种复杂度,一般以整型 ...

  9. 面试官邪魅一笑:MySQL千万级别大表,你要如何优化?

    作者:码农 原文链接:https://segmentfault.com/a/1190000006158186#comment-area 当MySQL单表记录数过大时,增删改查性能都会急剧下降,可以参考 ...

最新文章

  1. # 从零開始搭建Hadoop2.7.1的分布式集群
  2. zabbix数据库表结构简单解析
  3. Windows 10 powershell 中文乱码解决方案
  4. 基于HTML5的WebGL结合Box2DJS物理引擎应用
  5. 移动开发:android , IOS html5
  6. 《白鹿原》金句摘抄(七)
  7. mockito java_Java:使用Mockito模拟ResultSet
  8. 分布式应用中的一致性协议
  9. vs2005配置c语言连接mysql
  10. 那些实用的Nginx规则
  11. c语言写一元一次函数图像,一元一次函数练习题带答案.doc
  12. SOA webservice
  13. Nutch开发(一)
  14. python直方图解释_python直方图1 lin
  15. 有人在开课吧学习过吗?值得信任吗?教学质量如何?
  16. 华为手机获取root权限
  17. 【OPENCV】运行opencv时找不到Qt库
  18. 对抗网络之PG-GAN,无条件下生成更真实的人脸图像
  19. 通过labview vision视觉模块写的带学习功能的OCR字符识别程序
  20. 使用CRF++实现命名实体识别

热门文章

  1. sock5系列之模拟tcp请求sock5服务器!(三)
  2. SVN红色感叹号不在外层显示,红色感叹号优先级不如绿色
  3. 优恩-电源端口静电放电及雷击浪涌|兼容冗馀ESD防护设计方案
  4. 摄像头接口介绍及工作原理
  5. 网站服务器无法启动w3cvc,w3c标准网站
  6. 精美苹果cms影视双端同步APIcloud混合原生APP源码
  7. 两台虚拟服务器如何串联,两台tp-link路由器串联设置教程
  8. 洛阳亲友如相问,就说我在敲代码。
  9. 38 | 何时使用除了Innodb以外的Memory引擎
  10. win10系统盘多大合适_重装系统Win10