阿里開源數據庫遷移項目yugong——(使用指南)

背景

      08年左右,阿里巴巴開始嘗試MySQL的相關研究,並開發了基於MySQL分庫分表技術的相關產品,Cobar/TDDL(目前爲阿里雲DRDS產品),解決了單機Oracle無法滿足的擴展性問題,當時也掀起一股去IOE項目的浪潮,愚公這項目因此而誕生,其要解決的目標就是幫助用戶完成從Oracle數據遷移到MySQL上,完成去IOE的第一步. 


項目介紹

名稱:   yugong

譯意:   愚公移山

語言:   純java開發

定位:   數據庫遷移 (目前主要支持oracle / mysql / DRDS)


環境要求

操作系統

a. 純java開發,有bat和shell腳本,windows/linux均可支持.
b. jdk建議使用1.6.25以上的版本,穩定可靠,目前阿里巴巴使用基本爲此版本.


數據庫

a. 源庫爲oracle,目標庫可爲mysql/drds/oracle. 基於標準jdbc協議開發,對數據庫暫無版本要求
需要的數據庫賬戶權限:
1. 源庫(oracle)

GRANT SELECT,INSERT,UPDATE,DELETE ON XXX TO XXX; #常見CRUD權限
GRANT CREATE ANY MATERIALIZED VIEW TO XXX;
GRANT DROP ANY MATERIALIZED VIEW TO XXX;

2. 目標庫(mysql/oracle)

GRANT SELECT,INSERT,UPDATE,DELETE ON XXX TO XXX;

遷移方案

整個遷移方案,分爲兩部分:

  1. 全量遷移
  2. 增量遷移

過程描述:

  1. 增量數據收集 (創建oracle表的增量物化視圖)
  2. 進行全量複製
  3. 進行增量複製 (並行進行數據校驗)
  4. 原庫停寫,切到新庫

回滾方案:

  1. 開啓新庫到老庫的數據迴流

部署

下載

1. 源碼編譯

github地址: https://github.com/alibaba/yugong

git clone https://github.com/alibaba/yugong.git

下載後在yugong目錄下,執行

mvn clean install -Dmaven.test.skip -Denv=release

會在dist目錄下生成yugong-x.y.z.tar.gz文件

2. 二進制包下載

下載地址: https://github.com/alibaba/yugong/releases


目錄結構

解壓縮發佈包後,可得如下目錄結構:

drwxr-xr-x 2 jianghang jianghang  136 2013-09-29 17:19 bin
drwxr-xr-x 3 jianghang jianghang  152 2013-09-29 17:19 conf
drwxr-xr-x 2 jianghang jianghang 1640 2013-09-29 17:19 lib
drwxr-xr-x 2 jianghang jianghang   48 2013-09-29 11:57 logs

修改配置

正常情況下,只需修改下yugong.database的源庫和目標庫的地址信息,通過yugong.table.white定義本次需要遷移的表,通過yugong.table.mode定義要執行的操作,是全量還是增量等,其他的可以使用默認值.

默認值    :


啓動停止

linux啓動 :

sh startup.sh

linux帶debug方式啓動:(默認使用suspend=n,可設置爲y,阻塞等待你remote debug鏈接成功) 

sh startup.sh debug 9099 

linux停止:

sh stop.sh  

幾點注意:

  1. linux啓動完成後,會在bin目錄下生成yugong.pid,stop.sh會讀取yugong.pid進行進程關閉
  2. startup.sh默認讀取系統環境變量中的which java獲得JAVA執行路徑,需要設置PATH=$JAVA_HOME/bin環境變量

windows啓動:

startup.bat

windows停止:直接關閉終端即可


查看日誌

對應日誌結構爲:

logs/
  - yugong/  #系統根日誌
     - table.log
  - ${table}/  #每張同步表的日誌信息
     - table.log
     - extractor.log
     - applier.log
     - check.log

全量完成的日誌:(會在yugong/table.log 和 ${table}/table.log中出現記錄)

table[OTTER2.TEST_ALL_ONE_PK] is end!

增量日誌:(會在${table}/table.log中出現記錄)

table[OTTER2.TEST_ALL_ONE_PK] now is CATCH_UP ... #代表已經追上,最後一次增量數據小於onceCrawNum數量
table[OTTER2.TEST_ALL_ONE_PK] now is NO_UPDATE ... #代表最近一次無增量數據

ALL(全量+增量)模式日誌: (會在${table}/table.log中出現記錄)

table [OTTER2.TEST_ALL_ONE_PK] full extractor is end , next auto start inc extractor #出現這條代表全量已經完成,進入增量模式

CHECK日誌: (會在${table}/check.log中出現diff記錄)

-----------------
- Schema: yugong , Table: test_all_one_pk
-----------------
---Pks
        ColumnValue[column=ColumnMeta[index=0,name=ID,type=3],value=2576]
