从云数据迁移服务看MySQL大表抽取模式的原理解析

摘要:MySQL JDBC抽取到底应该采用什么样的方式,且听小编给你娓娓道来。

小编最近在云上的一个迁移项目中被MySQL抽取模式折磨的很惨。一开始爆内存被客户怼,再后来迁移效率低下再被怼。MySQL JDBC抽取到底应该采用什么样的方式,且听小编给你娓娓道来。

1.1 Java-JDBC通信原理

JDBC与数据库之间的通信是通过socket完,大致流程如下图所示。Mysql Server ->内核Socket Buffer -> 客户端Socket Buffer ->JDBC所在的JVM

1.2 JDBC读取数据的三种模式

1.2.1 方式1:使用JDBC默认参数读取数据

主要分为以下几步:

1)Mysql Server通过OuputStream 向 Socket Server 本地Kennel Buffer 写入数据,这里是一次内存拷贝。

2)当Socket Server 本地Kennel Buffer 有数据,就会通过TCP链路把数据传输到Socket Client 所在机器的Kennel Buffer。

3)JDBC 所在JVM利用InputSream读取本地Kennel Buffer 数据到JVM内存,没有数据时,则读取被阻塞。

接下来就是不断重复1,2,3的过程。 问题 是,Socket Client 端的JVM在默认模式下读取Kennel Buffer是没有考虑本机内存大小的,有多少读多少。如果数据太大,就会造成FULL GC,紧接着内存溢出。

参考 JDBC API docs,默认模式 Java demo 代码如下

1.2.2 方式2:游标查询

为了解决方式1爆内存的问题,JDBC提供了一个游标参数,在建立jdbc连接时加上useCursorFetch=true。设置游标后,JDBC 每次会告诉Server端每次抽取的数据量,避免爆内存。通信过程如下图所示。

​ 方式2游标查询虽然解决了内存溢出的问题,方式2极大的依赖网络质量。当网络时延增大,假设每次通信增加10ms,10万次通信就会多出1000s。这里仅仅是每次发请求的RT,TCP每次发送报文,都要求反馈ACK保证数据可靠性。client每取100行(请求行数可配置),就会有多次通信,进一步放大时延增加导致的效率问题。此外,游标查询下,Mysql无法预知查询的结束时延,为了应对自身的DML操作会在本地建立一个临时空间存放要抽取的数据。因此,游标查询时会有以下几个现象发生

a. IOPS飙升,Mysql将数据写入到临时空间,数据传输时从临时空间读取数据,这都会引发大量IO操作。

b. 磁盘空间飙升,临时空间生命周期存在于整个JDBC读取阶段,直到客户端发起Result.close()时才会被Mysql回收。

c. CPU和内存有一定比例上升。

有关游标查询的原理可参考博客MySQL JDBC StreamResult通信原理浅析以及JDBC源码,本文不在赘述。

参考 JDBC API docs,游标模式 Java demo 代码如下

1.2.3 方式3: Stream读取数据

方式1会导致JVM内存溢出,方式2虽然不会FULL GC但是通信效率较低,而且也会导致Mysql服务端IOPS飙升,消耗磁盘空间等问题。因此,我们介绍Stream读取数据 ,流式需要在读取Result前设置

方式3在通信前不会做任何Server-Cient的交互操作,避免通信效率低下。服务端准备好数据写入Server的Kennel Buffer中,这些数据通过TCP链路传输到Client的Kennel Buffer中,紧接着client端inputStream.read()方法被唤醒去读取数据,与方式1不同,client每次只会读取一个package大小的数据,如果一个package不满一行则会再读取一个package。当client消费数据的速度不及数据传输速率时,client端kennel区的数据就会被堆满,紧接着Server端的kennel数据也会堆满进而阻塞了OuputStream。这样,JDBC在Stream模式下就像一个水管连接两个蓄水池,Client和Server达到一个平衡。

​对于JDBC客户端,由于每次都是从kennel读取数据,效率会比方式2高很多,每次读取一小部分数据也不会导致JVM内存溢出。对于服务端,Mysql每次都是往kennel写数据,无需建立临时空间,不涉及IO读取,服务端压力也变小了。当然,方式3也有自己的问题,例如Stream流式时无法cancel,cancel不阻塞等等。

参考 JDBC API docs,网上很多教程需要设置useCursorFetch=trueResultSet.FETCH_REVERSE等,其实小编研究完JDBC驱动源码后发现,只需要设fetchSize=Integer. MIN_VALUE,其他配置均和默认配置保持一致即可。游标模式 Java demo 代码如下

1.3 云数据迁移服务在三种模式下的调优

