DataX离线数据同步

1. DataX

数据同步的工具有很多,比如Hadoop和结构化数据存储之间高效批量数据传输的工具Apache Sqoop,借助于 Hadoop集群可以并行的高效传输数据,但是这种方式往往需要依赖于一个Hadoop环境,在生产环境有时我们并没有直接的权限操作这个环境,而是只提供一个HDFS的端口,这时用Sqoop就不是很方便。Oracle数据和MySQL数据的同步工具会想到alibaba / yugong,基于MySQL binlog增量订阅和消费中间件使用起来非常方便,同时也执行消息队里模式(Apache KafkaApache RockMQ),但这个主要针对于特定场景和业务下。

DataX是阿里巴巴集团内被广泛使用的离线数据同步工具or平台,它支持MySQL、Oracle、SQLServer、PostgreSQL、HDFS、Hive、HBase、MaxCompute(ODPS)、MongoDB、Elasticsearch等各种异构数据源之间的高效的数据同步。Reader和Writer支持的列表可以访问文档Support Data Channels
DataX 概览

使用起来也是非常方便,只需要下载datax.tar.gz压缩包,解压之后就可以使用,不需要设置任何依赖,放置到任何一个开通了数据源和目标端端口权限的节点,然后定义一个JSON文件,在JSON文件中定义Reader和Writer,就可以在本地以多线程并发高效的进行数据之间的同步功能。
DataX核心架构

  • 执行一次数据同步作业称为一个Job,DataX接受到这个Job之后,开始启动一个进程来完成这个Job的同步过程;
  • 这个进程会根据不同的源端切分策略,将Job进行切分为多个小的Task,Task就是DataX作业的最小单元,每个Task都负责一部分数据的同步工作,这些Task是并发执行的;
  • 切分完数据之后,DataX Job会调用Scheduler模块,根据配置的并发数量,将拆分的Task重新组合,组装为TaskGroup,每一个TaskGroup负责以一定的并发执行Task,默认单个TaskGroup的并发数为5;
  • Task启动后会固定启动Reader -> Channel -> Writer的线程来完成任务同步工作;
  • Task运行时,Job开始监控并等待各个TaskGroup模块任务完成,等所有TaskGroup成功完成后Job进程才退出,否则异常退出。

例子:比如现在有1个100张分表,需要将数据从MySQL同步到odps,在json中设置了20个并发,DataX的调度决策如下:

  • DataX Job将表拆分为100个Task;
  • 由20个并发,可以计算出需要4个TaskGroup(一个TaskGroup运行5个Task);
  • 将100个任务平均分配个4个TaskGroup,也就是说每个TaskGroup会负责5个并发运行25个Task。

2. ODPS同步数据到HDFS

ODPS现在已经更名为MaxCompute,它是一种大数据计算服务,一个快速、完全托管的TB/PB级数据仓库解决方案,具体可以查看官方文档MaxCompute

在content中的reader处定义一个odpsreader,writer定义为hdfswriter。这里需要注意的是HdfsWriter插件目前只支持ORC和TEXT,而 HdfsReader插件目前支持ORC、 TEXT、CSV、SEQUENCE、RC

如果我们在写入HDFS时文件类型只有两个选择,要么write的文件类型是TEXT,要么是ORC格式,如果想要对数据进行压缩可以选择ORC格式文件,这个确实能够对数据进行非常有效的压缩(一个原本165MB的文件,压缩后约为20MB),在数据量较大时能很有效的节省空间,在Hive建表时指定文件存储格式STORED AS orc即可高效地使用数据,但是比较尴尬的是如果使用的是CDH平台上的Impala来操作Hive的数据,在Cloudera Enterprise 6.0.x是不支持ORC格式的,不过在随后的Cloudera Enterprise 6.1.x支持了ORC格式,有这方面业务的需要考虑下这种特殊情况。

注意:如果reader是ODPS,字段信息的定义顺序没有限制,但尽量和writer中定义的字段信息的顺序一致,或者writer中定义字段信息时要和reader处的顺序保持一致。字段名不要包含空字符,否则DataX验证类型时会报错。

