热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

本文转载自:华为云社区86万张表迁移的优化历程问题背景:2019年12月份的时候DRS项目组接到了一个线上问题:XX客户将mysql数据库

c13d9e18d3dfa3b9923ce7a46b3ac11a.png

本文转载自:华为云社区

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我们发现:

aced798bdcff240f9c1f84cbd58a0102.png

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内核的工作时间,大致分为下面几个阶段:

bcce95c785b9f5bb55039f545275fbf4.png

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

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

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

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

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

  • 优化思路

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

690c6de7aa27ee12058203d601b1d36d.png

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

05

优化结果

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

  • 思考

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

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

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

1a83cc049081235ce6290138d5557815.png

↓点击



推荐阅读
  • 在运行于MS SQL Server 2005的.NET 2.0 Web应用中,我偶尔会遇到令人头疼的SQL死锁问题。过去,我们主要通过调整查询来解决这些问题,但这既耗时又不可靠。我希望能找到一种确定性的查询模式,确保从设计上彻底避免SQL死锁。 ... [详细]
  • 本文详细探讨了在Web开发中常见的UTF-8编码问题及其解决方案,包括HTML页面、PHP脚本、MySQL数据库以及JavaScript和Flash应用中的乱码问题。 ... [详细]
  • 本文介绍了SIP(Session Initiation Protocol,会话发起协议)的基本概念、功能、消息格式及其实现机制。SIP是一种在IP网络上用于建立、管理和终止多媒体通信会话的应用层协议。 ... [详细]
  • 二维码的实现与应用
    本文介绍了二维码的基本概念、分类及其优缺点,并详细描述了如何使用Java编程语言结合第三方库(如ZXing和qrcode.jar)来实现二维码的生成与解析。 ... [详细]
  • 如何将955万数据表的17秒SQL查询优化至300毫秒
    本文详细介绍了通过优化SQL查询策略,成功将一张包含955万条记录的财务流水表的查询时间从17秒缩短至300毫秒的方法。文章不仅提供了具体的SQL优化技巧,还深入探讨了背后的数据库原理。 ... [详细]
  • 解决JavaScript中法语字符排序问题
    在开发一个使用JavaScript、HTML和CSS的Web应用时,遇到从SQLite数据库中提取的法语词汇排序不正确的问题,特别是带重音符号的字母未按预期排序。 ... [详细]
  • 本文作为《WM平台上使用Sybase Anywhere 11》系列的第二篇,将继续探讨在Windows Mobile (WM) 系统中如何高效地操作Sybase Anywhere 11数据库。继上一篇关于安装与基本测试的文章之后,本篇将深入讲解数据库的具体操作方法。 ... [详细]
  • 本文探讨了如何通过Service Locator模式来简化和优化在B/S架构中的服务命名访问,特别是对于需要频繁访问的服务,如JNDI和XMLNS。该模式通过缓存机制减少了重复查找的成本,并提供了对多种服务的统一访问接口。 ... [详细]
  • 流处理中的计数挑战与解决方案
    本文探讨了在流处理中进行计数的各种技术和挑战,并基于作者在2016年圣何塞举行的Hadoop World大会上的演讲进行了深入分析。文章不仅介绍了传统批处理和Lambda架构的局限性,还详细探讨了流处理架构的优势及其在现代大数据应用中的重要作用。 ... [详细]
  • 本文介绍了如何在两个Oracle数据库(假设为数据库A和数据库B)之间设置DBLink,以便能够从数据库A中直接访问和操作数据库B中的数据。文章详细描述了创建DBLink前的必要准备步骤以及具体的创建方法。 ... [详细]
  • 本文详细介绍了Oracle 11g中的创建表空间的方法,以及如何设置客户端和服务端的基本配置,包括用户管理、环境变量配置等。 ... [详细]
  • 本文详细介绍了在 Ubuntu 16.04 系统上安装和配置 PostgreSQL 数据库的方法,包括如何设置监听地址、启用密码加密、更改默认用户密码以及调整客户端访问控制。 ... [详细]
  • 在处理大量联系人数据的批量插入操作时,发现现有方法的执行效率低下,尤其是在处理数十条记录以上时,与导出操作的速度形成鲜明对比。本文将探讨如何通过代码优化来提升批量插入联系人的效率。 ... [详细]
  • 电商高并发解决方案详解
    本文以京东为例,详细探讨了电商中常见的高并发解决方案,包括多级缓存和Nginx限流技术,旨在帮助读者更好地理解和应用这些技术。 ... [详细]
  • RTThread线程间通信
    线程中通信在裸机编程中,经常会使用全局变量进行功能间的通信,如某些功能可能由于一些操作而改变全局变量的值,另一个功能对此全局变量进行读取& ... [详细]
author-avatar
福田商务汽车--南宁鑫来
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有