mirror of
https://github.com/alibaba/canal.git
synced 2026-11-04 00:30:15 +08:00
adapter代码整理优化
This commit is contained in:
@@ -27,7 +27,7 @@ public class EtlLock {
|
||||
|
||||
private static final Map<String, InterProcessMutex> DISTRIBUTED_LOCK = new ConcurrentHashMap<>();
|
||||
|
||||
private static Mode mode = Mode.LOCAL;
|
||||
private Mode mode = Mode.LOCAL;
|
||||
|
||||
@Resource
|
||||
private CuratorClient curatorClient;
|
||||
|
||||
@@ -34,7 +34,7 @@ public class SyncSwitch {
|
||||
|
||||
private static final Map<String, BooleanMutex> DISTRIBUTED_LOCK = new ConcurrentHashMap<>();
|
||||
|
||||
private static Mode mode = Mode.LOCAL;
|
||||
private Mode mode = Mode.LOCAL;
|
||||
|
||||
@Resource
|
||||
private AdapterCanalConfig adapterCanalConfig;
|
||||
@@ -165,20 +165,20 @@ public class SyncSwitch {
|
||||
}
|
||||
}
|
||||
|
||||
public Boolean status(String destination) {
|
||||
public boolean status(String destination) {
|
||||
if (mode == Mode.LOCAL) {
|
||||
BooleanMutex mutex = LOCAL_LOCK.get(destination);
|
||||
if (mutex != null) {
|
||||
return mutex.state();
|
||||
} else {
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
BooleanMutex mutex = DISTRIBUTED_LOCK.get(destination);
|
||||
if (mutex != null) {
|
||||
return mutex.state();
|
||||
} else {
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,7 @@ package com.alibaba.otter.canal.adapter.launcher.loader;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -43,7 +40,21 @@ public abstract class AbstractCanalAdapterWorker {
|
||||
|
||||
public AbstractCanalAdapterWorker(List<List<OuterAdapter>> canalOuterAdapters){
|
||||
this.canalOuterAdapters = canalOuterAdapters;
|
||||
this.groupInnerExecutorService = Executors.newFixedThreadPool(canalOuterAdapters.size());
|
||||
int adaptersSize = canalOuterAdapters.size();
|
||||
this.groupInnerExecutorService = new ThreadPoolExecutor(adaptersSize,
|
||||
adaptersSize,
|
||||
5000L,
|
||||
TimeUnit.MILLISECONDS,
|
||||
new SynchronousQueue<>(),
|
||||
(r, exe) -> {
|
||||
if (!exe.isShutdown()) {
|
||||
try {
|
||||
exe.getQueue().put(r);
|
||||
} catch (InterruptedException e1) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
});
|
||||
syncSwitch = (SyncSwitch) SpringContext.getBean(SyncSwitch.class);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package com.alibaba.otter.canal.adapter.launcher.loader;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
import org.apache.kafka.common.errors.WakeupException;
|
||||
|
||||
@@ -44,12 +42,22 @@ public class CanalAdapterKafkaWorker extends AbstractCanalAdapterWorker {
|
||||
protected void process() {
|
||||
while (!running) {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
Thread.sleep(500);
|
||||
} catch (InterruptedException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
ExecutorService workerExecutor = Executors.newSingleThreadExecutor();
|
||||
ExecutorService workerExecutor = new ThreadPoolExecutor(1, 1,
|
||||
5000L, TimeUnit.MILLISECONDS,
|
||||
new SynchronousQueue<>(), (r, exe) -> {
|
||||
if (!exe.isShutdown()) {
|
||||
try {
|
||||
exe.getQueue().put(r);
|
||||
} catch (InterruptedException e1) {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
});
|
||||
int retry = canalClientConfig.getRetries() == null
|
||||
|| canalClientConfig.getRetries() == 0 ? 1 : canalClientConfig.getRetries();
|
||||
long timeout = canalClientConfig.getTimeout() == null ? 30000 : canalClientConfig.getTimeout(); // 默认超时30秒
|
||||
@@ -63,8 +71,8 @@ public class CanalAdapterKafkaWorker extends AbstractCanalAdapterWorker {
|
||||
connector.subscribe();
|
||||
logger.info("=============> Subscribe topic: {} succeed <=============", this.topic);
|
||||
while (running) {
|
||||
Boolean status = syncSwitch.status(canalDestination);
|
||||
if (status != null && !status) {
|
||||
boolean status = syncSwitch.status(canalDestination);
|
||||
if (!status) {
|
||||
connector.disconnect();
|
||||
break;
|
||||
}
|
||||
@@ -85,6 +93,8 @@ public class CanalAdapterKafkaWorker extends AbstractCanalAdapterWorker {
|
||||
}
|
||||
}
|
||||
|
||||
workerExecutor.shutdown();
|
||||
|
||||
try {
|
||||
connector.unsubscribe();
|
||||
} catch (WakeupException e) {
|
||||
|
||||
@@ -5,7 +5,7 @@ import java.net.SocketAddress;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
@@ -176,40 +176,32 @@ public class CanalAdapterLoader {
|
||||
public void destroy() {
|
||||
if (!canalWorkers.isEmpty()) {
|
||||
ExecutorService stopExecutorService = Executors.newFixedThreadPool(canalWorkers.size());
|
||||
List<Future<Boolean>> futures = new ArrayList<>();
|
||||
for (CanalAdapterWorker canalAdapterWorker : canalWorkers.values()) {
|
||||
futures.add(stopExecutorService.submit(() -> {
|
||||
canalAdapterWorker.stop();
|
||||
return true;
|
||||
}));
|
||||
stopExecutorService.execute(canalAdapterWorker::stop);
|
||||
}
|
||||
futures.forEach(future -> {
|
||||
try {
|
||||
future.get();
|
||||
} catch (Exception e) {
|
||||
stopExecutorService.shutdown();
|
||||
try {
|
||||
while (!stopExecutorService.awaitTermination(1, TimeUnit.SECONDS)) {
|
||||
// ignore
|
||||
}
|
||||
});
|
||||
stopExecutorService.shutdown();
|
||||
} catch (InterruptedException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
if (!canalMQWorker.isEmpty()) {
|
||||
ExecutorService stopMQWorkerService = Executors.newFixedThreadPool(canalMQWorker.size());
|
||||
List<Future<Boolean>> futures = new ArrayList<>();
|
||||
for (AbstractCanalAdapterWorker canalAdapterMQWorker : canalMQWorker.values()) {
|
||||
futures.add(stopMQWorkerService.submit(() -> {
|
||||
canalAdapterMQWorker.stop();
|
||||
return true;
|
||||
}));
|
||||
stopMQWorkerService.execute(canalAdapterMQWorker::stop);
|
||||
}
|
||||
futures.forEach(future -> {
|
||||
try {
|
||||
future.get();
|
||||
} catch (Exception e) {
|
||||
stopMQWorkerService.shutdown();
|
||||
try {
|
||||
while (!stopMQWorkerService.awaitTermination(1, TimeUnit.SECONDS)) {
|
||||
// ignore
|
||||
}
|
||||
});
|
||||
stopMQWorkerService.shutdown();
|
||||
} catch (InterruptedException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
logger.info("All canal adapters destroyed");
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
package com.alibaba.otter.canal.adapter.launcher.loader;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
import org.apache.kafka.common.errors.WakeupException;
|
||||
|
||||
@@ -49,8 +48,22 @@ public class CanalAdapterRocketMQWorker extends AbstractCanalAdapterWorker {
|
||||
}
|
||||
}
|
||||
|
||||
ExecutorService workerExecutor = Executors.newSingleThreadExecutor();
|
||||
int retry = canalClientConfig.getRetries() == null || canalClientConfig.getRetries() == 0 ? 1 : canalClientConfig.getRetries();
|
||||
ExecutorService workerExecutor = new ThreadPoolExecutor(1,
|
||||
1,
|
||||
5000L,
|
||||
TimeUnit.MILLISECONDS,
|
||||
new SynchronousQueue<>(),
|
||||
(r, exe) -> {
|
||||
if (!exe.isShutdown()) {
|
||||
try {
|
||||
exe.getQueue().put(r);
|
||||
} catch (InterruptedException e1) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
});
|
||||
int retry = canalClientConfig.getRetries() == null
|
||||
|| canalClientConfig.getRetries() == 0 ? 1 : canalClientConfig.getRetries();
|
||||
long timeout = canalClientConfig.getTimeout() == null ? 30000 : canalClientConfig.getTimeout(); // 默认超时30秒
|
||||
|
||||
while (running) {
|
||||
@@ -62,8 +75,8 @@ public class CanalAdapterRocketMQWorker extends AbstractCanalAdapterWorker {
|
||||
connector.subscribe();
|
||||
logger.info("=============> Subscribe topic: {} succeed<=============", this.topic);
|
||||
while (running) {
|
||||
Boolean status = syncSwitch.status(canalDestination);
|
||||
if (status != null && !status) {
|
||||
boolean status = syncSwitch.status(canalDestination);
|
||||
if (!status) {
|
||||
connector.disconnect();
|
||||
break;
|
||||
}
|
||||
@@ -84,6 +97,8 @@ public class CanalAdapterRocketMQWorker extends AbstractCanalAdapterWorker {
|
||||
}
|
||||
}
|
||||
|
||||
workerExecutor.shutdown();
|
||||
|
||||
try {
|
||||
connector.unsubscribe();
|
||||
} catch (WakeupException e) {
|
||||
|
||||
@@ -140,7 +140,7 @@ public class CanalAdapterWorker extends AbstractCanalAdapterWorker {
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
logger.error("process error!", e);
|
||||
} finally {
|
||||
connector.disconnect();
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package com.alibaba.otter.canal.adapter.launcher.monitor;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
@@ -68,7 +70,7 @@ public class ApplicationConfigMonitor {
|
||||
super.onFileChange(file);
|
||||
try {
|
||||
// 检查yml格式
|
||||
new Yaml().loadAs(new FileReader(file), Map.class);
|
||||
new Yaml().loadAs(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8), Map.class);
|
||||
|
||||
canalAdapterService.destroy();
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.alibaba.otter.canal.adapter.launcher.monitor.remote;
|
||||
|
||||
import java.io.FileWriter;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
@@ -35,7 +37,7 @@ public class DbRemoteConfigLoader implements RemoteConfigLoader {
|
||||
|
||||
private DruidDataSource dataSource;
|
||||
|
||||
private static volatile long currentConfigTimestamp = 0;
|
||||
private volatile long currentConfigTimestamp = 0;
|
||||
private Map<String, ConfigItem> remoteAdapterConfigs = new MapMaker().makeMap();
|
||||
|
||||
private ScheduledExecutorService executor = Executors.newScheduledThreadPool(2,
|
||||
@@ -115,7 +117,10 @@ public class DbRemoteConfigLoader implements RemoteConfigLoader {
|
||||
* @param content 文件内容
|
||||
*/
|
||||
private void overrideLocalCanalConfig(String content) {
|
||||
try (FileWriter writer = new FileWriter(CommonUtils.getConfPath() + "application.yml")) {
|
||||
|
||||
try (OutputStreamWriter writer = new OutputStreamWriter(
|
||||
new FileOutputStream(CommonUtils.getConfPath() + "application.yml"),
|
||||
StandardCharsets.UTF_8)) {
|
||||
writer.write(content);
|
||||
writer.flush();
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
package com.alibaba.otter.canal.adapter.launcher.monitor.remote;
|
||||
|
||||
import com.alibaba.otter.canal.common.utils.CommonUtils;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import com.alibaba.otter.canal.common.utils.CommonUtils;
|
||||
|
||||
/**
|
||||
* 远程配置监听器实现
|
||||
@@ -35,7 +38,9 @@ public class RemoteAdapterMonitorImpl implements RemoteAdapterMonitor {
|
||||
}
|
||||
}
|
||||
String name = configItem.getName();
|
||||
try (FileWriter writer = new FileWriter(confPath + category + "/" + configItem.getName())) {
|
||||
try (OutputStreamWriter writer = new OutputStreamWriter(
|
||||
new FileOutputStream(confPath + category + "/" + configItem.getName()),
|
||||
StandardCharsets.UTF_8)) {
|
||||
writer.write(configItem.getContent());
|
||||
writer.flush();
|
||||
logger.info("## Loaded remote adapter config: {}/{}", category, name);
|
||||
|
||||
@@ -69,16 +69,16 @@ public class CommonRest {
|
||||
}
|
||||
try {
|
||||
|
||||
Boolean oriSwitchStatus;
|
||||
boolean oriSwitchStatus;
|
||||
if (destination != null) {
|
||||
oriSwitchStatus = syncSwitch.status(destination);
|
||||
if (oriSwitchStatus != null && oriSwitchStatus) {
|
||||
if (oriSwitchStatus) {
|
||||
syncSwitch.off(destination);
|
||||
}
|
||||
} else {
|
||||
// task可能为destination,直接锁task
|
||||
oriSwitchStatus = syncSwitch.status(task);
|
||||
if (oriSwitchStatus != null && oriSwitchStatus) {
|
||||
if (oriSwitchStatus) {
|
||||
syncSwitch.off(task);
|
||||
}
|
||||
}
|
||||
@@ -89,9 +89,9 @@ public class CommonRest {
|
||||
}
|
||||
return adapter.etl(task, paramArray);
|
||||
} finally {
|
||||
if (destination != null && oriSwitchStatus != null && oriSwitchStatus) {
|
||||
if (destination != null && oriSwitchStatus) {
|
||||
syncSwitch.on(destination);
|
||||
} else if (destination == null && oriSwitchStatus != null && oriSwitchStatus) {
|
||||
} else if (destination == null && oriSwitchStatus) {
|
||||
syncSwitch.on(task);
|
||||
}
|
||||
}
|
||||
@@ -102,7 +102,7 @@ public class CommonRest {
|
||||
|
||||
/**
|
||||
* ETL curl http://127.0.0.1:8081/etl/hbase/mytest_person2.yml -X POST
|
||||
*
|
||||
*
|
||||
* @param type 类型 hbase, es
|
||||
* @param task 任务名对应配置文件名 mytest_person2.yml
|
||||
* @param params etl where条件参数, 为空全部导入
|
||||
@@ -129,7 +129,7 @@ public class CommonRest {
|
||||
|
||||
/**
|
||||
* 统计总数 curl http://127.0.0.1:8081/count/hbase/mytest_person2.yml
|
||||
*
|
||||
*
|
||||
* @param type 类型 hbase, es
|
||||
* @param task 任务名对应配置文件名 mytest_person2.yml
|
||||
* @return
|
||||
@@ -148,11 +148,11 @@ public class CommonRest {
|
||||
Set<String> destinations = adapterCanalConfig.DESTINATIONS;
|
||||
for (String destination : destinations) {
|
||||
Map<String, String> resMap = new LinkedHashMap<>();
|
||||
Boolean status = syncSwitch.status(destination);
|
||||
String resStatus = "none";
|
||||
if (status != null && status) {
|
||||
boolean status = syncSwitch.status(destination);
|
||||
String resStatus;
|
||||
if (status) {
|
||||
resStatus = "on";
|
||||
} else if (status != null && !status) {
|
||||
} else {
|
||||
resStatus = "off";
|
||||
}
|
||||
resMap.put("destination", destination);
|
||||
@@ -164,7 +164,7 @@ public class CommonRest {
|
||||
|
||||
/**
|
||||
* 实例同步开关 curl http://127.0.0.1:8081/syncSwitch/example/off -X PUT
|
||||
*
|
||||
*
|
||||
* @param destination 实例名称
|
||||
* @param status 开关状态: off on
|
||||
* @return
|
||||
@@ -189,17 +189,17 @@ public class CommonRest {
|
||||
|
||||
/**
|
||||
* 获取实例开关状态 curl http://127.0.0.1:8081/syncSwitch/example
|
||||
*
|
||||
*
|
||||
* @param destination 实例名称
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/syncSwitch/{destination}")
|
||||
public Map<String, String> etl(@PathVariable String destination) {
|
||||
Boolean status = syncSwitch.status(destination);
|
||||
String resStatus = "none";
|
||||
if (status != null && status) {
|
||||
boolean status = syncSwitch.status(destination);
|
||||
String resStatus;
|
||||
if (status) {
|
||||
resStatus = "on";
|
||||
} else if (status != null && !status) {
|
||||
} else {
|
||||
resStatus = "off";
|
||||
}
|
||||
Map<String, String> res = new LinkedHashMap<>();
|
||||
|
||||
Reference in New Issue
Block a user