---diff
        ColumnMeta[index=3,name=AMOUNT,type=3] , values : [0] vs [0.0]

同步過程數據日誌:會通過extractor.log/applier.log分別記錄extractor和applier的數據記錄,因爲有DataTranslator的存在,兩者記錄可能不一致,所以分開兩份記錄.

統計信息:

  • progress統計,會在主日誌下,輸出當前全量/增量/異常表的數據,可通過該日誌,全局把握整個遷移任務的進度,輸出類似:
    {未啓動:0,全量中:2,增量中:3,已追上:3,異常數:0}
  • stat統計,會在每個表遷移日誌下,輸出當前遷移的tps信息
    {總記錄數:180000,採樣記錄數:5000,同步TPS:4681,最長時間:215,最小時間:212,平均時間:213} 

切換流程

  1. 當任務處於追上狀態時候,表示已經處於實時同步狀態
  2. 後續通過源數據庫進行停寫,稍等1-2分鐘後(保證延時的數據最終得到同步,此時源庫和目標庫當前數據是完全一致的)
  3. 檢查增量持續處於NO_UPDATE狀態,可關閉該遷移任務(sh stop.sh),即可發佈新程序,使用新的數據庫,完成切換的流程.

自定義數據轉換

 如果要遷移的oracle和mysql的表結構不同,比如表名,字段名有差異,字段類型不兼容,需要使用自定義數據轉換。如果完全相同那就可以跳過此章節

整個數據流爲:DB -> Extractor -> DataTranslator -> Applier -> DB,本程序預留DataTranslator接口,允許外部用戶自定義數據處理邏輯,比如:

  1. 表名不同
  2. 字段名不同
  3. 字段類型不同
  4. 字段個數不同
  5. 運行過程join其他表的數據做計算等

例子:

/**
 * 一個遷移的例子,涵蓋一些基本轉換操作
 *
 * <pre>
 * 例子包含特性:
 * 1. schema/table名不同. oracle中爲otter2.yugong_example_oracle,mysql中爲test.yugong_example_mysql
 * 2. 字段名字不同.  oracle中的name字段,映射到mysql的display_name
 * 3. 字段邏輯處理.  mysql的display_name字段數據來源爲oracle庫的:name+'('alias_name+')'
 * 4. 字段類型不同.  oracle中的amount爲number類型,映射到mysql的amount爲varchar文本型
 * 5. 源庫多一個字段. oracle中多了一個alias_name字段
 * 6. 目標庫多了一個字段. mysql中多了一個gmt_move字段,(簡單的用遷移時的當前時間進行填充)
 *
 * 測試的表結構:
 * // oracle表
 * create table otter2.yugong_example_oracle
 * (
 *     id NUMBER(11)  ,
 *     name varchar2(32) ,
 *     alias_name  char(32) default ' ' not null,
 *     amount number(11,2),
 *     score  number(20),
 *     text_b blob,
 *     text_c clob,
 *     gmt_create date not null,
 *     gmt_modified date not null,
 *     CONSTRAINT yugong_example_oracle_pk_id  PRIMARY   KEY (id)
 * );
 *
 * // mysql表
 * create table test.yugong_example_mysql
 * (
 *     id bigint(20) unsigned auto_increment,
 *     display_name varchar(128) ,
 *     amount varchar(32),
 *     score bigint(20) unsigned ,
 *     text_b blob,
 *     text_c text,
 *     gmt_create timestamp not null,
 *     gmt_modified timestamp not null,
 *     gmt_move timestamp not null,
 *     CONSTRAINT yugong_example_mysql_pk_id  PRIMARY KEY (id)
 * );
 * </pre>
 *
 * @author jianghang 2013-10-10 下午3:28:33
 */
public class YugongExampleOracleDataTranslator extends AbstractDataTranslator implements DataTranslator {
public boolean translator(Record record) {
    // 1. schema/table名不同
    // record.setSchemaName("test");
    record.setTableName("yugong_example_mysql");

    if (record instanceof IncrementRecord) {
        if (IncrementOpType.D == ((IncrementRecord) record).getOpType()) {
            // 忽略delete
            return super.translator(record);
        }
    }

    // 2. 字段名字不同
    ColumnValue nameColumn = record.getColumnByName("name");
    nameColumn.getColumn().setName("display_name");

    // 3. 字段邏輯處理
    ColumnValue aliasNameColumn = record.getColumnByName("alias_name");
    StringBuilder displayNameValue = new StringBuilder(64);
    displayNameValue.append(ObjectUtils.toString(nameColumn.getValue()))
        .append('(')
        .append(ObjectUtils.toString(aliasNameColumn.getValue()))
        .append(')');
    nameColumn.setValue(displayNameValue.toString());

    // 4. 字段類型不同
    ColumnValue amountColumn = record.getColumnByName("amount");
    amountColumn.getColumn().setType(Types.VARCHAR);
    amountColumn.setValue(ObjectUtils.toString(amountColumn.getValue()));

    // 5. 源庫多一個字段
    record.getColumns().remove(aliasNameColumn);

    // 6. 目標庫多了一個字段
    ColumnMeta gmtMoveMeta = new ColumnMeta("gmt_move", Types.TIMESTAMP);
    ColumnValue gmtMoveColumn = new ColumnValue(gmtMoveMeta, new Date());
    record.addColumn(gmtMoveColumn);

    // ColumnValue text_c = record.getColumnByName("text_c");
    // try {
    // text_c.setValue(new String((byte[]) text_c.getValue(), "GBK"));
    // } catch (UnsupportedEncodingException e) {
    // e.printStackTrace();
    // }
    return super.translator(record);
}

}

