從云數(shù)據(jù)遷移服務(wù)看MySQL大表抽取模式的原理解析
摘要:MySQL JDBC抽取到底應(yīng)該采用什么樣的方式,且聽(tīng)小編給你娓娓道來(lái)。
小編最近在云上的一個(gè)遷移項(xiàng)目中被MySQL抽取模式折磨的很慘。一開(kāi)始爆內(nèi)存被客戶(hù)懟,再后來(lái)遷移效率低下再被懟。MySQL JDBC抽取到底應(yīng)該采用什么樣的方式,且聽(tīng)小編給你娓娓道來(lái)。
1.1 Java-JDBC通信原理
JDBC與數(shù)據(jù)庫(kù)之間的通信是通過(guò)socket完,大致流程如下圖所示。Mysql Server ->內(nèi)核Socket Buffer -> 客戶(hù)端Socket Buffer ->JDBC所在的JVM
1.2 JDBC讀取數(shù)據(jù)的三種模式
1.2.1 方式1:使用JDBC默認(rèn)參數(shù)讀取數(shù)據(jù)
主要分為以下幾步:
1)Mysql Server通過(guò)OuputStream 向 Socket Server 本地Kennel Buffer 寫(xiě)入數(shù)據(jù),這里是一次內(nèi)存拷貝。
2)當(dāng)Socket Server 本地Kennel Buffer 有數(shù)據(jù),就會(huì)通過(guò)TCP鏈路把數(shù)據(jù)傳輸?shù)絊ocket Client 所在機(jī)器的Kennel Buffer。
3)JDBC 所在JVM利用InputSream讀取本地Kennel Buffer 數(shù)據(jù)到JVM內(nèi)存,沒(méi)有數(shù)據(jù)時(shí),則讀取被阻塞。
接下來(lái)就是不斷重復(fù)1,2,3的過(guò)程。 問(wèn)題 是,Socket Client 端的JVM在默認(rèn)模式下讀取Kennel Buffer是沒(méi)有考慮本機(jī)內(nèi)存大小的,有多少讀多少。如果數(shù)據(jù)太大,就會(huì)造成FULL GC,緊接著內(nèi)存溢出。
參考 JDBC API docs,默認(rèn)模式 Java demo 代碼如下
1.2.2 方式2:游標(biāo)查詢(xún)
為了解決方式1爆內(nèi)存的問(wèn)題,JDBC提供了一個(gè)游標(biāo)參數(shù),在建立jdbc連接時(shí)加上useCursorFetch=true。設(shè)置游標(biāo)后,JDBC 每次會(huì)告訴Server端每次抽取的數(shù)據(jù)量,避免爆內(nèi)存。通信過(guò)程如下圖所示。
方式2游標(biāo)查詢(xún)雖然解決了內(nèi)存溢出的問(wèn)題,方式2極大的依賴(lài)網(wǎng)絡(luò)質(zhì)量。當(dāng)網(wǎng)絡(luò)時(shí)延增大,假設(shè)每次通信增加10ms,10萬(wàn)次通信就會(huì)多出1000s。這里僅僅是每次發(fā)請(qǐng)求的RT,TCP每次發(fā)送報(bào)文,都要求反饋ACK保證數(shù)據(jù)可靠性。client每取100行(請(qǐng)求行數(shù)可配置),就會(huì)有多次通信,進(jìn)一步放大時(shí)延增加導(dǎo)致的效率問(wèn)題。此外,游標(biāo)查詢(xún)下,Mysql無(wú)法預(yù)知查詢(xún)的結(jié)束時(shí)延,為了應(yīng)對(duì)自身的DML操作會(huì)在本地建立一個(gè)臨時(shí)空間存放要抽取的數(shù)據(jù)。因此,游標(biāo)查詢(xún)時(shí)會(huì)有以下幾個(gè)現(xiàn)象發(fā)生
a. IOPS飆升,Mysql將數(shù)據(jù)寫(xiě)入到臨時(shí)空間,數(shù)據(jù)傳輸時(shí)從臨時(shí)空間讀取數(shù)據(jù),這都會(huì)引發(fā)大量IO操作。
b. 磁盤(pán)空間飆升,臨時(shí)空間生命周期存在于整個(gè)JDBC讀取階段,直到客戶(hù)端發(fā)起Result.close()時(shí)才會(huì)被Mysql回收。
c. CPU和內(nèi)存有一定比例上升。
有關(guān)游標(biāo)查詢(xún)的原理可參考博客MySQL JDBC StreamResult通信原理淺析以及JDBC源碼,本文不在贅述。
參考 JDBC API docs,游標(biāo)模式 Java demo 代碼如下
1.2.3 方式3: Stream讀取數(shù)據(jù)
方式1會(huì)導(dǎo)致JVM內(nèi)存溢出,方式2雖然不會(huì)FULL GC但是通信效率較低,而且也會(huì)導(dǎo)致Mysql服務(wù)端IOPS飆升,消耗磁盤(pán)空間等問(wèn)題。因此,我們介紹Stream讀取數(shù)據(jù) ,流式需要在讀取Result前設(shè)置
方式3在通信前不會(huì)做任何Server-Cient的交互操作,避免通信效率低下。服務(wù)端準(zhǔn)備好數(shù)據(jù)寫(xiě)入Server的Kennel Buffer中,這些數(shù)據(jù)通過(guò)TCP鏈路傳輸?shù)紺lient的Kennel Buffer中,緊接著client端inputStream.read()方法被喚醒去讀取數(shù)據(jù),與方式1不同,client每次只會(huì)讀取一個(gè)package大小的數(shù)據(jù),如果一個(gè)package不滿一行則會(huì)再讀取一個(gè)package。當(dāng)client消費(fèi)數(shù)據(jù)的速度不及數(shù)據(jù)傳輸速率時(shí),client端kennel區(qū)的數(shù)據(jù)就會(huì)被堆滿,緊接著Server端的kennel數(shù)據(jù)也會(huì)堆滿進(jìn)而阻塞了OuputStream。這樣,JDBC在Stream模式下就像一個(gè)水管連接兩個(gè)蓄水池,Client和Server達(dá)到一個(gè)平衡。
對(duì)于JDBC客戶(hù)端,由于每次都是從kennel讀取數(shù)據(jù),效率會(huì)比方式2高很多,每次讀取一小部分?jǐn)?shù)據(jù)也不會(huì)導(dǎo)致JVM內(nèi)存溢出。對(duì)于服務(wù)端,Mysql每次都是往kennel寫(xiě)數(shù)據(jù),無(wú)需建立臨時(shí)空間,不涉及IO讀取,服務(wù)端壓力也變小了。當(dāng)然,方式3也有自己的問(wèn)題,例如Stream流式時(shí)無(wú)法cancel,cancel不阻塞等等。
參考 JDBC API docs,網(wǎng)上很多教程需要設(shè)置useCursorFetch=trueResultSet.FETCH_REVERSE等,其實(shí)小編研究完JDBC驅(qū)動(dòng)源碼后發(fā)現(xiàn),只需要設(shè)fetchSize=Integer. MIN_VALUE,其他配置均和默認(rèn)配置保持一致即可。游標(biāo)模式 Java demo 代碼如下
1.3 云數(shù)據(jù)遷移服務(wù)在三種模式下的調(diào)優(yōu)
云數(shù)據(jù)遷移服務(wù)(Cloud Data Migration, CDM)是華為云上一個(gè)遷移工具,詳見(jiàn) CDM官網(wǎng) ,小編則通過(guò)CDM介紹如何切換三種模式抽取數(shù)據(jù)。CDM默認(rèn)使用的是方式3,流式抽取數(shù)據(jù),如果需要切換方式1,方式2需額外配置。
1.3.1 配置方式1:默認(rèn)讀取
新建Mysql連接器,建立方法詳見(jiàn)官網(wǎng),在高級(jí)屬性中增加useCursorFetch=false和adopt.stream=false
1.3.2 配置方式2:游標(biāo)查詢(xún)
編輯Mysql連接器,在高級(jí)屬性中增加useCursorFetch=true和adopt.stream=false。游標(biāo)查詢(xún)的大小可通過(guò)界面上的Fetch Size調(diào)整,默認(rèn)1000。
1.3.3 配置方式3:流式
CDM默認(rèn)走的流式,無(wú)需額外配置。注意Stream模式下,界面上的 Fetch Size
是不起作用的,原因參考上一節(jié)。
1.3.4 性能對(duì)比
新建Mysql2Hive的CDM遷移作業(yè),源表101個(gè)字段,100萬(wàn)行數(shù)據(jù),配置如下
方式1:寫(xiě)入100萬(wàn)行數(shù)據(jù)耗時(shí)1m22s
方式2:同樣寫(xiě)入100萬(wàn)行,調(diào)整fetchSzie分別為1,10,100,100,最低耗時(shí)2m1s
方式3:同樣寫(xiě)入100萬(wàn)行,耗時(shí)1m5s
小編還測(cè)試了100萬(wàn)的小表,明顯方式1和方式3的速率要遠(yuǎn)遠(yuǎn)高于方式2,另外小編還測(cè)試了1000萬(wàn)的大表,方式1爆內(nèi)存,方式2正常遷移但耗時(shí)20分鐘以上,而方式3仍然可以在15分鐘內(nèi)跑完。
到此這篇關(guān)于從云數(shù)據(jù)遷移服務(wù)看MySQL大表抽取模式的原理解析的文章就介紹到這了,更多相關(guān)MySQL大表抽取內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 關(guān)于MySQL數(shù)據(jù)遷移--data目錄直接替換注意事項(xiàng)的詳解
- 一句命令完成MySQL的數(shù)據(jù)遷移(輕量級(jí)數(shù)據(jù))
- SQL Server數(shù)據(jù)遷移至PostgreSQL出錯(cuò)的解釋以及解決方案
- 如何把sqlserver數(shù)據(jù)遷移到mysql數(shù)據(jù)庫(kù)及需要注意事項(xiàng)
- 簡(jiǎn)述MySQL分片中快速數(shù)據(jù)遷移
- mysql數(shù)據(jù)遷移到Oracle的正確方法
- MySQL數(shù)據(jù)遷移使用MySQLdump命令
- 使用SQL SERVER存儲(chǔ)過(guò)程實(shí)現(xiàn)歷史數(shù)據(jù)遷移方式
- mysql數(shù)據(jù)遷移之data目錄復(fù)制方法
- MySql使用存儲(chǔ)過(guò)程進(jìn)行單表數(shù)據(jù)遷移的實(shí)現(xiàn)
- Sql Server數(shù)據(jù)遷移的實(shí)現(xiàn)場(chǎng)景及示例
相關(guān)文章
遠(yuǎn)程連接mysql報(bào)錯(cuò)“Host?xxx?is?not?allowed?to?connect?to?th
這篇文章主要給大家介紹了關(guān)于遠(yuǎn)程連接mysql報(bào)錯(cuò)“Host?xxx?is?not?allowed?to?connect?to?this?MySQL?server“的解決辦法,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-07-07mysql查詢(xún)昨天 一周前 一月前 一年前的數(shù)據(jù)
這篇文章主要介紹了mysql查詢(xún)昨天 一周前 一月前 一年前的數(shù)據(jù)的方法,需要的朋友可以參考下2014-05-05Mysql數(shù)據(jù)庫(kù)時(shí)間查詢(xún)舉例詳解
在項(xiàng)目開(kāi)發(fā)中,一些業(yè)務(wù)表字段經(jīng)常使用日期和時(shí)間類(lèi)型,而且后續(xù)還會(huì)牽涉到這類(lèi)字段的查詢(xún),下面這篇文章主要給大家介紹了關(guān)于Mysql數(shù)據(jù)庫(kù)時(shí)間查詢(xún)的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-05-05MySQL遞歸查詢(xún)的3種實(shí)現(xiàn)方式實(shí)例
在項(xiàng)目中會(huì)遇到同一個(gè)表中保存著父子關(guān)系的數(shù)據(jù),最常見(jiàn)的就是處理樹(shù)形結(jié)構(gòu)資源,下面這篇文章主要給大家介紹了關(guān)于MySQL遞歸查詢(xún)的3種實(shí)現(xiàn)方式,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-04-04mysql中的utf8與utf8mb4存儲(chǔ)及區(qū)別
本文主要介紹了mysql中的utf8與utf8mb4存儲(chǔ)及區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-02-02解決Mysql同步到ES時(shí)date和time字段類(lèi)型轉(zhuǎn)換問(wèn)題
這篇文章主要介紹了Mysql同步到ES時(shí)date和time字段類(lèi)型轉(zhuǎn)換問(wèn)題解決辦法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-07-07MySQL級(jí)聯(lián)復(fù)制下如何進(jìn)行大表的字段擴(kuò)容
這篇文章主要介紹了MySQL級(jí)聯(lián)復(fù)制下進(jìn)行大表的字段擴(kuò)容,庫(kù)表信息環(huán)境是Mysql 8.0.22,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-04-04