datax避坑记录

先介绍一下datax,dataX 是阿里云 DataWorks数据集成 的开源版本,在阿里巴巴集团内被广泛使用的离线数据同步工具/平台。DataX 实现了包括 MySQL、Oracle、OceanBase、SqlServer、Postgre、HDFS、Hive、ADS、HBase、TableStore(OTS)、MaxCompute(ODPS)、Hologres、DRDS 等各种异构数据源之间高效的数据同步功能。

具体的使用方法其实官方的文档写得挺详细的,我就不做多余的重复了,这篇文章主要是写我使用datax时遇到的坑,就拿我之前用datax做mysql数据库的迁移做例子,另,附上官方地址:https://github.com/alibaba/DataX

插件名称对应

reader和writer必须对应自己要进行数据同步的对象,比如要进行同步的是mysql数据库,那么job文件中reader和writer对应的name就必须配置为mysqlreader和mysqlwriter。这是一个小细节,因为datax的例子中写的是streamreader和streamwriter,如果复制过来,写job文件的时候忘记改,有时候也会花费些时间去找问题。

1000行限制

了解datax的都知道,用datax时,需要我们自己配置job文件,如下:

{
  "job": {
    "setting": {
      "speed": {
        "channel": 3,
        "byte": 1048576
      },
      "errorLimit": {
        "record": 0,
        "percentage": 0.02
      }
    },
    "content": [
      {
        "reader": {
          "name": "mysqlreader",
          "parameter": {
            "username": "yRjwDFuoPKlqya9h9H2Amg==",
            "password": "6YrK4y3NaUxccEgnoAz8yA==",
            "column": [
              "id",
              "name",
              "age",
              "add_time"
            ],
            "where": "add_time >= ${startTime} and add_time < ${endtTime}",
            "splitPk": "",
            "connection": [
              {
                "table": [
                  "student"
                ],
                "jdbcUrl": [
                  "jdbc:mysql://127.0.0.1:3306/mytest?serverTimezone=Asia/Shanghai&useLegacyDatetimeCode=false&useSSL=false&nullNamePatternMatchesAll=true&useUnicode=true"
                ]
              }
            ]
          }
        },
        "writer": {
          "name": "mysqlwriter",
          "parameter": {
            "username": "yRjwDFuoPKlqya9h9H2Amg==",
            "password": "6YrK4y3NaUxccEgnoAz8yA==",
            "writeMode": "insert",
            "column": [
              "id",
              "name",
              "age",
              "add_time"
            ],
            "connection": [
              {
                "table": [
                  "student"
                ],
                "jdbcUrl": "jdbc:mysql://127.0.0.1:3306/datax_test?serverTimezone=Asia/Shanghai&useLegacyDatetimeCode=false&useSSL=false&nullNamePatternMatchesAll=true&useUnicode=true"
              }
            ]
          }
        }
      }
    ]
  }
}

但是有可能会遇到明明有上万的数据,却只能读取到一千条,为啥呢,有可能是数据库默认限制了一次只能抽取1000条,这个时候可以使用querySql,通过limit解决。

{
  "job": {
    "setting": {
      "speed": {
        "channel": 3,
        "byte": 1048576
      },
      "errorLimit": {
        "record": 0,
        "percentage": 0.02
      }
    },
    "content": [
      {
        "reader": {
          "name": "mysqlreader",
          "parameter": {
            "username": "yRjwDFuoPKlqya9h9H2Amg==",
            "password": "6YrK4y3NaUxccEgnoAz8yA==",
            "column": [
              "id",
              "name",
              "age",
              "add_time"
            ],
            "splitPk": "",
            "connection": [
              {
                "querySql":"select * from student limit 0,100000",
                "jdbcUrl": [
                  "jdbc:mysql://127.0.0.1:3306/mytest?serverTimezone=Asia/Shanghai&useLegacyDatetimeCode=false&useSSL=false&nullNamePatternMatchesAll=true&useUnicode=true"
                ]
              }
            ]
          }
        },
        "writer": {
          "name": "mysqlwriter",
          "parameter": {
            "username": "yRjwDFuoPKlqya9h9H2Amg==",
            "password": "6YrK4y3NaUxccEgnoAz8yA==",
            "writeMode": "insert",
            "column": [
              "id",
              "name",
              "age",
              "add_time"
            ],
            "connection": [
              {
                "table": [
                  "student"
                ],
                "jdbcUrl": "jdbc:mysql://127.0.0.1:3306/datax_test?serverTimezone=Asia/Shanghai&useLegacyDatetimeCode=false&useSSL=false&nullNamePatternMatchesAll=true&useUnicode=true"
              }
            ]
          }
        }
      }
    ]
  }
}

