数据源管理 | 基于DataX组件,同步数据和源码分析
本文源码:GitHub·点这里 || GitEE·点这里
一、DataX工具简介
1、设计理念
DataX是一个异构数据源离线同步工具,致力于实现包括关系型数据库(MySQL、Oracle等)、HDFS、Hive、ODPS、HBase、FTP等各种异构数据源之间稳定高效的数据同步功能。解决异构数据源同步问题,DataX将复杂的网状的同步链路变成了星型数据链路,DataX作为中间传输载体负责连接各种数据源。当需要接入一个新的数据源的时候,只需要将此数据源对接到DataX,便能跟已有的数据源做到无缝数据同步。

絮叨一句:异构数据源指,为了处理不同种类的业务,使用不同的数据库系统存储数据。
2、组件结构
DataX本身作为离线数据同步框架,采用Framework+plugin架构构建。将数据源读取和写入抽象成为Reader和Writer插件,纳入到整个同步框架中。

- Reader
Reader为数据采集模块,负责读取采集数据源的数据,将数据发送给Framework。
- Writer
Writer为数据写入模块,负责不断向Framework取数据,并将数据写入到目的端。
- Framework
Framework用于连接reader和writer,作为两者的数据传输通道,并处理缓冲,流控,并发,数据转换等核心技术问题。
3、架构设计