云数据迁移服务(Cloud Data Migration, CDM)是华为云上一个迁移工具,详见 CDM官网 ,小编则通过CDM介绍如何切换三种模式抽取数据。CDM默认使用的是方式3,流式抽取数据,如果需要切换方式1,方式2需额外配置。

1.3.1 配置方式1:默认读取

新建Mysql连接器,建立方法详见官网,在高级属性中增加useCursorFetch=false和adopt.stream=false

1.3.2 配置方式2:游标查询

编辑Mysql连接器,在高级属性中增加useCursorFetch=true和adopt.stream=false。游标查询的大小可通过界面上的Fetch Size调整,默认1000。

1.3.3 配置方式3:流式

CDM默认走的流式,无需额外配置。注意Stream模式下,界面上的 Fetch Size 是不起作用的,原因参考上一节。

1.3.4 性能对比

新建Mysql2Hive的CDM迁移作业,源表101个字段,100万行数据,配置如下

方式1:写入100万行数据耗时1m22s

方式2:同样写入100万行,调整fetchSzie分别为1,10,100,100,最低耗时2m1s

方式3:同样写入100万行,耗时1m5s

小编还测试了100万的小表,明显方式1和方式3的速率要远远高于方式2,另外小编还测试了1000万的大表,方式1爆内存,方式2正常迁移但耗时20分钟以上,而方式3仍然可以在15分钟内跑完。

