本文转载自:华为云社区

86万张表迁移的优化历程问题背景:2019年12月份的时候DRS项目组接到了一个线上问题:XX客户将mysql数据库从友商迁移至华为云的时候性能很慢,而且出现报错。运维同学定位发现用户的某几个实例存在大约2000个库,86万张表,而出错的原因是查询源库数据库超时。和开发同学联系后得到了第一个解决方案:增大和源库的socketTimeout值,保证查询不超时。然而,运维同学在后续保障的过程中发现……

01

86万张表迁移的优化历程

  • 问题背景

2019年12月份的时候DRS项目组接到了一个线上问题:XX客户将mysql数据库从友商迁移至华为云的时候性能很慢,而且出现报错。运维同学定位发现用户的某几个实例存在大约2000个库,86万张表,而出错的原因是查询源库数据库超时。和开发同学联系后得到了第一个解决方案:增大和源库的socketTimeout值,保证查询不超时。然而,运维同学在后续保障的过程中发现超时问题得以解决但是性能无法保证,而且容易出现OOM问题。客户要求在一天内要完成割接,然而我们目前的迁移时间远超24个小时,由于项目的进度问题,留给DRS的时间只剩一个周末。

02

问题定位过程

  • 问题定位

饭要一口口吃,问题也得一个个定位,回到最初的超时问题,我们首先找到了出现超时的sql语句:

SELECT TRIGGER_NAME FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA = '****';

这个sql用于查询每个库下面的所有触发器(其他对象的查询sql也有这个问题),我们发现这个sql执行了超过5分钟,这个结果令我们很意外。因为理论上而言只查询一个库下面的所有触发器,怎么会这么慢呢?explain这个sql我们发现:

Extra中表示Scanned all databases!!!这意味着虽然我们只是在查询一个库下面的触发器,但是其实它会扫描所有库对应的frm文件。DEBUG了一下mysql的源码,我们发现虽然只是查询了一个库下面的trigger,但是由于information_schema.triggers表里面并不是一张物理表,导致每次查询都会去打开所有的frm文件,我们知道frm文件是用来存放mysql元数据信息的物理文件,对于用户这个表数量,可想而知这个会对用户的源库IO造成多大的影响,即使有buffer pool也扛不住这么多表的缓存。更关键的是,用户有2000个库,也就是说单就查询trigger这一个对象,我们就需要耗费2000*5=10000分钟的时间,迁移性能可想而知。

  • 优化思路

有了上面的结果,其实采取的优化方式很简单了。首先,我们根据对象的类型来区分查询所有对象的方式,对于表,我们可以使用逐库查询,因为查询表的操作不会Scanned all databases;对于其他对象,我们使用只查询一次的sql:

SELECT TRIGGER_SCHEMA, TRIGGER_NAME FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA NOT in('mysql','information_schema','sys', 'performance_schema');

这样我们的查询时间大大缩短!

然而,现实是残酷的,虽然我们缩短了从源库查询对象列表的时间,但是导出对象到回放对象的性能还是不够出色,不能满足用户的12小时时间限制,此外偶发的OOM问题也随之没有解决。

03

OOM问题

  • 问题定位

用MAT分析了heap堆存储后发现,heap里面存在大量的DbSqlData类的对象,正是大量的这种对象导致堆内存溢出。结合我们的架构可以发现,我们在导出表结构的时候会先把所有对象结构分类型存储在ehcache中,然后在读取的时候又会把数据按类型导出到内存中。针对用户的场景,我们可以计算出(用户的表结构平均占用堆内存4000Byte)86万张表总共需要3.44G,而我们的永久代内存只配置了2G,OOM问题可想而知。

if [ -z "$REPLICATOR_HEAP_SIZE" ]; then
  REPLICATOR_HEAP_SIZE="-Xms3072m -Xmx3072m -XX:NewRatio=3 -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m"
fi

  • 优化思路

其实这一切的问题来源都是因为我们按对象类型对ehcache进行存取,这种方式不是流式进行的,很有可能发生OOM问题。因此,解决的思路就是我们按照单个对象的粒度进行存取,并且使用内存控制的方式控制读到堆内的对象数目,保证流式结构的回放,如何进行流式结构的回放将会在下面介绍。

04

性能问题

  • 问题定位

为了满足客户的迁移时间需求,我们统计了各个阶段DRS内核的工作时间,大致分为下面几个阶段:

这三个阶段的执行顺序是串行执行的,其中查询对象列表花了共计1个小时,导出对象结构共计10个小时,回放共计8个小时,总计19个小时。这个结果远远超出了客户的预期,为了解决这个问题,我们对整个迁移流程进行了重新梳理,发现有以下2个改进点:

1.查询对象列表的同时可以将已查询对象列表的结构导出2.导出对象结构可以由单线程导出演进为多线程并发导出

按照上述优化流程,假定查询对象列表时间为A,单线程导出结构所需时间为B,根据CPU核数/IO线程比我们设定导出结构的线程数为8,在源库性能足够的情形下,查询对象列表+导出对象结构的时间应该等于

CostTime(hour)=max(A, B/8) —— 约等于2

这样我们的总时间为2 + 8 = 10小时,满足客户的需求!

  • 优化思路

有了上面的分析,结合OOM问题和查询时间优化的思路,我们有了以下的设计:

上面图略去了数据的回放模型,主要突出了结构的回放,同时在两个store中加入了内存控制,防止出现OOM问题。

05

优化结果