- Job
DataX完成单个数据同步的作业,称为Job,DataX接受到一个Job之后,将启动一个进程来完成整个作业同步过程。Job模块是单个作业的中枢管理节点,承担了数据清理、子任务切分(将单一作业计算转化为多个子Task)、TaskGroup管理等功能。
- Split
DataXJob启动后,会根据不同的源端切分策略,将Job切分成多个小的Task(子任务),以便于并发执行。Task便是DataX作业的最小单元,每一个Task都会负责一部分数据的同步工作。
- Scheduler
切分多个Task之后,Job会调用Scheduler模块,根据配置的并发数据量,将拆分成的Task重新组合,组装成TaskGroup(任务组)。
- TaskGroup
每一个TaskGroup负责以一定的并发运行完毕分配好的所有Task,默认单个任务组的并发数量为5。每一个Task都由TaskGroup负责启动,Task启动后,会固定启动Reader—>Channel—>Writer的线程来完成任务同步工作。DataX作业运行起来之后,Job监控并等待多个TaskGroup模块任务完成,等待所有TaskGroup任务完成后Job成功退出。否则,异常退出,进程退出值非0。
二、环境安装
推荐Python2.6+,Jdk1.8+(脑补安装流程)。
1、Python包下载
# yum -y install wget
# wget https://www.python.org/ftp/python/2.7.15/Python-2.7.15.tgz
# tar -zxvf Python-2.7.15.tgz
2、安装Python
# yum install gcc openssl-devel bzip2-devel
[root@ctvm01 Python-2.7.15]# ./configure --enable-optimizations
# make altinstall
# python -V
3、DataX安装
# pwd
/opt/module
# ll
datax
# cd /opt/module/datax/bin
-- 测试环境是否正确
# python datax.py /opt/module/datax/job/job.json
三、同步任务
1、同步表创建
-- PostgreSQL
CREATE TABLE sync_user (
id INT NOT NULL,
user_name VARCHAR (32) NOT NULL,
user_age int4 NOT NULL,
CONSTRAINT "sync_user_pkey" PRIMARY KEY ("id")
);
CREATE TABLE data_user (
id INT NOT NULL,
user_name VARCHAR (32) NOT NULL,
user_age int4 NOT NULL,
CONSTRAINT "sync_user_pkey" PRIMARY KEY ("id")
);
2、编写任务脚本
[root@ctvm01 job]# pwd
/opt/module/datax/job
[root@ctvm01 job]# vim postgresql_job.json
3、脚本内容
{
"job": {
"setting": {
"speed": {
"channel": "3"
}
},
"content": [
{
"reader": {
"name": "postgresqlreader",
"parameter": {
"username": "root01",
"password": "123456",
"column": ["id","user_name","user_age"],
"connection": [
{
"jdbcUrl": ["jdbc:postgresql://192.168.72.131:5432/db_01"],
"table": ["data_user"]
}
]
}
},
"writer": {
"name": "postgresqlwriter",
"parameter": {
"username": "root01",
"password": "123456",
"column": ["id","user_name","user_age"],
"connection": [
{
"jdbcUrl": "jdbc:postgresql://192.168.72.131:5432/db_01",
"table": ["sync_user"]
}
],
"postSql": [],
"preSql": []
}
}
}
]
}
}
4、执行脚本
# /opt/module/datax/bin/datax.py /opt/module/datax/job/postgresql_job.json
5、执行日志
2020-04-23 18:25:33.404 [job-0] INFO JobContainer -
任务启动时刻 : 2020-04-23 18:25:22
任务结束时刻 : 2020-04-23 18:25:33
任务总计耗时 : 10s
任务平均流量 : 1B/s
记录写入速度 : 0rec/s
读出记录总数 : 2
读写失败总数 : 0
四、源码流程分析
注意:这里源码只贴出核心流程,如果要看完整源码,可以自行从Git上下载。
1、读取数据
核心入口:PostgresqlReader
启动读任务
public static class Task extends Reader.Task {
@Override
public void startRead(RecordSender recordSender) {
int fetchSize = this.readerSliceConfig.getInt(com.alibaba.datax.plugin.rdbms.reader.Constant.FETCH_SIZE);
this.commonRdbmsReaderSlave.startRead(this.readerSliceConfig, recordSender,
super.getTaskPluginCollector(), fetchSize);
}
}
读取任务启动之后,执行读取数据操作。
核心类:CommonRdbmsReader
public void startRead(Configuration readerSliceConfig,
RecordSender recordSender,
TaskPluginCollector taskPluginCollector, int fetchSize) {
ResultSet rs = null;
try {
// 数据读取
rs = DBUtil.query(conn, querySql, fetchSize);
queryPerfRecord.end();
ResultSetMetaData metaData = rs.getMetaData();
columnNumber = metaData.getColumnCount();
PerfRecord allResultPerfRecord = new PerfRecord(taskGroupId, taskId, PerfRecord.PHASE.RESULT_NEXT_ALL);
allResultPerfRecord.start();
long rsNextUsedTime = 0;
long lastTime = System.nanoTime();
// 数据传输至交换区
while (rs.next()) {
rsNextUsedTime += (System.nanoTime() - lastTime);
this.transportOneRecord(recordSender, rs,metaData, columnNumber, mandatoryEncoding, taskPluginCollector);
lastTime = System.nanoTime();
}
allResultPerfRecord.end(rsNextUsedTime);
}catch (Exception e) {
throw RdbmsException.asQueryException(this.dataBaseType, e, querySql, table, username);
} finally {
DBUtil.closeDBResources(null, conn);
}
}
2、数据传输
核心接口:RecordSender(发送)
public interface RecordSender {
public Record createRecord();
public void sendToWriter(Record record);
public void flush();
public void terminate();
public void shutdown();
}
核心接口:RecordReceiver(接收)
public interface RecordReceiver {
public Record getFromReader();
public void shutdown();
}
核心类:BufferedRecordExchanger
class BufferedRecordExchanger implements RecordSender, RecordReceiver
3、写入数据
核心入口:PostgresqlWriter
启动写任务
public static class Task extends Writer.Task {
public void startWrite(RecordReceiver recordReceiver) {
this.commonRdbmsWriterSlave.startWrite(recordReceiver, this.writerSliceConfig, super.getTaskPluginCollector());
}
}
写数据任务启动之后,执行数据写入操作。
核心类:CommonRdbmsWriter
public void startWriteWithConnection(RecordReceiver recordReceiver,
Connection connection) {
// 写数据库的SQL语句
calcWriteRecordSql();
List<Record> writeBuffer = new ArrayList<>(this.batchSize);
int bufferBytes = 0;
try {
Record record;
while ((record = recordReceiver.getFromReader()) != null) {
writeBuffer.add(record);
bufferBytes += record.getMemorySize();
if (writeBuffer.size() >= batchSize || bufferBytes >= batchByteSize) {
doBatchInsert(connection, writeBuffer);
writeBuffer.clear();
bufferBytes = 0;
}
}
if (!writeBuffer.isEmpty()) {
doBatchInsert(connection, writeBuffer);
writeBuffer.clear();
bufferBytes = 0;
}
} catch (Exception e) {
throw DataXException.asDataXException(
DBUtilErrorCode.WRITE_DATA_ERROR, e);
} finally {
writeBuffer.clear();
bufferBytes = 0;
DBUtil.closeDBResources(null, null, connection);
}
}
五、源代码地址
GitHub·地址
https://github.com/cicadasmile/data-manage-parent
GitEE·地址
https://gitee.com/cicadasmile/data-manage-parent

