資料移轉經驗總結——億層級多表異構的資料移轉工作,經驗總結異構

來源:互聯網
上載者:User

資料移轉經驗總結——億層級多表異構的資料移轉工作,經驗總結異構

由於系統改版,最近三個月在做資料移轉工作,由於業務的特殊,基本將資料移轉所能踩的坑都踩了一遍,決定好好做個總結。

遷移類型——新老系統資料表結構變化較大的曆史資料

一、核心問題

1.新老表結構變化極大。新表是以deliver為核心,另外還涉及倉儲系統的一張表,訂單系統的4張表,並按照新的邏輯映射關係進行遷移。
2.增量資料移轉。在全量資料移轉時必然會有新的資料,這些資料應該即時進行遷移
3.億層級資料效能、效率的考慮。由於訂單業務非常重要,資料移轉帶來的qps對資料庫的壓力非常大,需要不斷測試迭代找到一個適合的遷移效率和效能。
4.老資料格式問題。12、13年的資料由於曆史悠久,會存在缺資料,資料不全的問題,這些問題都應該在程式中進行容錯。
5.核對資料比較困難。由於新表涉及多箇舊表且資料量龐大,資料核對比較困難,目前自己寫指令碼按周並根據一定的邏輯進行資料核對,同時輔以肉眼比對。


二、資料移轉流程

全量同步 java程式

增量同步處理 otter + 擴充的java程式

曆史資料 需同步到 後端backend 和 前端cobar庫 


1.曆史資料按年份下載成多個文本(1個文本2g左右)

2.多線程讀文本資料

3.處理類型主要有insert batch_insert update ,根據類型不同,線程調用不同邏輯方法處理資料並寫入新表


三、展開討論

將上面問題進行展開,並總結其中的技術問題

1.項目架構層次

   該遷移項目採用java開發,僅僅作為遷移,定位輕量級,後端db採用jdbcTemplate , spring管理javabean 分為三層, 一層manager主要對資料流根據類型分發給不同商務邏輯處理 一層商務邏輯——處理映射關係 一層dao。

