摘要: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大表抽取模式》,原文作者:Leef724。
点击关注,第一工夫理解华为云陈腐技术~