推荐系列阅读
数据源管理 | 基于DataX组件,同步数据和源码分析的更多相关文章
- Quartz学习--二 Hello Quartz! 和源码分析
Quartz学习--二 Hello Quartz! 和源码分析 三. Hello Quartz! 我会跟着 第一章 6.2 的图来 进行同步代码编写 简单入门示例: 创建一个新的java普通工程 ...
- Java并发编程(七)ConcurrentLinkedQueue的实现原理和源码分析
相关文章 Java并发编程(一)线程定义.状态和属性 Java并发编程(二)同步 Java并发编程(三)volatile域 Java并发编程(四)Java内存模型 Java并发编程(五)Concurr ...
- Okhttp同步请求源码分析
进阶android,OKhttp源码分析——同步请求的源码分析 OKhttp是我们经常用到的框架,作为开发者们,我们不单单要学会灵活使用,还要知道他的源码是如何设计的. 今天我们来分析一下OKhttp ...
- Android Debuggerd 简要介绍和源码分析(转载)
转载: http://dylangao.com/2014/05/16/android-debuggerd-%E7%AE%80%E8%A6%81%E4%BB%8B%E7%BB%8D%E5%92%8C%E ...
- Kubernetes Job Controller 原理和源码分析(一)
概述什么是 JobJob 入门示例Job 的 specPod Template并发问题其他属性 概述 Job 是主要的 Kubernetes 原生 Workload 资源之一,是在 Kubernete ...
- Kubernetes Job Controller 原理和源码分析(二)
概述程序入口Job controller 的创建Controller 对象NewController()podControlEventHandlerJob AddFunc DeleteFuncJob ...
- Kubernetes Job Controller 原理和源码分析(三)
概述Job controller 的启动processNextWorkItem()核心调谐逻辑入口 - syncJob()Pod 数量管理 - manageJob()小结 概述 源码版本:kubern ...
- OLAP引擎:基于Druid组件进行数据统计分析
一.Druid概述 1.Druid简介 Druid是一款基于分布式架构的OLAP引擎,支持数据写入.低延时.高性能的数据分析,具有优秀的数据聚合能力与实时查询能力.在大数据分析.实时计算.监控等领域都 ...
- 数据源管理 | 基于JDBC模式,适配和管理动态数据源
本文源码:GitHub·点这里 || GitEE·点这里 一.关系型数据源 1.动态数据源 动态管理数据源的基本功能:数据源加载,容器维护,持久化管理. 2.关系型数据库 不同厂商的关系型数据库,提供 ...
随机推荐
- Python爬虫 ---scrapy框架初探及实战
目录 Scrapy框架安装 操作环境介绍 安装scrapy框架(linux系统下) 检测安装是否成功 Scrapy框架爬取原理 Scrapy框架的主体结构分为五个部分: 它还有两个可以自定义下载功能的 ...
- Spring(DI,AOP) 理解(一)
感觉自己的spring理解的不好.所以重新开始学习. 这篇文章主要是来理解DI(依赖注入),Aop(切面) 一.DI(依赖注入,这里没有涉及到注释.只是用xml文件和Bean的方法来注册pojo,) ...
- 项目中你不得不知的11个Java第三方类库
项目中你不得不知的11个Java第三方类库 博客分类: Java综合 JavaGoogle框架单元测试Hibernate Java第三方library ecosystem是一个很广阔的范畴.不久前有人 ...
- CSS3 制作正方体
一.预备知识 变形属性 2D变形属性 transform:他是css3中的变形属性: 通过transform(变形) 来实现2d 或者3d 转换,其中2d 有,缩放 scale(x, y) ,移动 t ...
- [算法总结]DFS(深度优先搜索)
目录 一.关于DFS 1. 什么是DFS 2. DFS的搜索方式 二.DFS的具体实现 三.剪枝 1. 顺序性剪枝 2. 重复性剪枝 3. 可行性剪枝 4. 最优性剪枝 5. 记忆化剪枝 四.练习 一 ...
- Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(五)之Controlling Execution
In Java, the keywords include if-else,while,do-while,for,return,break, and a selection statement cal ...
- threejs创建地球
上个月底,在朋友圈看到一个号称“这可能是地球上最美的h5”的分享,点进入后发现这个h5还很别致,思考了一会,决定要不高仿一个? 到今天为止,高仿基本完成, 线上地址 github地址 除了手机端的me ...
- C# windows服务没有RunInstallerAttribute.Yes的公共安装程序
1.在视图状态 右键添加ServiceInstaller及ServiceProcessInstaller两个控件; 2.将serviceProcessInstaller类的Account属性改为 Lo ...
- L12 Transformer
Transformer 在之前的章节中,我们已经介绍了主流的神经网络架构如卷积神经网络(CNNs)和循环神经网络(RNNs).让我们进行一些回顾: CNNs 易于并行化,却不适合捕捉变长序列内的依赖关 ...
- golang slice 源码解读
本文从源码角度学习 golang slice 的创建.扩容,深拷贝的实现. 内部数据结构 slice 仅有三个字段,其中array 是保存数据的部分,len 字段为长度,cap 为容量. type s ...