在通宵达旦的开发和验证后,我们终于构建了以上的框架,并且成功将86万张表的总时长优化到了10小时以内,更为可喜的是整个流程中的full gc次数为0,最终客户的需求得以实现,技术人员也从中学习到了新的知识。

  • 思考

优化是无止境的,其实上述的架构还存在优化空间,比如以下的两点:

1.结构的导入和数据的回放可以并行执行,针对用户表多数据少的场景,统计发现表结构的导入花了4个小时而数据的导入也只花了4个小时,这一个阶段可以优化(DRS已经做了这个优化,会在后续的博客中给大家科普实现方式)2.结构的导出和结构回放是否可以并行执行,他们之间的限制关系是什么?

如果有小伙伴对我们的架构有看法也可以积极留言,我们会去认真观摩!

↓点击

expdp导出表结构_超强技术案例!86万张表迁移的优化历程相关推荐

  1. expdp导出表结构_(转)oracle使用expdp、impdp和exp、imp导入导出表及表结构

    使用expdp.impdp和exp.imp时应该注重的事项: 1.exp和imp是客户端工具程序,它们既可以在客户端使用,也可以在服务端使用. 2.expdp和impdp是服务端的工具程序,他们只能在 ...

  2. 【impdp】IMPDP中的TRANSFORM参数--【数据泵】EXPDP导出表结构(真实案例)后传

    在上一篇文章[数据泵]EXPDP导出表结构(真实案例) 中:http://blog.itpub.net/26736162/viewspace-1657828/  ,由于表的storage参数存储很大, ...

  3. 【数据泵】EXPDP导出表结构

    [数据泵]EXPDP导出表结构(真实案例) BLOG文档结构图 因工作需要现需要把一个生产库下的元数据(表定义,索引定义,函数定义,包定义,存储过程)导出到测试库上,本来以为很简单的,可是做的过程发现 ...

  4. 导出表结构_十分钟教你轻松掌握移动PE导出表,快来学习!

    今天的文章分享是 i 春秋论坛作者flag0原创的文章,浅析移动PE导出表的相关内容,文章未经许可禁止转载! 注:i 春秋公众号旨在为大家提供更多的学习方法与技能技巧,文章仅供学习参考. 导出表概述 ...

  5. 【沉淀】一张表的设计优化节省了两百万_客户不断盛誉……_这背后他究竟做对了什么?——记访谈汪建明

    原文地址 "客户第一"是阿里巴巴"六脉神剑"中排名第一的价值观,它除了要求阿里人服务好客户之外,也要求阿里的同学时时刻刻去了解客户的所思所想,不断地挑战自己,用 ...

  6. mysql比对表中数据是否相同_如何用sql比较两张表数据是否一致?

    在批量程序的测试中,经常会涉及到对数据库表的测试,今天我们来介绍一下用sql比较两张表结构相同的表数据是否完全一致的方法. 1.inner join 浅尝 提到比对两张表的数据是否完全相同,很容易想到 ...

  7. front mysql 导出表结构_肿么将mysql的表结构导出到sqlserver中

    在命令行下mysql的数据导出有个很好用命令mysqldump,它的参数有一大把,可以这样查看: mysqldump 最常用的: mysqldump -uroot -pmysql databasefo ...

  8. mapgis中6.7属性结构_【技术】这世界的完美,原本一直在我们眼前 ——MapGIS打造全空间GIS平台...

    所谓"世界",世为"时间",界为"空间".无垠大地.浩瀚苍穹,世界上的任何事物都被牢牢打上了时空的烙印.GIS作为获取.存储.分析和管理时空 ...

  9. mysql命令导出表结构和数据_mysql-用命令导出、导入表结构或数据

    1. 导出整个数据库(表结构和数据) mysqldump -u用户名 -p  数据库名 > 导出的文件名 [root@localhost work]# mysqldump -uroot -p m ...

最新文章

  1. 动态规划DP----背包问题总结
  2. 1.8 分割字符串(spilt())
  3. 拥抱敏捷的用例分析方法
  4. 已解决 selenium.common.exceptions.NoSuchElementException: Message: Unable to locate element 找不到元素的问题
  5. 【转载】Gradle命令行黑魔法
  6. 分类计数原理与分步计数原理_两种基础的计数原理
  7. C# Combobox清空值
  8. matlab如何批量去背景,ImageJ怎么消除背景 批量去背景教程
  9. 离散域下的泊松方程求解(python实现)
  10. EXCEL数组公式(3)---数组公式的基础应用,理解数组公式
  11. vim配置——C/C++代码自动补全
  12. 关于Python常用的办公自动化技巧
  13. 用计算机画漫画很难吗,怎么在电脑上画漫画,难不难
  14. 易语言 php post,易语言POST发送邮件
  15. 稀疏数组真心话大冒险
  16. EDA学习环境的搭建
  17. 5G融合行业专网解决方案分析与研究
  18. LaTeX中一些常用符号及编写技巧
  19. R语言入门——批量读取文件
  20. springMVC+jcrop实现头像上传截图功能

热门文章

  1. 如何用Jmeter做压力测试
  2. 网络虚拟化是否需要额外的网络架构?
  3. ResourceLoader
  4. 装机必备工具(普通家庭版)
  5. 技术社区,你真的会混吗?
  6. 利用ViewPager+Fragment+actionbar实现可左右滑动的Action Tab
  7. 《Java编程思想》学习笔记9——集合容器高级
  8. 后台开发经典书籍--构建高性能WEB站点
  9. 汇编语言--CPU对外设的控制
  10. stm32f10x_it.c 定义的程序列表模板(stm32f103x_it.c中放的是中断的空函数)