mirror of
https://github.com/alibaba/canal.git
synced 2026-11-04 00:30:15 +08:00
调整Hbase适配
This commit is contained in:
@@ -28,6 +28,16 @@
|
|||||||
<artifactId>joda-time</artifactId>
|
<artifactId>joda-time</artifactId>
|
||||||
<version>2.9.4</version>
|
<version>2.9.4</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba</groupId>
|
||||||
|
<artifactId>druid</artifactId>
|
||||||
|
<version>1.1.9</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>mysql</groupId>
|
||||||
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
|
<version>5.1.40</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package com.alibaba.otter.canal.client.adapter;
|
package com.alibaba.otter.canal.client.adapter;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import com.alibaba.otter.canal.client.adapter.support.CanalOuterAdapterConfiguration;
|
import com.alibaba.otter.canal.client.adapter.support.CanalOuterAdapterConfiguration;
|
||||||
import com.alibaba.otter.canal.client.adapter.support.Dml;
|
import com.alibaba.otter.canal.client.adapter.support.Dml;
|
||||||
import com.alibaba.otter.canal.client.adapter.support.SPI;
|
import com.alibaba.otter.canal.client.adapter.support.SPI;
|
||||||
@@ -11,7 +13,7 @@ import com.alibaba.otter.canal.client.adapter.support.SPI;
|
|||||||
* @version 1.0.0
|
* @version 1.0.0
|
||||||
*/
|
*/
|
||||||
@SPI("logger")
|
@SPI("logger")
|
||||||
public interface CanalOuterAdapter {
|
public interface OuterAdapter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 外部适配器初始化接口
|
* 外部适配器初始化接口
|
||||||
@@ -21,11 +23,11 @@ public interface CanalOuterAdapter {
|
|||||||
void init(CanalOuterAdapterConfiguration configuration);
|
void init(CanalOuterAdapterConfiguration configuration);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 往适配器中写入数据
|
* 往适配器中同步数据
|
||||||
*
|
*
|
||||||
* @param dml 数据包
|
* @param dml 数据包
|
||||||
*/
|
*/
|
||||||
void writeOut(Dml dml);
|
void sync(Dml dml);
|
||||||
|
|
||||||
// void writeOut(FlatMessage flatMessage);
|
// void writeOut(FlatMessage flatMessage);
|
||||||
|
|
||||||
@@ -33,4 +35,14 @@ public interface CanalOuterAdapter {
|
|||||||
* 外部适配器销毁接口
|
* 外部适配器销毁接口
|
||||||
*/
|
*/
|
||||||
void destroy();
|
void destroy();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Etl操作
|
||||||
|
*
|
||||||
|
* @param criteriaSql 条件拼接sql
|
||||||
|
*/
|
||||||
|
default void etl(String criteriaSql) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,28 @@
|
|||||||
package com.alibaba.otter.canal.client.adapter.support;
|
package com.alibaba.otter.canal.client.adapter.support;
|
||||||
|
|
||||||
import com.google.common.collect.ArrayListMultimap;
|
import java.util.LinkedHashSet;
|
||||||
import com.google.common.collect.Multimap;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
public interface AdapterConfigs {
|
public class AdapterConfigs {
|
||||||
Multimap<String, String> configs = ArrayListMultimap.create();
|
|
||||||
|
private static Map<String, Set<String>> configs = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public static void put(String key, String value) {
|
||||||
|
Set<String> values = configs.get(key);
|
||||||
|
if (values == null) {
|
||||||
|
values = new LinkedHashSet<>();
|
||||||
|
}
|
||||||
|
values.add(value);
|
||||||
|
configs.put(key, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Set<String> get(String key) {
|
||||||
|
return configs.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void clear() {
|
||||||
|
configs.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
package com.alibaba.otter.canal.client.adapter.support;
|
||||||
|
|
||||||
|
import com.alibaba.druid.pool.DruidDataSource;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
public class DatasourceConfig {
|
||||||
|
|
||||||
|
public final static Map<String, DruidDataSource> DATA_SOURCES = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
private String driver = "com.mysql.jdbc.Driver";
|
||||||
|
private String url;
|
||||||
|
private String database;
|
||||||
|
private String type = "mysql";
|
||||||
|
private String username;
|
||||||
|
private String password;
|
||||||
|
private Integer maxActive = 3;
|
||||||
|
|
||||||
|
public String getDriver() {
|
||||||
|
return driver;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDriver(String driver) {
|
||||||
|
this.driver = driver;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUrl(String url) {
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDatabase() {
|
||||||
|
return database;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDatabase(String database) {
|
||||||
|
this.database = database;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getMaxActive() {
|
||||||
|
return maxActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxActive(Integer maxActive) {
|
||||||
|
this.maxActive = maxActive;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,7 +10,7 @@ import java.util.concurrent.Future;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.alibaba.otter.canal.client.adapter.CanalOuterAdapter;
|
import com.alibaba.otter.canal.client.adapter.OuterAdapter;
|
||||||
import com.alibaba.otter.canal.client.adapter.support.Dml;
|
import com.alibaba.otter.canal.client.adapter.support.Dml;
|
||||||
import com.alibaba.otter.canal.client.adapter.support.MessageUtil;
|
import com.alibaba.otter.canal.client.adapter.support.MessageUtil;
|
||||||
import com.alibaba.otter.canal.protocol.FlatMessage;
|
import com.alibaba.otter.canal.protocol.FlatMessage;
|
||||||
@@ -27,7 +27,7 @@ public abstract class AbstractCanalAdapterWorker {
|
|||||||
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
|
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||||
|
|
||||||
protected String canalDestination; // canal实例
|
protected String canalDestination; // canal实例
|
||||||
protected List<List<CanalOuterAdapter>> canalOuterAdapters; // 外部适配器
|
protected List<List<OuterAdapter>> canalOuterAdapters; // 外部适配器
|
||||||
protected ExecutorService groupInnerExecutorService; // 组内工作线程池
|
protected ExecutorService groupInnerExecutorService; // 组内工作线程池
|
||||||
protected volatile boolean running = false; // 是否运行中
|
protected volatile boolean running = false; // 是否运行中
|
||||||
protected Thread thread = null;
|
protected Thread thread = null;
|
||||||
@@ -42,21 +42,21 @@ public abstract class AbstractCanalAdapterWorker {
|
|||||||
protected void writeOut(final Message message) {
|
protected void writeOut(final Message message) {
|
||||||
List<Future<Boolean>> futures = new ArrayList<>();
|
List<Future<Boolean>> futures = new ArrayList<>();
|
||||||
// 组间适配器并行运行
|
// 组间适配器并行运行
|
||||||
for (List<CanalOuterAdapter> outerAdapters : canalOuterAdapters) {
|
for (List<OuterAdapter> outerAdapters : canalOuterAdapters) {
|
||||||
final List<CanalOuterAdapter> adapters = outerAdapters;
|
final List<OuterAdapter> adapters = outerAdapters;
|
||||||
futures.add(groupInnerExecutorService.submit(new Callable<Boolean>() {
|
futures.add(groupInnerExecutorService.submit(new Callable<Boolean>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Boolean call() {
|
public Boolean call() {
|
||||||
try {
|
try {
|
||||||
// 组内适配器穿行运行,尽量不要配置组内适配器
|
// 组内适配器穿行运行,尽量不要配置组内适配器
|
||||||
for (final CanalOuterAdapter c : adapters) {
|
for (final OuterAdapter c : adapters) {
|
||||||
long begin = System.currentTimeMillis();
|
long begin = System.currentTimeMillis();
|
||||||
MessageUtil.parse4Dml(message, new MessageUtil.Consumer<Dml>() {
|
MessageUtil.parse4Dml(message, new MessageUtil.Consumer<Dml>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void accept(Dml dml) {
|
public void accept(Dml dml) {
|
||||||
c.writeOut(dml);
|
c.sync(dml);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -90,18 +90,18 @@ public abstract class AbstractCanalAdapterWorker {
|
|||||||
protected void writeOut(final FlatMessage flatMessage) {
|
protected void writeOut(final FlatMessage flatMessage) {
|
||||||
List<Future<Boolean>> futures = new ArrayList<>();
|
List<Future<Boolean>> futures = new ArrayList<>();
|
||||||
// 组间适配器并行运行
|
// 组间适配器并行运行
|
||||||
for (List<CanalOuterAdapter> outerAdapters : canalOuterAdapters) {
|
for (List<OuterAdapter> outerAdapters : canalOuterAdapters) {
|
||||||
final List<CanalOuterAdapter> adapters = outerAdapters;
|
final List<OuterAdapter> adapters = outerAdapters;
|
||||||
futures.add(groupInnerExecutorService.submit(new Callable<Boolean>() {
|
futures.add(groupInnerExecutorService.submit(new Callable<Boolean>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Boolean call() {
|
public Boolean call() {
|
||||||
try {
|
try {
|
||||||
// 组内适配器穿行运行,尽量不要配置组内适配器
|
// 组内适配器穿行运行,尽量不要配置组内适配器
|
||||||
for (CanalOuterAdapter c : adapters) {
|
for (OuterAdapter c : adapters) {
|
||||||
long begin = System.currentTimeMillis();
|
long begin = System.currentTimeMillis();
|
||||||
Dml dml = MessageUtil.flatMessage2Dml(flatMessage);
|
Dml dml = MessageUtil.flatMessage2Dml(flatMessage);
|
||||||
c.writeOut(dml);
|
c.sync(dml);
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("{} elapsed time: {}",
|
logger.debug("{} elapsed time: {}",
|
||||||
c.getClass().getName(),
|
c.getClass().getName(),
|
||||||
@@ -154,8 +154,8 @@ public abstract class AbstractCanalAdapterWorker {
|
|||||||
}
|
}
|
||||||
groupInnerExecutorService.shutdown();
|
groupInnerExecutorService.shutdown();
|
||||||
logger.info("topic connectors' worker thread dead!");
|
logger.info("topic connectors' worker thread dead!");
|
||||||
for (List<CanalOuterAdapter> outerAdapters : canalOuterAdapters) {
|
for (List<OuterAdapter> outerAdapters : canalOuterAdapters) {
|
||||||
for (CanalOuterAdapter adapter : outerAdapters) {
|
for (OuterAdapter adapter : outerAdapters) {
|
||||||
adapter.destroy();
|
adapter.destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,12 +4,11 @@ import java.util.List;
|
|||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
|
|
||||||
import org.apache.kafka.clients.consumer.CommitFailedException;
|
import org.apache.kafka.clients.consumer.CommitFailedException;
|
||||||
import org.apache.kafka.common.errors.WakeupException;
|
import org.apache.kafka.common.errors.WakeupException;
|
||||||
|
|
||||||
import com.alibaba.otter.canal.client.adapter.CanalOuterAdapter;
|
import com.alibaba.otter.canal.client.adapter.OuterAdapter;
|
||||||
import com.alibaba.otter.canal.client.kafka.KafkaCanalConnector;
|
import com.alibaba.otter.canal.client.kafka.KafkaCanalConnector;
|
||||||
import com.alibaba.otter.canal.client.kafka.KafkaCanalConnectors;
|
import com.alibaba.otter.canal.client.kafka.KafkaCanalConnectors;
|
||||||
import com.alibaba.otter.canal.protocol.FlatMessage;
|
import com.alibaba.otter.canal.protocol.FlatMessage;
|
||||||
@@ -30,7 +29,7 @@ public class CanalAdapterKafkaWorker extends AbstractCanalAdapterWorker {
|
|||||||
private boolean flatMessage;
|
private boolean flatMessage;
|
||||||
|
|
||||||
public CanalAdapterKafkaWorker(String bootstrapServers, String topic, String groupId,
|
public CanalAdapterKafkaWorker(String bootstrapServers, String topic, String groupId,
|
||||||
List<List<CanalOuterAdapter>> canalOuterAdapters, boolean flatMessage){
|
List<List<OuterAdapter>> canalOuterAdapters, boolean flatMessage){
|
||||||
this.canalOuterAdapters = canalOuterAdapters;
|
this.canalOuterAdapters = canalOuterAdapters;
|
||||||
this.groupInnerExecutorService = Executors.newFixedThreadPool(canalOuterAdapters.size());
|
this.groupInnerExecutorService = Executors.newFixedThreadPool(canalOuterAdapters.size());
|
||||||
this.topic = topic;
|
this.topic = topic;
|
||||||
@@ -81,8 +80,8 @@ public class CanalAdapterKafkaWorker extends AbstractCanalAdapterWorker {
|
|||||||
}
|
}
|
||||||
groupInnerExecutorService.shutdown();
|
groupInnerExecutorService.shutdown();
|
||||||
logger.info("topic {} connectors' worker thread dead!", this.topic);
|
logger.info("topic {} connectors' worker thread dead!", this.topic);
|
||||||
for (List<CanalOuterAdapter> outerAdapters : canalOuterAdapters) {
|
for (List<OuterAdapter> outerAdapters : canalOuterAdapters) {
|
||||||
for (CanalOuterAdapter adapter : outerAdapters) {
|
for (OuterAdapter adapter : outerAdapters) {
|
||||||
adapter.destroy();
|
adapter.destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import org.apache.commons.lang.StringUtils;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.alibaba.otter.canal.client.adapter.CanalOuterAdapter;
|
import com.alibaba.otter.canal.client.adapter.OuterAdapter;
|
||||||
import com.alibaba.otter.canal.client.adapter.support.CanalClientConfig;
|
import com.alibaba.otter.canal.client.adapter.support.CanalClientConfig;
|
||||||
import com.alibaba.otter.canal.client.adapter.support.CanalOuterAdapterConfiguration;
|
import com.alibaba.otter.canal.client.adapter.support.CanalOuterAdapterConfiguration;
|
||||||
import com.alibaba.otter.canal.client.adapter.support.ExtensionLoader;
|
import com.alibaba.otter.canal.client.adapter.support.ExtensionLoader;
|
||||||
@@ -33,7 +33,7 @@ public class CanalAdapterLoader {
|
|||||||
|
|
||||||
private Map<String, AbstractCanalAdapterWorker> canalMQWorker = new HashMap<>();
|
private Map<String, AbstractCanalAdapterWorker> canalMQWorker = new HashMap<>();
|
||||||
|
|
||||||
private ExtensionLoader<CanalOuterAdapter> loader;
|
private ExtensionLoader<OuterAdapter> loader;
|
||||||
|
|
||||||
public CanalAdapterLoader(CanalClientConfig canalClientConfig){
|
public CanalAdapterLoader(CanalClientConfig canalClientConfig){
|
||||||
this.canalClientConfig = canalClientConfig;
|
this.canalClientConfig = canalClientConfig;
|
||||||
@@ -48,7 +48,7 @@ public class CanalAdapterLoader {
|
|||||||
throw new RuntimeException("Blank config property: canalInstances or canalMQTopics");
|
throw new RuntimeException("Blank config property: canalInstances or canalMQTopics");
|
||||||
}
|
}
|
||||||
|
|
||||||
loader = ExtensionLoader.getExtensionLoader(CanalOuterAdapter.class, "" /*
|
loader = ExtensionLoader.getExtensionLoader(OuterAdapter.class, "" /*
|
||||||
* TODO
|
* TODO
|
||||||
* canalClientConfig
|
* canalClientConfig
|
||||||
* .
|
* .
|
||||||
@@ -68,10 +68,10 @@ public class CanalAdapterLoader {
|
|||||||
// 初始化canal-client的适配器
|
// 初始化canal-client的适配器
|
||||||
if (canalClientConfig.getCanalInstances() != null) {
|
if (canalClientConfig.getCanalInstances() != null) {
|
||||||
for (CanalClientConfig.CanalInstance instance : canalClientConfig.getCanalInstances()) {
|
for (CanalClientConfig.CanalInstance instance : canalClientConfig.getCanalInstances()) {
|
||||||
List<List<CanalOuterAdapter>> canalOuterAdapterGroups = new ArrayList<>();
|
List<List<OuterAdapter>> canalOuterAdapterGroups = new ArrayList<>();
|
||||||
|
|
||||||
for (CanalClientConfig.AdapterGroup connectorGroup : instance.getAdapterGroups()) {
|
for (CanalClientConfig.AdapterGroup connectorGroup : instance.getAdapterGroups()) {
|
||||||
List<CanalOuterAdapter> canalOutConnectors = new ArrayList<>();
|
List<OuterAdapter> canalOutConnectors = new ArrayList<>();
|
||||||
for (CanalOuterAdapterConfiguration c : connectorGroup.getOutAdapters()) {
|
for (CanalOuterAdapterConfiguration c : connectorGroup.getOutAdapters()) {
|
||||||
loadConnector(c, canalOutConnectors);
|
loadConnector(c, canalOutConnectors);
|
||||||
}
|
}
|
||||||
@@ -93,9 +93,9 @@ public class CanalAdapterLoader {
|
|||||||
if (canalClientConfig.getMqTopics() != null) {
|
if (canalClientConfig.getMqTopics() != null) {
|
||||||
for (CanalClientConfig.MQTopic topic : canalClientConfig.getMqTopics()) {
|
for (CanalClientConfig.MQTopic topic : canalClientConfig.getMqTopics()) {
|
||||||
for (CanalClientConfig.Group group : topic.getGroups()) {
|
for (CanalClientConfig.Group group : topic.getGroups()) {
|
||||||
List<List<CanalOuterAdapter>> canalOuterAdapterGroups = new ArrayList<>();
|
List<List<OuterAdapter>> canalOuterAdapterGroups = new ArrayList<>();
|
||||||
|
|
||||||
List<CanalOuterAdapter> canalOuterAdapters = new ArrayList<>();
|
List<OuterAdapter> canalOuterAdapters = new ArrayList<>();
|
||||||
|
|
||||||
for (CanalOuterAdapterConfiguration config : group.getOutAdapters()) {
|
for (CanalOuterAdapterConfiguration config : group.getOutAdapters()) {
|
||||||
loadConnector(config, canalOuterAdapters);
|
loadConnector(config, canalOuterAdapters);
|
||||||
@@ -125,9 +125,9 @@ public class CanalAdapterLoader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadConnector(CanalOuterAdapterConfiguration config, List<CanalOuterAdapter> canalOutConnectors) {
|
private void loadConnector(CanalOuterAdapterConfiguration config, List<OuterAdapter> canalOutConnectors) {
|
||||||
try {
|
try {
|
||||||
CanalOuterAdapter adapter = loader.getExtension(config.getName());
|
OuterAdapter adapter = loader.getExtension(config.getName());
|
||||||
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
||||||
// 替换ClassLoader
|
// 替换ClassLoader
|
||||||
Thread.currentThread().setContextClassLoader(adapter.getClass().getClassLoader());
|
Thread.currentThread().setContextClassLoader(adapter.getClass().getClassLoader());
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import java.util.concurrent.TimeUnit;
|
|||||||
import org.apache.kafka.clients.consumer.CommitFailedException;
|
import org.apache.kafka.clients.consumer.CommitFailedException;
|
||||||
import org.apache.kafka.common.errors.WakeupException;
|
import org.apache.kafka.common.errors.WakeupException;
|
||||||
|
|
||||||
import com.alibaba.otter.canal.client.adapter.CanalOuterAdapter;
|
import com.alibaba.otter.canal.client.adapter.OuterAdapter;
|
||||||
import com.alibaba.otter.canal.client.rocketmq.RocketMQCanalConnector;
|
import com.alibaba.otter.canal.client.rocketmq.RocketMQCanalConnector;
|
||||||
import com.alibaba.otter.canal.client.rocketmq.RocketMQCanalConnectorProvider;
|
import com.alibaba.otter.canal.client.rocketmq.RocketMQCanalConnectorProvider;
|
||||||
import com.alibaba.otter.canal.protocol.Message;
|
import com.alibaba.otter.canal.protocol.Message;
|
||||||
@@ -26,7 +26,7 @@ public class CanalAdapterRocketMQWorker extends AbstractCanalAdapterWorker {
|
|||||||
private String topic;
|
private String topic;
|
||||||
|
|
||||||
public CanalAdapterRocketMQWorker(String nameServers, String topic, String groupId,
|
public CanalAdapterRocketMQWorker(String nameServers, String topic, String groupId,
|
||||||
List<List<CanalOuterAdapter>> canalOuterAdapters){
|
List<List<OuterAdapter>> canalOuterAdapters){
|
||||||
logger.info("RocketMQ consumer config topic:{}, nameServer:{}, groupId:{}", topic, nameServers, groupId);
|
logger.info("RocketMQ consumer config topic:{}, nameServer:{}, groupId:{}", topic, nameServers, groupId);
|
||||||
this.canalOuterAdapters = canalOuterAdapters;
|
this.canalOuterAdapters = canalOuterAdapters;
|
||||||
this.groupInnerExecutorService = Executors.newFixedThreadPool(canalOuterAdapters.size());
|
this.groupInnerExecutorService = Executors.newFixedThreadPool(canalOuterAdapters.size());
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import java.util.concurrent.Executors;
|
|||||||
|
|
||||||
import com.alibaba.otter.canal.client.CanalConnector;
|
import com.alibaba.otter.canal.client.CanalConnector;
|
||||||
import com.alibaba.otter.canal.client.CanalConnectors;
|
import com.alibaba.otter.canal.client.CanalConnectors;
|
||||||
import com.alibaba.otter.canal.client.adapter.CanalOuterAdapter;
|
import com.alibaba.otter.canal.client.adapter.OuterAdapter;
|
||||||
import com.alibaba.otter.canal.client.impl.ClusterCanalConnector;
|
import com.alibaba.otter.canal.client.impl.ClusterCanalConnector;
|
||||||
import com.alibaba.otter.canal.protocol.Message;
|
import com.alibaba.otter.canal.protocol.Message;
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ public class CanalAdapterWorker extends AbstractCanalAdapterWorker {
|
|||||||
* @param canalOuterAdapters 外部适配器组
|
* @param canalOuterAdapters 外部适配器组
|
||||||
*/
|
*/
|
||||||
public CanalAdapterWorker(String canalDestination, SocketAddress address,
|
public CanalAdapterWorker(String canalDestination, SocketAddress address,
|
||||||
List<List<CanalOuterAdapter>> canalOuterAdapters){
|
List<List<OuterAdapter>> canalOuterAdapters){
|
||||||
this.canalOuterAdapters = canalOuterAdapters;
|
this.canalOuterAdapters = canalOuterAdapters;
|
||||||
this.canalDestination = canalDestination;
|
this.canalDestination = canalDestination;
|
||||||
groupInnerExecutorService = Executors.newFixedThreadPool(canalOuterAdapters.size());
|
groupInnerExecutorService = Executors.newFixedThreadPool(canalOuterAdapters.size());
|
||||||
@@ -46,7 +46,7 @@ public class CanalAdapterWorker extends AbstractCanalAdapterWorker {
|
|||||||
* @param canalOuterAdapters 外部适配器组
|
* @param canalOuterAdapters 外部适配器组
|
||||||
*/
|
*/
|
||||||
public CanalAdapterWorker(String canalDestination, String zookeeperHosts,
|
public CanalAdapterWorker(String canalDestination, String zookeeperHosts,
|
||||||
List<List<CanalOuterAdapter>> canalOuterAdapters){
|
List<List<OuterAdapter>> canalOuterAdapters){
|
||||||
this.canalOuterAdapters = canalOuterAdapters;
|
this.canalOuterAdapters = canalOuterAdapters;
|
||||||
this.canalDestination = canalDestination;
|
this.canalDestination = canalDestination;
|
||||||
groupInnerExecutorService = Executors.newFixedThreadPool(canalOuterAdapters.size());
|
groupInnerExecutorService = Executors.newFixedThreadPool(canalOuterAdapters.size());
|
||||||
@@ -96,8 +96,8 @@ public class CanalAdapterWorker extends AbstractCanalAdapterWorker {
|
|||||||
}
|
}
|
||||||
groupInnerExecutorService.shutdown();
|
groupInnerExecutorService.shutdown();
|
||||||
logger.info("destination {} adapters' worker thread dead!", canalDestination);
|
logger.info("destination {} adapters' worker thread dead!", canalDestination);
|
||||||
for (List<CanalOuterAdapter> outerAdapters : canalOuterAdapters) {
|
for (List<OuterAdapter> outerAdapters : canalOuterAdapters) {
|
||||||
for (CanalOuterAdapter adapter : outerAdapters) {
|
for (OuterAdapter adapter : outerAdapters) {
|
||||||
adapter.destroy();
|
adapter.destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import org.apache.hadoop.hbase.HBaseConfiguration;
|
|||||||
import org.apache.hadoop.hbase.client.Connection;
|
import org.apache.hadoop.hbase.client.Connection;
|
||||||
import org.apache.hadoop.hbase.client.ConnectionFactory;
|
import org.apache.hadoop.hbase.client.ConnectionFactory;
|
||||||
|
|
||||||
import com.alibaba.otter.canal.client.adapter.CanalOuterAdapter;
|
import com.alibaba.otter.canal.client.adapter.OuterAdapter;
|
||||||
import com.alibaba.otter.canal.client.adapter.hbase.config.MappingConfig;
|
import com.alibaba.otter.canal.client.adapter.hbase.config.MappingConfig;
|
||||||
import com.alibaba.otter.canal.client.adapter.hbase.config.MappingConfigLoader;
|
import com.alibaba.otter.canal.client.adapter.hbase.config.MappingConfigLoader;
|
||||||
import com.alibaba.otter.canal.client.adapter.hbase.service.HbaseSyncService;
|
import com.alibaba.otter.canal.client.adapter.hbase.service.HbaseSyncService;
|
||||||
@@ -25,7 +25,7 @@ import com.alibaba.otter.canal.client.adapter.support.SPI;
|
|||||||
* @version 1.0.0
|
* @version 1.0.0
|
||||||
*/
|
*/
|
||||||
@SPI("hbase")
|
@SPI("hbase")
|
||||||
public class HbaseAdapter implements CanalOuterAdapter {
|
public class HbaseAdapter implements OuterAdapter {
|
||||||
|
|
||||||
private static volatile Map<String, MappingConfig> mappingConfigCache = null;
|
private static volatile Map<String, MappingConfig> mappingConfigCache = null;
|
||||||
|
|
||||||
@@ -83,7 +83,7 @@ public class HbaseAdapter implements CanalOuterAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeOut(Dml dml) {
|
public void sync(Dml dml) {
|
||||||
if (dml == null) {
|
if (dml == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,9 +13,18 @@ import java.util.Set;
|
|||||||
* @version 1.0.0
|
* @version 1.0.0
|
||||||
*/
|
*/
|
||||||
public class MappingConfig {
|
public class MappingConfig {
|
||||||
|
private String dataSourceKey;
|
||||||
|
|
||||||
private HbaseOrm hbaseOrm;
|
private HbaseOrm hbaseOrm;
|
||||||
|
|
||||||
|
public String getDataSourceKey() {
|
||||||
|
return dataSourceKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDataSourceKey(String dataSourceKey) {
|
||||||
|
this.dataSourceKey = dataSourceKey;
|
||||||
|
}
|
||||||
|
|
||||||
public HbaseOrm getHbaseOrm() {
|
public HbaseOrm getHbaseOrm() {
|
||||||
return hbaseOrm;
|
return hbaseOrm;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ public class MappingConfigLoader {
|
|||||||
|
|
||||||
Map<String, MappingConfig> result = new LinkedHashMap<>();
|
Map<String, MappingConfig> result = new LinkedHashMap<>();
|
||||||
|
|
||||||
Collection<String> configs = AdapterConfigs.configs.get("hbase");
|
Collection<String> configs = AdapterConfigs.get("hbase");
|
||||||
for (String c : configs) {
|
for (String c : configs) {
|
||||||
if (c == null) {
|
if (c == null) {
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
package com.alibaba.otter.canal.client.adapter.hbase.service;
|
||||||
|
|
||||||
|
public class HbaseEtlService {
|
||||||
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
|
dataSourceKey: defaultDS
|
||||||
hbaseOrm:
|
hbaseOrm:
|
||||||
mode: PHOENIX #NATIVE #STRING
|
mode: PHOENIX #NATIVE #STRING
|
||||||
database: mytest # 数据库名
|
database: mytest # 数据库名
|
||||||
table: person2 # 数据库表名
|
table: person2 # 数据库表名
|
||||||
hbaseTable: MYTEST.PERSON2 # HBase表名
|
hbaseTable: MYTEST_PERSON2 # HBase表名
|
||||||
family: CF # 默认统一Family名称
|
family: CF # 默认统一Family名称
|
||||||
uppercaseQualifier: true # 字段名转大写, 默认为true
|
uppercaseQualifier: true # 字段名转大写, 默认为true
|
||||||
commitBatch: 3000 # 批量提交的大小
|
commitBatch: 3000 # 批量提交的大小
|
||||||
|
|||||||
@@ -81,6 +81,7 @@
|
|||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
<finalName>canal-client-launcher</finalName>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
|||||||
@@ -1,56 +1,12 @@
|
|||||||
package com.alibaba.otter.canal.adapter.launcher;
|
package com.alibaba.otter.canal.adapter.launcher;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
|
||||||
import javax.annotation.PreDestroy;
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
|
|
||||||
import com.alibaba.otter.canal.adapter.launcher.loader.CanalAdapterLoader;
|
|
||||||
import com.alibaba.otter.canal.client.adapter.support.CanalClientConfig;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||||
|
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
public class CanalAdapterApplication {
|
public class CanalAdapterApplication {
|
||||||
private static final Logger logger = LoggerFactory.getLogger(CanalAdapterApplication.class);
|
|
||||||
|
|
||||||
private static CanalAdapterLoader adapterLoader;
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
new SpringApplicationBuilder(CanalAdapterApplication.class).run(args);
|
new SpringApplicationBuilder(CanalAdapterApplication.class).run(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Resource
|
|
||||||
private CanalClientConfig canalClientConf;
|
|
||||||
|
|
||||||
@PostConstruct
|
|
||||||
public void init() {
|
|
||||||
if (adapterLoader == null) {
|
|
||||||
try {
|
|
||||||
logger.info("## start the canal client adapters.");
|
|
||||||
adapterLoader = new CanalAdapterLoader(canalClientConf);
|
|
||||||
adapterLoader.init();
|
|
||||||
logger.info("## the canal client adapters are running now ......");
|
|
||||||
} catch (Throwable e) {
|
|
||||||
logger.error("## something goes wrong when starting up the canal client adapters:", e);
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@PreDestroy
|
|
||||||
public void destroy() {
|
|
||||||
try {
|
|
||||||
logger.info("## stop the canal client adapters");
|
|
||||||
if (adapterLoader != null) {
|
|
||||||
adapterLoader.destroy();
|
|
||||||
}
|
|
||||||
} catch (Throwable e) {
|
|
||||||
logger.warn("## something goes wrong when stopping canal client adapters:", e);
|
|
||||||
} finally {
|
|
||||||
logger.info("## canal client adapters are down.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import com.alibaba.otter.canal.client.adapter.support.CanalClientConfig;
|
|||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@ConfigurationProperties(prefix = "canal.conf")
|
|
||||||
@Component
|
@Component
|
||||||
|
@ConfigurationProperties(prefix = "canal.conf")
|
||||||
public class AdapterCanalConfig extends CanalClientConfig {
|
public class AdapterCanalConfig extends CanalClientConfig {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
package com.alibaba.otter.canal.adapter.launcher.config;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import com.alibaba.druid.pool.DruidDataSource;
|
||||||
|
import com.alibaba.otter.canal.client.adapter.support.AdapterConfigs;
|
||||||
|
import com.alibaba.otter.canal.client.adapter.support.DatasourceConfig;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@ConfigurationProperties(prefix = "adapter.conf")
|
||||||
|
public class AdapterConfig {
|
||||||
|
|
||||||
|
private Map<String, DatasourceConfig> datasourceConfigs;
|
||||||
|
|
||||||
|
private List<String> adapterConfigs;
|
||||||
|
|
||||||
|
public List<String> getAdapterConfigs() {
|
||||||
|
return adapterConfigs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, DatasourceConfig> getDatasourceConfigs() {
|
||||||
|
return datasourceConfigs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDatasourceConfigs(Map<String, DatasourceConfig> datasourceConfigs) {
|
||||||
|
this.datasourceConfigs = datasourceConfigs;
|
||||||
|
|
||||||
|
if (datasourceConfigs != null) {
|
||||||
|
for (Map.Entry<String, DatasourceConfig> entry : datasourceConfigs.entrySet()) {
|
||||||
|
DatasourceConfig datasourceConfig = entry.getValue();
|
||||||
|
// 加载数据源连接池
|
||||||
|
DruidDataSource ds = new DruidDataSource();
|
||||||
|
ds.setDriverClassName(datasourceConfig.getDriver());
|
||||||
|
ds.setUrl(datasourceConfig.getUrl());
|
||||||
|
ds.setUsername(datasourceConfig.getUsername());
|
||||||
|
ds.setPassword(datasourceConfig.getPassword());
|
||||||
|
ds.setInitialSize(1);
|
||||||
|
ds.setMinIdle(1);
|
||||||
|
ds.setMaxActive(datasourceConfig.getMaxActive());
|
||||||
|
ds.setMaxWait(60000);
|
||||||
|
ds.setTimeBetweenEvictionRunsMillis(60000);
|
||||||
|
ds.setMinEvictableIdleTimeMillis(300000);
|
||||||
|
ds.setPoolPreparedStatements(false);
|
||||||
|
ds.setMaxPoolPreparedStatementPerConnectionSize(20);
|
||||||
|
ds.setValidationQuery("select 1");
|
||||||
|
try {
|
||||||
|
ds.init();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
DatasourceConfig.DATA_SOURCES.put(entry.getKey(), ds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAdapterConfigs(List<String> adapterConfigs) {
|
||||||
|
this.adapterConfigs = adapterConfigs;
|
||||||
|
|
||||||
|
if (adapterConfigs != null) {
|
||||||
|
AdapterConfigs.clear();
|
||||||
|
for (String adapterConfig : adapterConfigs) {
|
||||||
|
int idx = adapterConfig.indexOf("/");
|
||||||
|
if (idx > -1) {
|
||||||
|
String type = adapterConfig.substring(0, idx);
|
||||||
|
String ymlFile = adapterConfig.substring(idx + 1);
|
||||||
|
AdapterConfigs.put(type, ymlFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
package com.alibaba.otter.canal.adapter.launcher.config;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import com.alibaba.otter.canal.client.adapter.support.AdapterConfigs;
|
|
||||||
|
|
||||||
@Component
|
|
||||||
@ConfigurationProperties(prefix = "adapter.conf.path")
|
|
||||||
public class AdapterConfigPath {
|
|
||||||
|
|
||||||
private List<String> adapterConfigs;
|
|
||||||
|
|
||||||
public List<String> getAdapterConfigs() {
|
|
||||||
return adapterConfigs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAdapterConfigs(List<String> adapterConfigs) {
|
|
||||||
this.adapterConfigs = adapterConfigs;
|
|
||||||
|
|
||||||
if (adapterConfigs != null) {
|
|
||||||
AdapterConfigs.configs.clear();
|
|
||||||
for (String adapterConfig : adapterConfigs) {
|
|
||||||
int idx = adapterConfig.indexOf("/");
|
|
||||||
if (idx > -1) {
|
|
||||||
String type = adapterConfig.substring(0, idx);
|
|
||||||
String ymlFile = adapterConfig.substring(idx + 1);
|
|
||||||
AdapterConfigs.configs.put(type, ymlFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -10,7 +10,7 @@ import java.util.concurrent.Future;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.alibaba.otter.canal.client.adapter.CanalOuterAdapter;
|
import com.alibaba.otter.canal.client.adapter.OuterAdapter;
|
||||||
import com.alibaba.otter.canal.client.adapter.support.MessageUtil;
|
import com.alibaba.otter.canal.client.adapter.support.MessageUtil;
|
||||||
import com.alibaba.otter.canal.protocol.Message;
|
import com.alibaba.otter.canal.protocol.Message;
|
||||||
|
|
||||||
@@ -25,32 +25,23 @@ public abstract class AbstractCanalAdapterWorker {
|
|||||||
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
|
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||||
|
|
||||||
protected String canalDestination; // canal实例
|
protected String canalDestination; // canal实例
|
||||||
protected List<List<CanalOuterAdapter>> canalOuterAdapters; // 外部适配器
|
protected List<List<OuterAdapter>> canalOuterAdapters; // 外部适配器
|
||||||
protected ExecutorService groupInnerExecutorService; // 组内工作线程池
|
protected ExecutorService groupInnerExecutorService; // 组内工作线程池
|
||||||
protected volatile boolean running = false; // 是否运行中
|
protected volatile boolean running = false; // 是否运行中
|
||||||
protected Thread thread = null;
|
protected Thread thread = null;
|
||||||
protected Thread.UncaughtExceptionHandler handler = new Thread.UncaughtExceptionHandler() {
|
protected Thread.UncaughtExceptionHandler handler = (t, e) -> logger.error("parse events has an error", e);
|
||||||
|
|
||||||
@Override
|
|
||||||
public void uncaughtException(Thread t, Throwable e) {
|
|
||||||
logger.error("parse events has an error", e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
protected void writeOut(final Message message) {
|
protected void writeOut(final Message message) {
|
||||||
List<Future<Boolean>> futures = new ArrayList<>();
|
List<Future<Boolean>> futures = new ArrayList<>();
|
||||||
// 组间适配器并行运行
|
// 组间适配器并行运行
|
||||||
for (List<CanalOuterAdapter> outerAdapters : canalOuterAdapters) {
|
for (List<OuterAdapter> outerAdapters : canalOuterAdapters) {
|
||||||
final List<CanalOuterAdapter> adapters = outerAdapters;
|
final List<OuterAdapter> adapters = outerAdapters;
|
||||||
futures.add(groupInnerExecutorService.submit(new Callable<Boolean>() {
|
futures.add(groupInnerExecutorService.submit(() -> {
|
||||||
|
|
||||||
@Override
|
|
||||||
public Boolean call() {
|
|
||||||
try {
|
try {
|
||||||
// 组内适配器穿行运行,尽量不要配置组内适配器
|
// 组内适配器穿行运行,尽量不要配置组内适配器
|
||||||
for (final CanalOuterAdapter c : adapters) {
|
for (final OuterAdapter c : adapters) {
|
||||||
long begin = System.currentTimeMillis();
|
long begin = System.currentTimeMillis();
|
||||||
MessageUtil.parse4Dml(message, c::writeOut);
|
MessageUtil.parse4Dml(message, c::sync);
|
||||||
|
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("{} elapsed time: {}",
|
logger.debug("{} elapsed time: {}",
|
||||||
@@ -62,7 +53,6 @@ public abstract class AbstractCanalAdapterWorker {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// 等待所有适配器写入完成
|
// 等待所有适配器写入完成
|
||||||
@@ -131,9 +121,6 @@ public abstract class AbstractCanalAdapterWorker {
|
|||||||
if ((System.currentTimeMillis() - begin) > 5 * 60 * 1000) {
|
if ((System.currentTimeMillis() - begin) > 5 * 60 * 1000) {
|
||||||
logger.error("topic: {} batchId {} elapsed time: {} ms", topic, message.getId(), now - begin);
|
logger.error("topic: {} batchId {} elapsed time: {} ms", topic, message.getId(), now - begin);
|
||||||
}
|
}
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("topic: {} batchId {} elapsed time: {} ms", topic, message.getId(), now - begin);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void stopOutAdapters() {
|
protected void stopOutAdapters() {
|
||||||
@@ -146,8 +133,8 @@ public abstract class AbstractCanalAdapterWorker {
|
|||||||
}
|
}
|
||||||
groupInnerExecutorService.shutdown();
|
groupInnerExecutorService.shutdown();
|
||||||
logger.info("topic connectors' worker thread dead!");
|
logger.info("topic connectors' worker thread dead!");
|
||||||
for (List<CanalOuterAdapter> outerAdapters : canalOuterAdapters) {
|
for (List<OuterAdapter> outerAdapters : canalOuterAdapters) {
|
||||||
for (CanalOuterAdapter adapter : outerAdapters) {
|
for (OuterAdapter adapter : outerAdapters) {
|
||||||
adapter.destroy();
|
adapter.destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import java.util.Map;
|
|||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
import com.alibaba.otter.canal.client.adapter.CanalOuterAdapter;
|
import com.alibaba.otter.canal.client.adapter.OuterAdapter;
|
||||||
import com.alibaba.otter.canal.client.adapter.support.CanalOuterAdapterConfiguration;
|
import com.alibaba.otter.canal.client.adapter.support.CanalOuterAdapterConfiguration;
|
||||||
import com.alibaba.otter.canal.client.adapter.support.ExtensionLoader;
|
import com.alibaba.otter.canal.client.adapter.support.ExtensionLoader;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -30,9 +30,9 @@ public class CanalAdapterLoader {
|
|||||||
|
|
||||||
private Map<String, CanalAdapterWorker> canalWorkers = new HashMap<>();
|
private Map<String, CanalAdapterWorker> canalWorkers = new HashMap<>();
|
||||||
|
|
||||||
private ExtensionLoader<CanalOuterAdapter> loader;
|
private ExtensionLoader<OuterAdapter> loader;
|
||||||
|
|
||||||
public CanalAdapterLoader(CanalClientConfig canalClientConfig) {
|
public CanalAdapterLoader(CanalClientConfig canalClientConfig){
|
||||||
this.canalClientConfig = canalClientConfig;
|
this.canalClientConfig = canalClientConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,12 +40,7 @@ public class CanalAdapterLoader {
|
|||||||
* 初始化canal-client
|
* 初始化canal-client
|
||||||
*/
|
*/
|
||||||
public void init() {
|
public void init() {
|
||||||
// canal instances 和 mq topics 配置不能同时为空
|
loader = ExtensionLoader.getExtensionLoader(OuterAdapter.class);
|
||||||
// if (canalClientConfig.getCanalInstances() == null && canalClientConfig.getMqTopics() == null) {
|
|
||||||
// throw new RuntimeException("Blank config property: canalInstances or canalMQTopics");
|
|
||||||
// }
|
|
||||||
|
|
||||||
loader = ExtensionLoader.getExtensionLoader(CanalOuterAdapter.class);
|
|
||||||
|
|
||||||
String canalServerHost = this.canalClientConfig.getCanalServerHost();
|
String canalServerHost = this.canalClientConfig.getCanalServerHost();
|
||||||
SocketAddress sa = null;
|
SocketAddress sa = null;
|
||||||
@@ -58,10 +53,10 @@ public class CanalAdapterLoader {
|
|||||||
// 初始化canal-client的适配器
|
// 初始化canal-client的适配器
|
||||||
if (canalClientConfig.getCanalInstances() != null) {
|
if (canalClientConfig.getCanalInstances() != null) {
|
||||||
for (CanalClientConfig.CanalInstance instance : canalClientConfig.getCanalInstances()) {
|
for (CanalClientConfig.CanalInstance instance : canalClientConfig.getCanalInstances()) {
|
||||||
List<List<CanalOuterAdapter>> canalOuterAdapterGroups = new ArrayList<>();
|
List<List<OuterAdapter>> canalOuterAdapterGroups = new ArrayList<>();
|
||||||
|
|
||||||
for (CanalClientConfig.AdapterGroup connectorGroup : instance.getAdapterGroups()) {
|
for (CanalClientConfig.AdapterGroup connectorGroup : instance.getAdapterGroups()) {
|
||||||
List<CanalOuterAdapter> canalOutConnectors = new ArrayList<>();
|
List<OuterAdapter> canalOutConnectors = new ArrayList<>();
|
||||||
for (CanalOuterAdapterConfiguration c : connectorGroup.getOutAdapters()) {
|
for (CanalOuterAdapterConfiguration c : connectorGroup.getOutAdapters()) {
|
||||||
loadConnector(c, canalOutConnectors);
|
loadConnector(c, canalOutConnectors);
|
||||||
}
|
}
|
||||||
@@ -80,9 +75,9 @@ public class CanalAdapterLoader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadConnector(CanalOuterAdapterConfiguration config, List<CanalOuterAdapter> canalOutConnectors) {
|
private void loadConnector(CanalOuterAdapterConfiguration config, List<OuterAdapter> canalOutConnectors) {
|
||||||
try {
|
try {
|
||||||
CanalOuterAdapter adapter = loader.getExtension(config.getName());
|
OuterAdapter adapter = loader.getExtension(config.getName());
|
||||||
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
||||||
// 替换ClassLoader
|
// 替换ClassLoader
|
||||||
Thread.currentThread().setContextClassLoader(adapter.getClass().getClassLoader());
|
Thread.currentThread().setContextClassLoader(adapter.getClass().getClassLoader());
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package com.alibaba.otter.canal.adapter.launcher.loader;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import javax.annotation.PreDestroy;
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import com.alibaba.druid.pool.DruidDataSource;
|
||||||
|
import com.alibaba.otter.canal.adapter.launcher.config.AdapterCanalConfig;
|
||||||
|
import com.alibaba.otter.canal.adapter.launcher.config.AdapterConfig;
|
||||||
|
import com.alibaba.otter.canal.client.adapter.support.DatasourceConfig;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class CanalAdapterService {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(CanalAdapterService.class);
|
||||||
|
|
||||||
|
private static CanalAdapterLoader adapterLoader;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private AdapterCanalConfig adapterCanalConfig;
|
||||||
|
|
||||||
|
// 注入配置保证配置优先先注册
|
||||||
|
@Resource
|
||||||
|
private AdapterConfig adapterConfig;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
if (adapterLoader == null) {
|
||||||
|
try {
|
||||||
|
logger.info("## start the canal client adapters.");
|
||||||
|
adapterLoader = new CanalAdapterLoader(adapterCanalConfig);
|
||||||
|
adapterLoader.init();
|
||||||
|
logger.info("## the canal client adapters are running now ......");
|
||||||
|
} catch (Throwable e) {
|
||||||
|
logger.error("## something goes wrong when starting up the canal client adapters:", e);
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreDestroy
|
||||||
|
public void destroy() {
|
||||||
|
try {
|
||||||
|
logger.info("## stop the canal client adapters");
|
||||||
|
if (adapterLoader != null) {
|
||||||
|
adapterLoader.destroy();
|
||||||
|
}
|
||||||
|
for (DruidDataSource druidDataSource : DatasourceConfig.DATA_SOURCES.values()) {
|
||||||
|
try {
|
||||||
|
druidDataSource.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
logger.warn("## something goes wrong when stopping canal client adapters:", e);
|
||||||
|
} finally {
|
||||||
|
logger.info("## canal client adapters are down.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,7 +6,7 @@ import java.util.concurrent.Executors;
|
|||||||
|
|
||||||
import com.alibaba.otter.canal.client.CanalConnector;
|
import com.alibaba.otter.canal.client.CanalConnector;
|
||||||
import com.alibaba.otter.canal.client.CanalConnectors;
|
import com.alibaba.otter.canal.client.CanalConnectors;
|
||||||
import com.alibaba.otter.canal.client.adapter.CanalOuterAdapter;
|
import com.alibaba.otter.canal.client.adapter.OuterAdapter;
|
||||||
import com.alibaba.otter.canal.client.impl.ClusterCanalConnector;
|
import com.alibaba.otter.canal.client.impl.ClusterCanalConnector;
|
||||||
import com.alibaba.otter.canal.protocol.Message;
|
import com.alibaba.otter.canal.protocol.Message;
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ public class CanalAdapterWorker extends AbstractCanalAdapterWorker {
|
|||||||
* @param canalOuterAdapters 外部适配器组
|
* @param canalOuterAdapters 外部适配器组
|
||||||
*/
|
*/
|
||||||
public CanalAdapterWorker(String canalDestination, SocketAddress address,
|
public CanalAdapterWorker(String canalDestination, SocketAddress address,
|
||||||
List<List<CanalOuterAdapter>> canalOuterAdapters){
|
List<List<OuterAdapter>> canalOuterAdapters){
|
||||||
this.canalOuterAdapters = canalOuterAdapters;
|
this.canalOuterAdapters = canalOuterAdapters;
|
||||||
this.canalDestination = canalDestination;
|
this.canalDestination = canalDestination;
|
||||||
groupInnerExecutorService = Executors.newFixedThreadPool(canalOuterAdapters.size());
|
groupInnerExecutorService = Executors.newFixedThreadPool(canalOuterAdapters.size());
|
||||||
@@ -46,7 +46,7 @@ public class CanalAdapterWorker extends AbstractCanalAdapterWorker {
|
|||||||
* @param canalOuterAdapters 外部适配器组
|
* @param canalOuterAdapters 外部适配器组
|
||||||
*/
|
*/
|
||||||
public CanalAdapterWorker(String canalDestination, String zookeeperHosts,
|
public CanalAdapterWorker(String canalDestination, String zookeeperHosts,
|
||||||
List<List<CanalOuterAdapter>> canalOuterAdapters){
|
List<List<OuterAdapter>> canalOuterAdapters){
|
||||||
this.canalOuterAdapters = canalOuterAdapters;
|
this.canalOuterAdapters = canalOuterAdapters;
|
||||||
this.canalDestination = canalDestination;
|
this.canalDestination = canalDestination;
|
||||||
groupInnerExecutorService = Executors.newFixedThreadPool(canalOuterAdapters.size());
|
groupInnerExecutorService = Executors.newFixedThreadPool(canalOuterAdapters.size());
|
||||||
@@ -96,8 +96,8 @@ public class CanalAdapterWorker extends AbstractCanalAdapterWorker {
|
|||||||
}
|
}
|
||||||
groupInnerExecutorService.shutdown();
|
groupInnerExecutorService.shutdown();
|
||||||
logger.info("destination {} adapters' worker thread dead!", canalDestination);
|
logger.info("destination {} adapters' worker thread dead!", canalDestination);
|
||||||
for (List<CanalOuterAdapter> outerAdapters : canalOuterAdapters) {
|
for (List<OuterAdapter> outerAdapters : canalOuterAdapters) {
|
||||||
for (CanalOuterAdapter adapter : outerAdapters) {
|
for (OuterAdapter adapter : outerAdapters) {
|
||||||
adapter.destroy();
|
adapter.destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,11 @@ canal.conf:
|
|||||||
# hosts: slave1:2181
|
# hosts: slave1:2181
|
||||||
# properties: {znodeParent: "/hbase-unsecure"}
|
# properties: {znodeParent: "/hbase-unsecure"}
|
||||||
|
|
||||||
adapter.conf.path:
|
adapter.conf:
|
||||||
|
datasourceConfigs:
|
||||||
|
defaultDS:
|
||||||
|
url: jdbc:mysql://127.0.0.1:3306/mytest?useUnicode=true
|
||||||
|
username: root
|
||||||
|
password: 121212
|
||||||
adapterConfigs:
|
adapterConfigs:
|
||||||
- hbase/mytest_person2.yml
|
- hbase/mytest_person2.yml
|
||||||
@@ -3,7 +3,7 @@ package com.alibaba.otter.canal.client.adapter.logger;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.alibaba.otter.canal.client.adapter.CanalOuterAdapter;
|
import com.alibaba.otter.canal.client.adapter.OuterAdapter;
|
||||||
import com.alibaba.otter.canal.client.adapter.support.CanalOuterAdapterConfiguration;
|
import com.alibaba.otter.canal.client.adapter.support.CanalOuterAdapterConfiguration;
|
||||||
import com.alibaba.otter.canal.client.adapter.support.Dml;
|
import com.alibaba.otter.canal.client.adapter.support.Dml;
|
||||||
import com.alibaba.otter.canal.client.adapter.support.SPI;
|
import com.alibaba.otter.canal.client.adapter.support.SPI;
|
||||||
@@ -16,7 +16,7 @@ import com.alibaba.otter.canal.client.adapter.support.SPI;
|
|||||||
*/
|
*/
|
||||||
@SPI("logger")
|
@SPI("logger")
|
||||||
// logger参数对应CanalOuterAdapterConfiguration配置中的name
|
// logger参数对应CanalOuterAdapterConfiguration配置中的name
|
||||||
public class LoggerAdapterExample implements CanalOuterAdapter {
|
public class LoggerAdapterExample implements OuterAdapter {
|
||||||
|
|
||||||
private Logger logger = LoggerFactory.getLogger(this.getClass());
|
private Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ public class LoggerAdapterExample implements CanalOuterAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeOut(Dml dml) {
|
public void sync(Dml dml) {
|
||||||
logger.info(dml.toString());
|
logger.info(dml.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user