Alibaba Otter实现扩展导入nosql DB和其它DB

本文介绍如何扩展 Alibaba Otter 和 Canal 工具,使其能够支持多种 NoSQL 数据库,如 HBase、Cassandra 等,实现从 MySQL binlog 近实时同步数据到这些目标数据库。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简介:

       Alibaba Otter和Canal是抽取mysqlbinlog的工具,可以在不修改任何业务程序的情况下,以极小的网络IO代价抽取业务数据库的数据到离线分析数据库,在网络状况良好的情况下,可以实现延时小于1s的近实时数据同步。但是他仅仅支持同步到mysql,oracle数据库,实际离线分析中,往往需要数据导入到Kafka,HBase,Cassandra,GreenPlum,ElasticSearch等数据库中,公司有这个需求,因而花了几个礼拜扩展开发了Otter,主要步骤如下:

1、修改Manager端,使管理界面支持nosql DB的数据源和表,字段映射的配置;

1.1 数据库类型扩展定义:

com.alibaba.otter.shared.common.model.config.data.DataMediaType

public enum DataMediaType {
	GREENPLUM,
    /** mysql DB */
    MYSQL,
    /** oracle DB */
    ORACLE,
    /** elsaticsearch  */
    ELASTICSEARCH,
    /** KAFKA DB */
    KAFKA,
    /** HBASE DB */
    HBASE,
    /** CASSANDRA DB */
    CASSANDRA,
    /** HDFS-ARVO DB */
    HDFS_ARVO,
    /** cobar */
    COBAR,
    /** tddl */
    TDDL,
    /** cache */
    MEMCACHE,
    /** mq */
    MQ,
    /** napoli */
    NAPOLI,
    /** diamond push for us */
    DIAMOND_PUSH;

    public boolean isKafka() {
        return this.equals(DataMediaType.KAFKA);
    }

    public boolean isElasticSearch() {
        return this.equals(DataMediaType.ELASTICSEARCH);
    }
    
    public boolean isHBase() {
        return this.equals(DataMediaType.HBASE);
    }

    public boolean isCassandra() {
        return this.equals(DataMediaType.CASSANDRA);
    }
    public boolean isHDFSArvo() {
        return this.equals(DataMediaType.HDFS_ARVO);
    }

    public boolean isOracle() {
        return this.equals(DataMediaType.ORACLE);
    }
    public boolean isMysql() {
        return this.equals(DataMediaType.MYSQL);
    }


    public boolean isTddl() {
        return this.equals(DataMediaType.TDDL);
    }

    public boolean isCobar() {
        return this.equals(DataMediaType.COBAR);
    }

    public boolean isMemcache() {
        return this.equals(DataMediaType.MEMCACHE);
    }

    public boolean isMq() {
        return this.equals(DataMediaType.MQ);
    }
    
    public boolean isGreenPlum() {
        return this.equals(DataMediaType.GREENPLUM);
    }

    public boolean isNapoli() {
        return this.equals(DataMediaType.NAPOLI);
    }

    public boolean isDiamondPush() {
        return this.equals(DataMediaType.DIAMOND_PUSH);
    }
}


   1.2 修改vm页面和相应webx action,screen类,修改支持页面参数配置和check.

注意,screen等中原来otter做了判断非mysql或者oracle类型的不显示,都需要硬编码改为可以显示,这个有点土,害我找了好会儿微笑


check需要修改的比较多,使用的是Dwr调用的,

com.alibaba.otter.manager.biz.utils.DataSourceChecker

需要修改

 public String check(String name,String url, String username, String password, String encode, String sourceType)  测试数据源连接是否成功

public String checkMap(String namespace, String name, Long dataSourceId)  测试数据表是否连接

 public String checkNamespaceTables(final String namespace, final String name, final Long dataSourceId)  测试多个表是否select连接,对应数据源和表2个模块。

扩展支持其它NoSql DB类型。

1.3 vm页面修改


2、因为Otter使用的Guava版本和HBase等的guava冲突:

otter node中大量使用了guava的MapMaker,需要升级改为LoadingCache(这个工作量其实不小,而且要小心实现准确,待后面node中调试的时候测试);

主要修改实现不同NoSqlDB的连接获取,表元数据查询等:

DbDialectFactory 

DBDataSourceService 原接口返回sql的connection对象改为Object,在调用的时候根据数据库类型转换为不同的连接

// 构建第一层map
		dataSources = CacheBuilder.newBuilder().maximumSize(1000)
				.build(new CacheLoader<Long, LoadingCache<DbMediaSource, Object>>() {
					@Override
					public LoadingCache<DbMediaSource, Object> load(Long pipelineId) throws Exception {
						return CacheBuilder.newBuilder().maximumSize(1000)
								.build(new CacheLoader<DbMediaSource, Object>() {
									@Override
									public Object load(DbMediaSource dbMediaSource) throws Exception {
										// 扩展功能,可以自定义一些自己实现的 dataSource
										if (dbMediaSource.getType().isCassandra()) {
											return getCluster(dbMediaSource);
										} else if (dbMediaSource.getType().isElasticSearch()) {
											return getClient(dbMediaSource);
										} else if (dbMediaSource.getType().isHBase()) {
											return getHBaseConnection(dbMediaSource);
										} else if (dbMediaSource.getType().isHDFSArvo()) {
											return getHDFS(dbMediaSource);
										} else if (dbMediaSource.getType().isKafka()) {
											return getProducer(dbMediaSource);
										} else {
											DataSource customDataSource = preCreate(pipelineId, dbMediaSource);
											if (customDataSource != null) {
												return customDataSource;
											}
											return createDataSource(dbMediaSource.getUrl(), dbMediaSource.getUsername(),
													dbMediaSource.getPassword(), dbMediaSource.getDriver(),
													dbMediaSource.getType(), dbMediaSource.getEncode());
										}
									}
								});
					}

				});

	}