这样,可以一次性可以查询出100000条数据了,因为我是导全表数据,所以where条件也不需要。

批量执行

因为是数据库迁移,一般来说有个几百张表都是基本操作,如果我执行一个表的迁移就要去改一下job文件中的表名岂不是很麻烦吗,所以我去留意了一下datax的配置,发现table的配置是用的[],那感觉这里面应该是支持多表的。

DataX和sqoop和flume_mysql

emmm。。。那如果schema结构不一样怎么办,本来我要做的就是把这部分数据迁移到另一个数据库里。所以这里是有点麻烦,但是也不是没有办法解决,这里可以通过一个sh脚本去解决。

首先job文件需要调整一下,表名这些就不能固定死,要通过参数传递进来。因为我可以确定表的字段结构这些都是能一一对应的,column配置我就直接使用的*。

{
  "job": {
    "setting": {
      "speed": {
        "channel": 3,
        "byte": 1048576
      },
      "errorLimit": {
        "record": 0,
        "percentage": 0.02
      }
    },
    "content": [
      {
        "reader": {
          "name": "mysqlreader",
          "parameter": {
            "username": "yRjwDFuoPKlqya9h9H2Amg==",
            "password": "6YrK4y3NaUxccEgnoAz8yA==",
            "column": ["*"],
            "splitPk": "",
            "connection": [
              {
                "querySql":"select * from ${source_table_name} limit 0,100000",
                "jdbcUrl": [
                  "${source_db}"
                ]
              }
            ]
          }
        },
        "writer": {
          "name": "mysqlwriter",
          "parameter": {
            "username": "yRjwDFuoPKlqya9h9H2Amg==",
            "password": "6YrK4y3NaUxccEgnoAz8yA==",
            "writeMode": "insert",
            "column": ["*"],
            "connection": [
              {
                "table": [
                  "${target_table_name}"
                ],
                "jdbcUrl": "${target_db}"
              }
            ]
          }
        }
      }
    ]
  }
}

说明一下sh脚本,我的datax安装目录:/data/lxf/datax,我写的job文件名为datasync.json,就放在datax的job目录下,tables.txt是我存放所有需要导的表名的文件,为了方便我也同样放在datax的job目录下,且两个数据库需要迁移的表的表名都是一样的。所以,最终sh脚本如下:

table_list='/data/lxf/datax/job/tables.txt'
exec_path='/data/lxf/datax/bin/datax.py'
source_db='jdbc:mysql://127.0.0.1:3306/mytest?serverTimezone=Asia/Shanghai&useLegacyDatetimeCode=false&useSSL=false&nullNamePatternMatchesAll=true&useUnicode=true'
target_db='jdbc:mysql://127.0.0.1:3306/datax_test?serverTimezone=Asia/Shanghai&useLegacyDatetimeCode=false&useSSL=false&nullNamePatternMatchesAll=true&useUnicode=true'
for table_name in cat $table_list
do
	python $exec_path -p "-Dsource_table_name=$table_name -Dtarget_table_name=$table_name -Dsource_db=$source_db -Dtarget_db=$target_db" /data/lxf/datax/job/datasync.json
done

tables.txt的内容如下,有多少表写多少就行,一个表名一行:

student
user_info
role_info

以上就是我第一次使用datax遇到的一些坑,也用自己的办法解决了,希望对大家有用。