{
  "job": {
    "setting": {
      "speed": {
        "channel": "3"
      }
    },
    "content": [
      {
        "reader": {
          "name": "odpsreader",
          "parameter": {
            "accessId": "3oL**********BDZ",
            "accessKey": "Myk********************WY9UTly",
            "project": "targetProjectName",
            "table": "tableName",
            "column": [
              "*"
            ],
            "partition": [
              "pt=20141010000000,year=2014"
            ],
            "odpsServer": "http://xxx/api",
            "tunnelServer": "http://xxx",
            "splitMode": "record"
          }
        },
        "writer": {
          "name": "hdfswriter",
          "parameter": {
            "defaultFS": "hdfs://cdh1:8020",
            "fileType": "TEXT",
            "path": "/user/hive/warehouse/kudu_test.db/dataxtype_test",
            "fileName": "xxxx",
            "writeMode": "append",
            "fieldDelimiter": "?",
            "column": [
              {
                "name": "f1",
                "type": "BIGINT"
              },
              {
                "name": "f2",
                "type": "STRING"
              },
              {
                "name": "f3",
                "type": "BOOLEAN"
              },
              {
                "name": "f4",
                "type": "DOUBLE"
              },
              {
                "name": "f5",
                "type": "FLOAT"
              },
              {
                "name": " f6",
                "type": "TIMESTAMP"
              }
            ]
          }
        }
      }
    ]
  }
}

注意:在writer中的column一定要对读取的每个字段定义字段名和字段类型。关于分隔符,可以使用一些非常特殊的单字符,比如输入法中提供的特殊字符(最好测试一下,有些虽然是单字符但也不支持),如果想使用多字符作为分隔符,可以查看我的另一篇blog Hive中的自定义分隔符

在writer中会定义pathfileName,这里可能有些人会有个疑问,就是为什么定义fileName,这个文件名并不是严格的文件名,只是文件名的一个前缀标识,多个并行时会生成fileName__随机字符串的文件。


3. HDFS同步数据到另一个HDFS

将下面json保存为 xxx.json,然后执行 $DATAX_HOME/bin/datax.py xxx.json
注意:reader定义字段类型时一定要和HDFS上的文件的列的顺序一致(也就是建表时字段的顺序),writer时和reader列顺序一致。

{
  "job": {
    "setting": {
      "speed": {
        "channel": 1
      }
    },
    "content": [
      {
        "reader": {
          "name": "hdfsreader",
          "parameter": {
            "path": "/user/hive/warehouse/hive_test.db/dataxtype_test/*",
            "defaultFS": "hdfs://one-hdfs:8020",
            "fileType": "text",
            "encoding": "UTF-8",
            "fieldDelimiter": "|",
            "column": [
              {
                "type": "Long",
                "index": "0"
              },
              {
                "type": "String",
                "index": "1"
              },
              {
                "type": "Boolean",
                "index": "2"
              },
              {
                "type": "Double",
                "index": "3"
              },
              {
                "type": "Double",
                "index": "4"
              },
              {
                "type": "Date",
                "index": "5"
              }
            ]
          }
        },
        "writer": {
          "name": "hdfswriter",
          "parameter": {
            "defaultFS": "hdfs://cdh1:8020",
            "fileType": "TEXT",
            "path": "/user/hive/warehouse/kudu_test.db/dataxtype_test",
            "fileName": "xxxx",
            "writeMode": "append",
            "fieldDelimiter": "?",
            "column": [
              {
                "name": "f1",
                "type": "BIGINT"
              },
              {
                "name": "f2",
                "type": "STRING"
              },
              {
                "name": "f3",
                "type": "BOOLEAN"
              },
              {
                "name": "f4",
                "type": "DOUBLE"
              },
			  {
                "name": "f5",
                "type": "FLOAT"
              },
              {
                "name": " f6",
                "type": "TIMESTAMP"
              }
            ]
          }
        }
      }
    ]
  }
}