到此这篇关于从云数据迁移服务看MySQL大表抽取模式的原理解析的文章就介绍到这了,更多相关MySQL大表抽取内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Innodb中mysql快速删除2T的大表方法示例

    前言 本文主要给大家介绍了关于Innodb中mysql快速删除2T的大表的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧 来,先来看小漫画陶冶一下情操 OK,这里就说了.假设,你有一个表erp,如果你直接进行下面的命令 drop table erp 这个时候所有的mysql的相关进程都会停止,直到drop结束,mysql才会恢复执行.出现这个情况的原因就是因为,在drop table的时候,innodb维护了一个全局锁,drop完毕锁就释放了. 这意味着,如果在白天,访

  • mysql千万级数据大表该如何优化?

    1.数据的容量:1-3年内会大概多少条数据,每条数据大概多少字节: 2.数据项:是否有大字段,那些字段的值是否经常被更新: 3.数据查询SQL条件:哪些数据项的列名称经常出现在WHERE.GROUP BY.ORDER BY子句中等: 4.数据更新类SQL条件:有多少列经常出现UPDATE或DELETE 的WHERE子句中: 5.SQL量的统计比,如:SELECT:UPDATE+DELETE:INSERT=多少? 6.预计大表及相关联的SQL,每天总的执行量在何数量级? 7.表中的数据:更新为主的

  • MySQL 大表添加一列的实现

    问题参考自: https://www.zhihu.com/question/440231149 ,mysql中,一张表里有3亿数据,未分表,要求是在这个大表里添加一列数据.数据库不能停,并且还有增删改操作.请问如何操作?答案为个人原创 以前老版本 MySQL 添加一列的方式: ALTER TABLE 你的表 ADD COLUMN 新列 char(128); 会造成锁表,简易过程如下: 新建一个和 Table1 完全同构的 Table2 对表 Table1 加写锁 在表 Table2 上执行 AL

  • MySQL 删除大表的性能问题解决方案

    微博上讨论MySQL在删除大表engine=innodb(30G+)时,如何减少MySQL hang的时间,现做一下简单总结: 当buffer_pool很大的时候(30G+),由于删除表时,会遍历整个buffer pool来清理数据,会导致MySQL hang住,解决的办法是: 1.当innodb_file_per_table=0的时候,以上不是问题,因为采用共享表空间的时候,该表所占用的空间不会被删除,buffer pool中的相关页不会 被discard. 2.当innodb_file_pe

  • MySQL大表中重复字段的高效率查询方法

    MySQL大表重复字段应该如何查询到呢?这是很多人都遇到的问题,下面就教您一个MySQL大表重复字段的查询方法,供您参考. 数据库中有个大表,需要查找其中的名字有重复的记录id,以便比较.如果仅仅是查找数据库中name不重复的字段,很容易 复制代码 代码如下: SELECT min(`id`),`name` FROM `table` GROUP BY `name`; 但是这样并不能得到说有重复字段的id值.(只得到了最小的一个id值)查询哪些字段是重复的也容易  复制代码 代码如下: SELEC

  • 从云数据迁移服务看MySQL大表抽取模式的原理解析

    摘要:MySQL JDBC抽取到底应该采用什么样的方式,且听小编给你娓娓道来. 小编最近在云上的一个迁移项目中被MySQL抽取模式折磨的很惨.一开始爆内存被客户怼,再后来迁移效率低下再被怼.MySQL JDBC抽取到底应该采用什么样的方式,且听小编给你娓娓道来. 1.1 Java-JDBC通信原理 JDBC与数据库之间的通信是通过socket完,大致流程如下图所示.Mysql Server ->内核Socket Buffer -> 客户端Socket Buffer ->JDBC所在的JV

  • mysql 大表批量删除大量数据的实现方法

    问题参考自:https://www.zhihu.com/question/440066129/answer/1685329456 ,mysql中,一张表里有3亿数据,未分表,其中一个字段是企业类型,企业类型是一般企业和个体户,个体户的数据量差不多占50%,根据条件把个体户的行都删掉.请问如何操作?答案为个人原创 假设表的引擎是 Innodb, MySQL 5.7+ 删除一条记录,首先锁住这条记录,数据原有的被废弃,记录头发生变化,主要是打上了删除标记.也就是原有的数据 deleted_flag

  • 浅谈MySQL大表优化方案

    背景 阿里云RDS FOR MySQL(MySQL5.7版本)数据库业务表每月新增数据量超过千万,随着数据量持续增加,我们业务出现大表慢查询,在业务高峰期主业务表的慢查询需要几十秒严重影响业务 方案概述 一.数据库设计及索引优化 MySQL数据库本身高度灵活,造成性能不足,严重依赖开发人员的表设计能力以及索引优化能力,在这里给几点优化建议 时间类型转化为时间戳格式,用int类型储存,建索引增加查询效率 建议字段定义not null,null值很难查询优化且占用额外的索引空间 使用TINYINT类

  • MySQL 大表的count()优化实现

    以下是基于我结合B+树的数据结构和对实验结果的推测作出的判断,如有错误,恳请指正! 今天实验了一下MySQL的count()操作优化, 以下讨论基于mysql5.7 InnoDB存储引擎. x86 windows操作系统. 创建的表的结构如下(数据量为100万): 首先是关于mysql的count(*),count(PK), count(1)哪个快的问题. 实现结果如下: 并没有什么区别!加上了WHERE子句之后3个查询的时间也是相同的,我就不贴图片了. 之前在公司的时候就写过一个select

  • MySQL在线DDL工具 gh-ost的原理解析

    一.简介 gh-ost基于 golang 语言,是 github 开源的一个 DDL 工具,是 GitHub's Online Schema Transmogrifier/Transfigurator/Transformer/Thingy 的缩写,意思是 GitHub 的在线表定义转换器. 1.1 原理 主要实现原理,首先建两张表,一张_gho的影子表,gh-ost会将原表数据以及增量数据都应用到这个表,最后会将这个表和原表做次表名切换,另一张是_ghc表,这个表是存放changelog的数据,

  • mysql的Buffer Pool存储及原理解析

    目录 一.前言 1.buffer pool是什么 2.buffer pool的工作流程 3.buffer pool缓冲池和查询缓存(query cache) 二.buffer pool的内存数据结构 1.数据页概念 2.那么怎么识别数据在哪个缓存页中 3.buffer pool的初始化与配置 3.1.初始化 3.2.buffer pool的配置 3.3.Buffer Pool Size 设置和生效过程 3.4.Buffer Pool Instances 3.5.SHOW ENGINE INNOD

  • MySQL多版本并发控制MVCC底层原理解析

    目录 1 事务并发中遇到的问题 1.1 脏读 1.2 不可重复读 1.3 幻读 2 隔离级别 3 版本链 4 ReadView 4.1 ReadView 定义 4.2 访问控制 4.3 再谈隔离 4.3.1 READ COMMITTED(读已提交) 4.3.2 REPEATABLE READ(可重读) 5 幻读 6 总结 1 事务并发中遇到的问题 1.1 脏读 当一个事务读取到了另外一个事务修改但未提交的数据,被称为脏读. 1.2 不可重复读 当事务内相同的记录被检索两次,且两次得到的结果不同时

  • Mysql大数据量查询优化思路详析

    目录 1. 千万级别日志查询的优化 2. 几百万黑名单库的查询优化 3. Mybatis批量插入处理问题 项目场景: Mysql大表查询优化,理论上千万级别以下的数据量Mysql单表查询性能处理都是可以的. 问题描述: 在我们线上环境中,出现了mysql几千万级别的日志查询.几百万级别的黑名单库查询分页查询及条件查询都慢的问题,针对Mysql表优化做了一些优化处理. 原因分析:首先说一下日志查询,在Mysql中如果索引加的比较合适,走索引情况下千万级别查询不会超过一秒,Mysql查询的速度和检索

随机推荐