2.db相關問題

   後台db 是一主多從 主用來接受寫請求,從都是讀請求。 從庫效能遠遠低於主庫

  2.1 調用介面取資料的問題

   剛開始做時,由於想把項目做的很輕,擷取老資料採用調介面的形式,調用order介面、wms介面擷取就可以擷取相應資料。但介面是很脆弱的,經統計http介面每秒只能抗500-1000左右的請求,大資料量下介面很快就成為瓶頸。我測試過一次,1億資料需要2周時間才能導完,所以必須放棄調用介面,自己讀db進行查詢。

  2.2 冷熱庫問題

   曆史資料大部分在冷庫裡,在db查詢是需要先查熱庫再查冷庫,並按照相應的邏輯進行查庫。

  2.3 batch批量插入 主從延遲問題

      一開始資料處理一條插入一條,這樣1億資料要產生1億條insert語句。對於主庫來說寫入是沒有影響的,但是從庫有很大問題,其效能和主庫相差深遠,同時在同步binlog上會產生很大的延時,一億insert意味著一億次commited 一億次提交 binlog同步時就會進行1億次網路傳輸,從庫也會執行1億次insert。這時候延遲還會產生更大的問題,因為主庫還有其他業務資料寫入,從庫沒有即時同步,導致客服查不到訂單。

     後來改成多value的insert語句,每次處理一批資料,一個commit提交。這樣即提高了insert插入效能,又解決了延遲問題。

     jdbcTemplate改為updateBacth()方法,但發現sql語句還是一個資料一個insert,這是必須讓jdbc如何支援batch insert, 需要在jdbc串連加上參數 jdbc:mysql://.....&rewriteBatchedStatements=true ;

    2.4  sql的dead connection

    多線程讀資料時,發現有幾個線程一直阻塞了,jstack後,發現Mysql報sokcetAvaiable,這個錯誤一般發生在串連前端cobar時。這是因為jdbc串連沒有設定連線逾時,要加上connectTime socketTIme,這個是自己應用串連資料庫的網路逾時時間,如果不設定就會一直等待下去。

      設定參數:&failOverReadOnly=false&connectTimeout=60000&socketTimeout=60000 failOverReadOnly jdbc預設逾時重試就變為唯讀了,必須加上failOverReadOnly參數

   3. 程式級最佳化

    3.1 全量資料的多線程解決方案

    單進程遷移,1億資料大概需要1周時間,時間和效率都太低了,所以思考改為多線程。其實改多線程很簡單,曆史資料是文本形式,只需要多線程去逐一讀文本,並發處理就可以了,同時採用countdownlatch保證線程全部完成後在退出主程式。

    3.2 增量資料的多線程解決方案

    otter會順序的消費binlog,消費過程是很快的,但如果採用單進程模式,瓶頸會卡在我的寫入程式上,所以將程式該為多線程。otter每次讀取2000個binlog記錄,主進程一旦獲得滿2000個後,再啟動多線程去並發處理這些記錄。還需要注意問題,有可能同一時間段針對一條記錄有多個改動,需要以最後一次改動為準,所以我將線程個數最為桶的個數,按照order_id和桶的餘數放入到對應的桶裡,同時通的value是一個map (order_id , row對象),這樣可以保證每一批處理都是最新的記錄。

    3.3 otter的擴充

    以後我會再寫一篇博文分析otter,這裡先簡要介紹一下。otter是阿里的一個開源項目,主要解決異地機房即時資料備份的問題,它的原理就是通過把自己偽裝成slave去讀取master的binlog然後解析成eventData對象並寫入新的表裡。它預設情況下僅支援一對一的複製、表的欄位對應邏輯非常簡單的複製。但阿里的項目就是強大,它給使用者提供了一個介面,繼承之後就可以按照自己的邏輯去同步資料了。繼承類是AbstractEventProcessor,這個類會接受到擷取的eventData對象(就是binlog一條內容),這裡面有你訂閱的表的所有欄位值,sql類型等。繼承後,在該類的方法裡引入自己的同步程式,這樣otter訂閱的資料就會進入自己的程式了。


   4.資料補救策略

    資料移轉後依然會存在一些問題:

    1.增量過程中,由於網路等原因會造成binlog讀取的卡頓,canal會進行重試,但是貌似該時間點上的資料依然會丟失

    2.遷移過程中,有一些時間點的誤差導致資料丟失或異常。

    由於新舊錶結果相差很大,資料量也太大了,不能簡單用一條sql,這樣會拖庫。所以我寫程式一周一周核對資料,主要核對新表有舊錶沒有的,這些需要刪除;舊錶有新表沒有的,這些需要添加;新表舊錶status不一致的這些需要根據舊錶更新。


    小結:

        1.效能——在遷移前對mysql效能,資料量大小都沒有一定的認識,採用介面擷取資料後改用讀庫多線程,一前一後浪費了半個多月的時間,再做遷移一定要考慮好資料量,遷移時間,表結果,mysql效能。

        2.代碼編寫——該程式耦合太嚴重,後期每增加一種操作類型,原代碼上都要加很多判斷,下次再寫必須要面向介面編程,使用繼承和Factory 方法(參考秒殺項目);jdbcTample很輕量級,單sql多了後,代碼量還是會上來,下次提前做好評估,用mybatis;校正指令碼和執行指令碼過多,日誌列印也過多,下次還是採用log4j可輸出多文本,同時指令碼書寫上要更優雅和簡潔。

        3.核對資料——資料移轉是一件髒活累活,這次遷移有一大半時間在進行資料和對,不停寫sql,不停看校正資料。以後再有類似的遷移必須要先規劃好,怎樣進行核對,例如選擇幾個關鍵字段做hash。



參考文獻:

1.《關於資料移轉的方法、步驟和心得》http://m.blog.csdn.net/blog/baoqiangwang_11109/5492910

2.  Jdbc驅動的rewriteBatchedStatements參數 http://www.cnblogs.com/chenjianjx/archive/2012/08/14/2637914.html

3.  深入理解JDBC的逾時設定 http://www.importnew.com/2466.html 

4. otter https://github.com/alibaba/otter

著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.