幾點說明:

  1. DataTranslator目前僅支持java擴展,允許用戶完成類實現後,將類源文件放置到conf/translator/目錄下,yugong啓動後會進行動態編譯.
  2. DataTranslator目前查找規則會根據表名自動查找,比如需要處理的表爲otter2.test_all_one_pk,查找的時候會將test_all_one_pk轉化爲TestAllOnePk + 固定DataTranslator後綴. (如果當前classpath中存在,優先使用classpath,如果不存在,則到conf/translator中查找該名字的java文件進行動態編譯)
  3. 目前提供了幾個樣例,可參見解壓後的conf/translator/目錄
    a. YugongExampleOracleDataTranslator  (當前例子,介紹oracle一張表和mysql一張表之間的轉換處理)
    b. YugongExampleJoinDataTranslator  (介紹oracle多張表和mysql一張表之間的轉換處理,oracle中會通過一張表爲主表,運行時join查詢出其他表數據,合併同步到mysql)
    c. YugongExampleTwoDataTranslator (介紹oracle一張表和mysql多張表之間的轉換處理,oracle的一張大表數據,可運行時拆分後輸出到多張mysql表上)

運行模式詳細介紹

MARK模式(MARK)

開啓增量日誌的記錄,如果是oracle就是創建物化視圖

CLEAR模式(CLEAR)

清理增量日誌的記錄,如果是oracle就是刪除物化視圖

全量模式(FULL)

全量模式,顧名思議即爲對源表進行一次全量操作,遍歷源表所有的數據後,插入目標表.
全量有兩種處理方式:

  1. 分頁處理:如果源表存在主鍵,只有一個主鍵字段,並且主鍵字段類型爲Number類型,默認會選擇該分頁處理模式. 優點:支持斷點續做,對源庫壓力相對較小。 缺點:遷移速度慢
  2. once處理:通過select * from訪問整個源表的某一個mvcc版本的數據,通過cursor.next遍歷整個結果集. 優點:遷移速度快,爲分頁處理的5倍左右。 缺點:源庫壓力大,如果源庫併發修改量大,會導致數據庫MVCC版本過多,出現棧錯誤. 還有就是不支持斷點續做.

 特別注意
如果全量模式運行過程中,源庫有變化時,不能保證源庫最近變化的數據能同步到目標表,這時需要配合增量模式. 具體操作就是:在運行全量模式之前,先開啓增量模式的記錄日誌功能,然後開啓全量模式,完成後,再將最近變化的數據通過增量模式同步到目標表。

增量模式(INC)

全量模式,顧名思議即爲對源表增量變化的數據插入目標表,增量模式依賴記錄日誌功能.
目前增量模式的記錄日誌功能,是通過oracle的物化視圖功能。

 創建物化視圖

CREATE MATERIALIZED VIEW LOG ON ${tableName} with primary key.

 

  • 運行增量模式之前,需要先開啓記錄日誌的功能,即預先創建物化視圖. 特別是配合全量模式時,創建物化視圖的時間點要早於運行全量之前,這樣纔可以保證數據能全部同步到目標表
  • 增量模式沒有完成的概念,它只有追上的概念,具體的停止需有業務進行判斷,可以看一下切換流程

自動模式(ALL)

自動模式,是對全量+增量模式的一種組合,自動化運行,減少操作成本.
自動模式的內部實現步驟:

  1. 開啓記錄日誌功能. (創建物化視圖)
  2. 運行全量同步模式. (全量完成後,自動進入下一步)
  3. 運行增量同步模式. (增量模式,沒有完成的概念,所以也就不會自動退出,需要業務判斷是否可以退出,可以看一下切換流程)

對比模式(CHECK)

對比模式,即爲對源庫和目標庫的數據進行一次全量對比,驗證一下遷移結果. 對比模式爲一種可選運行,做完全量/增量/自動模式後,可選擇性的運行對比模式,來確保本次遷移的正確性.

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章