4. MongoDB同步数据到HDFS

将下面json保存为 xxx.json,然后执行 $DATAX_HOME/bin/datax.py xxx.json。如果测试数据可以先导到本地"defaultFS": "file:///",如果格式没问题再改为"defaultFS": "hdfs://bigdata001:8020",。或者因为端口问题只能通过某个服务上传,可以直接将远程连接读入MongoDB的数据通过FTP方式发送到指定服务上,这里只需将hdfswriter改为ftpwriter

{
  "job": {
    "setting": {
      "speed": {
        "channel": "3"
      }
    },
    "content": [
      {
        "reader": {
          "name": "mongodbreader",
          "parameter": {
            "address": [
              "xx.xxx.x.xx:27017"
            ],
            "userName": "",
            "userPassword": "",
            "dbName": "tag_per_data",
            "collectionName": "tag_data12",
            "column": [
              {
                "name": "_id",
                "type": "string"
              },
              {
                "name": "r_cert_no",
                "type": "string"
              },
              {
                "name": "r_name",
                "type": "string"
              },
              {
                "name": "b_cert_no",
                "type": "string"
              },
              {
                "name": "b_name",
                "type": "string"
              },
              {
                "name": "r_flag",
                "type": "string"
              },
              {
                "name": "body_md5",
                "type": "Array",
                "spliter": ""
              }
            ]
          }
        },
        "writer": {
          "name": "hdfswriter",
          "parameter": {
            "defaultFS": "file:///",
            "fieldDelimiter": "╬",
            "fileName": "m_cpws_info_w3",
            "fileType": "orc",
            "path": "/root/mongo_data/m_cpws_info_w3",
            "writeMode": "append",
            "column": [
              {
                "name": "_id",
                "type": "string"
              },
              {
                "name": "r_cert_no",
                "type": "string"
              },
              {
                "name": "r_name",
                "type": "string"
              },
              {
                "name": "b_cert_no",
                "type": "string"
              },
              {
                "name": "b_name",
                "type": "string"
              },
              {
                "name": "r_flag",
                "type": "string"
              },
              {
                "name": "body_md5",
                "type": "string"
              }
            ]
          }
        }
      }
    ]
  }
}

Info:但在MongoDB右密码时,用但在MongoDB右密码时,用$MONGO_HOME/bin/mongo --host xx.xxx.x.xx --port 27017 -u "用户名" -p "密码" --authenticationDatabase "admin"可以正常访问给定的库,但是在上述mongodbreader中配置上用户名和免密依然没有权限访问。

这是可以临时这样迁移数据:

# 登陆远程MongoDB
$MONGO_HOME/bin/mongo --host xx.xxx.x.xx --port 27017 -u "用户名" -p "密码"  --authenticationDatabase "admin"
# 切换到给定库下
use 库名
# 查看表字段信息,不显示 details 字段值
db.getCollection("表名").find({},{details: 0}).limit(1)

然后用MongoDB自带的数据导出工具mongoexport导出数据为csv文件

$MONGO_HOME/bin/mongoexport --host xx.xxx.x.xx --port 27017 \
-d 库名 -c 表名 -u "用户名" -p "密码"  --authenticationDatabase "admin"  \
-o ./data/表名.csv --type csv \
-f "_id,field_01,field_02,field_03,……"

也许这个数据文件非常大,可以对这个文件进行切分,使用Linux的sed命令。

#每100万条数据切分为一个文件
sed -n '1,1000000'p axd_tao_ord.csv >> axd_tao_ord_0000001-1000000.csv
sed -n '1000001,2000000'p axd_tao_ord.csv >> axd_tao_ord_1000001-2000000.csv
sed -n '2000001,3000000'p axd_tao_ord.csv >> axd_tao_ord_2000001-3000000.csv
……

# 这里也可以使用split命令
split -l 1000000  axd_tao_ord.csv axd_tao_ord_
发布了40 篇原创文章 · 获赞 97 · 访问量 15万+

猜你喜欢

转载自blog.csdn.net/github_39577257/article/details/100077668