3、Node端修改:

3.1 实现不同类型的数据写入

新建 NoSqlTemplate接口,nosql db不使用sqlTemplate的sql,直接实现增删改和DDL的操作:

package com.alibaba.otter.node.etl.common.db.dialect;

import java.util.List;

import com.alibaba.otter.node.etl.load.exception.ConnClosedException;
import com.alibaba.otter.shared.etl.model.EventData;

public interface NoSqlTemplate {
	/**
	 * 批量执行dml数据操作,增,删,改
	 * 
	 * @param events
	 * @return 执行失败的记录集合返回,失败原因消息保存在exeResult字段中
	 */
	public List<EventData> batchEventDatas(List<EventData> events) throws ConnClosedException;

	/**
	 * 插入行数据
	 * 
	 * @param event
	 * @return 记录返回,失败原因消息保存在exeResult字段中
	 */
	public EventData insertEventData(EventData event) throws ConnClosedException;

	/**
	 * 更新行数句
	 * 
	 * @param event
	 * @return 记录返回,失败原因消息保存在exeResult字段中
	 */
	public EventData updateEventData(EventData event) throws ConnClosedException;

	/**
	 * 删除记录
	 * 
	 * @param event
	 * @return 记录返回,失败原因消息保存在exeResult字段中
	 */
	public EventData deleteEventData(EventData event) throws ConnClosedException;

	/**
	 * 建立表
	 * 
	 * @param event
	 * @return
	 */
	public EventData createTable(EventData event) throws ConnClosedException;

	/**
	 * 修改表
	 * 
	 * @param event
	 * @return
	 */
	public EventData alterTable(EventData event) throws ConnClosedException;

	/**
	 * 删除表
	 * 
	 * @param event
	 * @return
	 */
	public EventData eraseTable(EventData event) throws ConnClosedException;

	/**
	 * 清空表
	 * 
	 * @param event
	 * @return
	 */
	public EventData truncateTable(EventData event) throws ConnClosedException;

	/**
	 * 改名表
	 * 
	 * @param event
	 * @return
	 */
	public EventData renameTable(EventData event) throws ConnClosedException;
}

修改原 DbDialect,扩展原来的返回JdbcTemplate和SqlTemplate,在DbLoad端根据返回类型和数据类型分别判断后执行。

<span style="white-space:pre">	</span>//JdbcTemplate在nosqldb返回相应nosql db的链接
<span style="white-space:pre">	</span>public <T> T getJdbcTemplate();

	/**
	 * 获取数据操作相关类型,关系数据库,返回SqlTemplate,返回组织的sql NoSql
	 * database放回NoSqlTemplate,执行相关操作
	 * 
	 * @return
	 */
	public <T> T getSqlTemplate();

实现不同Nosql DB的DbDialect和NoSqlTemplate;

每个数据库系统类型2个实现类:

CassandraDialect;CassandraTemplate;

ElasticSearchDialect;ElasticSearchTemplate;

GreenPlumDialect;GreenPlumSqlTemplate gp继承SqlTemplate,跟关系数据库一样实现即可;

HBaseDialect;HBaseTemplate;

KafkaDialect;KafkaTemplate

3.2  修改DbLoader模块,支持各个数据类型写入

com.alibaba.otter.node.etl.load.loader.db.DbLoadAction

主要修改它的inner class 

DbLoadWorker

DoCall方法:

if (dbDialect.isNoSqlDB()) {
							NoSqlTemplate nosqltemplate = (NoSqlTemplate) dbDialect.getSqlTemplate();
							failedDatas.clear(); // 先清理
							processedDatas.clear();
							if (useBatch && canBatch) {
								nosqltemplate.batchEventDatas(splitDatas);
								// 更新统计信息
								for (int i = 0; i < splitDatas.size(); i++) {
									processStat(splitDatas.get(i));
								}
							} else {
								for (EventData event : splitDatas) {
									if (event.getEventType().isDelete()) {// 删除
										nosqltemplate.deleteEventData(event);
									} else if (event.getEventType().isUpdate()) {
										nosqltemplate.updateEventData(event);
									} else if (event.getEventType().isInsert()) {
										nosqltemplate.insertEventData(event);
									}
									processStat(event);
								}
							}
							
						} else {
							final LobCreator lobCreator = dbDialect.getLobHandler().getLobCreator();

然后基本完成,根据自己修改的过程毛糙的记录了一下。



评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值