mirror of
https://github.com/alibaba/canal.git
synced 2026-11-04 00:30:15 +08:00
fixed admin
This commit is contained in:
@@ -0,0 +1,17 @@
|
|||||||
|
package com.alibaba.otter.canal.admin.common;
|
||||||
|
|
||||||
|
import java.util.concurrent.ArrayBlockingQueue;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
public class Threads {
|
||||||
|
|
||||||
|
public static int pool = 60;
|
||||||
|
public static final ExecutorService executorService = new ThreadPoolExecutor(pool,
|
||||||
|
pool,
|
||||||
|
0L,
|
||||||
|
TimeUnit.MILLISECONDS,
|
||||||
|
new ArrayBlockingQueue<Runnable>(pool * 20),
|
||||||
|
DaemonThreadFactory.daemonThreadFactory);
|
||||||
|
}
|
||||||
@@ -54,13 +54,6 @@ public interface AdminConnector {
|
|||||||
*/
|
*/
|
||||||
boolean restart();
|
boolean restart();
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取所有当前节点下所有实例
|
|
||||||
*
|
|
||||||
* @return 实例信息
|
|
||||||
*/
|
|
||||||
String getInstances();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取所有当前节点下运行中的实例
|
* 获取所有当前节点下运行中的实例
|
||||||
*
|
*
|
||||||
@@ -92,6 +85,14 @@ public interface AdminConnector {
|
|||||||
*/
|
*/
|
||||||
boolean stopInstance(String destination);
|
boolean stopInstance(String destination);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过实例名释放,主要针对cluster模式有效(通知当前主机释放instance运行交给其他人来抢占)
|
||||||
|
*
|
||||||
|
* @param destination 实例名
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
boolean releaseInstance(String destination);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过实例名重启实例
|
* 通过实例名重启实例
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -156,11 +156,6 @@ public class SimpleAdminConnector implements AdminConnector {
|
|||||||
return BooleanUtils.toBoolean(Integer.parseInt(doServerAdmin("restart")));
|
return BooleanUtils.toBoolean(Integer.parseInt(doServerAdmin("restart")));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getInstances() {
|
|
||||||
return doServerAdmin("instances");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getRunningInstances() {
|
public String getRunningInstances() {
|
||||||
return doServerAdmin("list");
|
return doServerAdmin("list");
|
||||||
@@ -181,6 +176,11 @@ public class SimpleAdminConnector implements AdminConnector {
|
|||||||
return BooleanUtils.toBoolean(Integer.parseInt(doInstanceAdmin(destination, "stop")));
|
return BooleanUtils.toBoolean(Integer.parseInt(doInstanceAdmin(destination, "stop")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean releaseInstance(String destination) {
|
||||||
|
return BooleanUtils.toBoolean(Integer.parseInt(doInstanceAdmin(destination, "release")));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean restartInstance(String destination) {
|
public boolean restartInstance(String destination) {
|
||||||
return BooleanUtils.toBoolean(Integer.parseInt(doInstanceAdmin(destination, "restart")));
|
return BooleanUtils.toBoolean(Integer.parseInt(doInstanceAdmin(destination, "restart")));
|
||||||
@@ -232,8 +232,11 @@ public class SimpleAdminConnector implements AdminConnector {
|
|||||||
try {
|
try {
|
||||||
writeWithHeader(Packet.newBuilder()
|
writeWithHeader(Packet.newBuilder()
|
||||||
.setType(PacketType.INSTANCE)
|
.setType(PacketType.INSTANCE)
|
||||||
.setBody(
|
.setBody(InstanceAdmin.newBuilder()
|
||||||
InstanceAdmin.newBuilder().setDestination(destination).setAction(action).build().toByteString())
|
.setDestination(destination)
|
||||||
|
.setAction(action)
|
||||||
|
.build()
|
||||||
|
.toByteString())
|
||||||
.build()
|
.build()
|
||||||
.toByteArray());
|
.toByteArray());
|
||||||
|
|
||||||
|
|||||||
@@ -162,6 +162,6 @@ public class CanalInstanceController {
|
|||||||
*/
|
*/
|
||||||
@GetMapping(value = "/active/instances/{serverId}")
|
@GetMapping(value = "/active/instances/{serverId}")
|
||||||
public BaseModel<List<CanalInstanceConfig>> activeInstances(@PathVariable Long serverId, @PathVariable String env) {
|
public BaseModel<List<CanalInstanceConfig>> activeInstances(@PathVariable Long serverId, @PathVariable String env) {
|
||||||
return BaseModel.getInstance(canalInstanceConfigService.findActiveInstanceByServerId(serverId));
|
return BaseModel.getInstance(canalInstanceConfigService.findActiveInstaceByServerId(serverId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,15 @@
|
|||||||
package com.alibaba.otter.canal.admin.controller;
|
package com.alibaba.otter.canal.admin.controller;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PutMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import com.alibaba.otter.canal.admin.model.BaseModel;
|
import com.alibaba.otter.canal.admin.model.BaseModel;
|
||||||
import com.alibaba.otter.canal.admin.model.NodeServer;
|
import com.alibaba.otter.canal.admin.model.NodeServer;
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ public interface CanalInstanceService {
|
|||||||
|
|
||||||
CanalInstanceConfig detail(Long id);
|
CanalInstanceConfig detail(Long id);
|
||||||
|
|
||||||
|
CanalInstanceConfig findOne(String name);
|
||||||
|
|
||||||
void updateContent(CanalInstanceConfig canalInstanceConfig);
|
void updateContent(CanalInstanceConfig canalInstanceConfig);
|
||||||
|
|
||||||
void delete(Long id);
|
void delete(Long id);
|
||||||
@@ -30,5 +32,5 @@ public interface CanalInstanceService {
|
|||||||
|
|
||||||
boolean instanceOperation(Long id, String option);
|
boolean instanceOperation(Long id, String option);
|
||||||
|
|
||||||
List<CanalInstanceConfig> findActiveInstanceByServerId(Long serverId);
|
List<CanalInstanceConfig> findActiveInstaceByServerId(Long serverId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
package com.alibaba.otter.canal.admin.service.impl;
|
package com.alibaba.otter.canal.admin.service.impl;
|
||||||
|
|
||||||
|
import io.ebean.Query;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.alibaba.otter.canal.admin.common.exception.ServiceException;
|
|
||||||
import com.alibaba.otter.canal.admin.model.CanalInstanceConfig;
|
|
||||||
import com.alibaba.otter.canal.admin.model.NodeServer;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import com.alibaba.otter.canal.admin.common.exception.ServiceException;
|
||||||
import com.alibaba.otter.canal.admin.model.CanalCluster;
|
import com.alibaba.otter.canal.admin.model.CanalCluster;
|
||||||
|
import com.alibaba.otter.canal.admin.model.NodeServer;
|
||||||
import com.alibaba.otter.canal.admin.service.CanalClusterServic;
|
import com.alibaba.otter.canal.admin.service.CanalClusterServic;
|
||||||
|
|
||||||
import io.ebean.Query;
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class CanalClusterServiceImpl implements CanalClusterServic {
|
public class CanalClusterServiceImpl implements CanalClusterServic {
|
||||||
|
|
||||||
@@ -31,16 +30,10 @@ public class CanalClusterServiceImpl implements CanalClusterServic {
|
|||||||
// 判断集群下是否存在server信息
|
// 判断集群下是否存在server信息
|
||||||
int serverCnt = NodeServer.find.query().where().eq("clusterId", id).findCount();
|
int serverCnt = NodeServer.find.query().where().eq("clusterId", id).findCount();
|
||||||
if (serverCnt > 0) {
|
if (serverCnt > 0) {
|
||||||
throw new ServiceException("Servers exist, delete failed");
|
throw new ServiceException("当前集群下存在Server, 无法删除");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 判断集群下是否存在instance信息
|
CanalCluster canalCluster = CanalCluster.find.byId(id);
|
||||||
int instanceCnt = CanalInstanceConfig.find.query().where().eq("clusterId", id).findCount();
|
|
||||||
if (instanceCnt > 0) {
|
|
||||||
throw new ServiceException("Instances exist, delete failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
CanalCluster canalCluster = CanalCluster.find.byId(id);
|
|
||||||
if (canalCluster != null) {
|
if (canalCluster != null) {
|
||||||
canalCluster.delete();
|
canalCluster.delete();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,19 +5,17 @@ import java.io.InputStream;
|
|||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import com.alibaba.otter.canal.admin.common.exception.ServiceException;
|
|
||||||
import com.alibaba.otter.canal.admin.model.CanalCluster;
|
|
||||||
import com.alibaba.otter.canal.admin.model.NodeServer;
|
|
||||||
import com.alibaba.otter.canal.protocol.SecurityUtil;
|
|
||||||
import io.ebean.Query;
|
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import com.alibaba.otter.canal.admin.common.exception.ServiceException;
|
||||||
import com.alibaba.otter.canal.admin.model.CanalConfig;
|
import com.alibaba.otter.canal.admin.model.CanalConfig;
|
||||||
|
import com.alibaba.otter.canal.admin.model.NodeServer;
|
||||||
import com.alibaba.otter.canal.admin.service.CanalConfigService;
|
import com.alibaba.otter.canal.admin.service.CanalConfigService;
|
||||||
|
import com.alibaba.otter.canal.protocol.SecurityUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Canal配置信息业务层
|
* Canal配置信息业务层
|
||||||
|
|||||||
@@ -1,23 +1,32 @@
|
|||||||
package com.alibaba.otter.canal.admin.service.impl;
|
package com.alibaba.otter.canal.admin.service.impl;
|
||||||
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
import io.ebean.Query;
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.*;
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
import com.alibaba.otter.canal.admin.model.Pager;
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import com.alibaba.otter.canal.admin.common.DaemonThreadFactory;
|
import com.alibaba.otter.canal.admin.common.Threads;
|
||||||
import com.alibaba.otter.canal.admin.common.exception.ServiceException;
|
import com.alibaba.otter.canal.admin.common.exception.ServiceException;
|
||||||
import com.alibaba.otter.canal.admin.connector.AdminConnector;
|
import com.alibaba.otter.canal.admin.connector.AdminConnector;
|
||||||
import com.alibaba.otter.canal.admin.connector.SimpleAdminConnectors;
|
import com.alibaba.otter.canal.admin.connector.SimpleAdminConnectors;
|
||||||
import com.alibaba.otter.canal.admin.model.CanalInstanceConfig;
|
import com.alibaba.otter.canal.admin.model.CanalInstanceConfig;
|
||||||
import com.alibaba.otter.canal.admin.model.NodeServer;
|
import com.alibaba.otter.canal.admin.model.NodeServer;
|
||||||
|
import com.alibaba.otter.canal.admin.model.Pager;
|
||||||
import com.alibaba.otter.canal.admin.service.CanalInstanceService;
|
import com.alibaba.otter.canal.admin.service.CanalInstanceService;
|
||||||
import com.alibaba.otter.canal.protocol.SecurityUtil;
|
import com.alibaba.otter.canal.protocol.SecurityUtil;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
import io.ebean.Query;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Canal实例配置信息业务层
|
* Canal实例配置信息业务层
|
||||||
@@ -28,8 +37,7 @@ import io.ebean.Query;
|
|||||||
@Service
|
@Service
|
||||||
public class CanalInstanceServiceImpl implements CanalInstanceService {
|
public class CanalInstanceServiceImpl implements CanalInstanceService {
|
||||||
|
|
||||||
public Pager<CanalInstanceConfig> findList(CanalInstanceConfig canalInstanceConfig,
|
public Pager<CanalInstanceConfig> findList(CanalInstanceConfig canalInstanceConfig, Pager<CanalInstanceConfig> pager) {
|
||||||
Pager<CanalInstanceConfig> pager) {
|
|
||||||
Query<CanalInstanceConfig> query = CanalInstanceConfig.find.query()
|
Query<CanalInstanceConfig> query = CanalInstanceConfig.find.query()
|
||||||
.setDisableLazyLoading(true)
|
.setDisableLazyLoading(true)
|
||||||
.select("clusterId, serverId, name, modifiedTime")
|
.select("clusterId, serverId, name, modifiedTime")
|
||||||
@@ -62,12 +70,9 @@ public class CanalInstanceServiceImpl implements CanalInstanceService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check all canal instances running status
|
// check all canal instances running status
|
||||||
ExecutorService executorService = Executors.newFixedThreadPool(canalInstanceConfigs.size(),
|
|
||||||
DaemonThreadFactory.daemonThreadFactory);
|
|
||||||
List<Future<Void>> futures = new ArrayList<>(canalInstanceConfigs.size());
|
List<Future<Void>> futures = new ArrayList<>(canalInstanceConfigs.size());
|
||||||
|
|
||||||
for (CanalInstanceConfig canalInstanceConfig1 : canalInstanceConfigs) {
|
for (CanalInstanceConfig canalInstanceConfig1 : canalInstanceConfigs) {
|
||||||
futures.add(executorService.submit(() -> {
|
futures.add(Threads.executorService.submit(() -> {
|
||||||
List<NodeServer> nodeServers;
|
List<NodeServer> nodeServers;
|
||||||
if (canalInstanceConfig1.getClusterId() != null) { // 集群模式
|
if (canalInstanceConfig1.getClusterId() != null) { // 集群模式
|
||||||
nodeServers = NodeServer.find.query()
|
nodeServers = NodeServer.find.query()
|
||||||
@@ -81,15 +86,17 @@ public class CanalInstanceServiceImpl implements CanalInstanceService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (NodeServer nodeServer : nodeServers) {
|
for (NodeServer nodeServer : nodeServers) {
|
||||||
String runningInstances = SimpleAdminConnectors
|
String runningInstances = SimpleAdminConnectors.execute(nodeServer.getIp(),
|
||||||
.execute(nodeServer.getIp(), nodeServer.getAdminPort(), AdminConnector::getRunningInstances);
|
nodeServer.getAdminPort(),
|
||||||
|
AdminConnector::getRunningInstances);
|
||||||
if (runningInstances == null) {
|
if (runningInstances == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
String[] instances = runningInstances.split(",");
|
String[] instances = runningInstances.split(",");
|
||||||
for (String instance : instances) {
|
for (String instance : instances) {
|
||||||
if (instance.equals(canalInstanceConfig1.getName())) {
|
if (instance.equals(canalInstanceConfig1.getName())) {
|
||||||
if (canalInstanceConfig1.getNodeServer() == null) { // 集群模式下 server 对象为空
|
// 集群模式下server对象为空
|
||||||
|
if (canalInstanceConfig1.getNodeServer() == null) {
|
||||||
canalInstanceConfig1.setNodeServer(nodeServer);
|
canalInstanceConfig1.setNodeServer(nodeServer);
|
||||||
}
|
}
|
||||||
canalInstanceConfig1.setRunningStatus("1");
|
canalInstanceConfig1.setRunningStatus("1");
|
||||||
@@ -109,8 +116,6 @@ public class CanalInstanceServiceImpl implements CanalInstanceService {
|
|||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
executorService.shutdownNow();
|
|
||||||
|
|
||||||
return pager;
|
return pager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,29 +124,20 @@ public class CanalInstanceServiceImpl implements CanalInstanceService {
|
|||||||
*
|
*
|
||||||
* @param serverId server id
|
* @param serverId server id
|
||||||
*/
|
*/
|
||||||
public List<CanalInstanceConfig> findActiveInstanceByServerId(Long serverId) {
|
public List<CanalInstanceConfig> findActiveInstaceByServerId(Long serverId) {
|
||||||
NodeServer nodeServer = NodeServer.find.byId(serverId);
|
NodeServer nodeServer = NodeServer.find.byId(serverId);
|
||||||
if (nodeServer == null) {
|
if (nodeServer == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
String runningInstances = SimpleAdminConnectors.execute(nodeServer.getIp(),
|
||||||
String runningInstances = null;
|
nodeServer.getAdminPort(),
|
||||||
if (nodeServer.getClusterId() != null) {// 集群模式
|
AdminConnector::getRunningInstances);
|
||||||
// 只取活动的instances
|
|
||||||
runningInstances = SimpleAdminConnectors
|
|
||||||
.execute(nodeServer.getIp(), nodeServer.getAdminPort(), AdminConnector::getRunningInstances);
|
|
||||||
} else {
|
|
||||||
// 取所属所有instances
|
|
||||||
runningInstances = SimpleAdminConnectors
|
|
||||||
.execute(nodeServer.getIp(), nodeServer.getAdminPort(), AdminConnector::getInstances);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (runningInstances == null) {
|
if (runningInstances == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
String[] instances = runningInstances.split(",");
|
String[] instances = runningInstances.split(",");
|
||||||
|
Object obj[] = Lists.newArrayList(instances).toArray();
|
||||||
// 单机模式和集群模式区分处理
|
// 单机模式和集群模式区分处理
|
||||||
if (nodeServer.getClusterId() != null) { // 集群模式
|
if (nodeServer.getClusterId() != null) { // 集群模式
|
||||||
List<CanalInstanceConfig> list = CanalInstanceConfig.find.query()
|
List<CanalInstanceConfig> list = CanalInstanceConfig.find.query()
|
||||||
@@ -149,7 +145,7 @@ public class CanalInstanceServiceImpl implements CanalInstanceService {
|
|||||||
.select("clusterId, serverId, name, modifiedTime")
|
.select("clusterId, serverId, name, modifiedTime")
|
||||||
.where()
|
.where()
|
||||||
// 暂停的实例也显示 .eq("status", "1")
|
// 暂停的实例也显示 .eq("status", "1")
|
||||||
.in("name", instances)
|
.in("name", obj)
|
||||||
.findList();
|
.findList();
|
||||||
list.forEach(config -> config.setRunningStatus("1"));
|
list.forEach(config -> config.setRunningStatus("1"));
|
||||||
return list; // 集群模式直接返回当前运行的Instances
|
return list; // 集群模式直接返回当前运行的Instances
|
||||||
@@ -237,6 +233,16 @@ public class CanalInstanceServiceImpl implements CanalInstanceService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CanalInstanceConfig findOne(String name) {
|
||||||
|
CanalInstanceConfig config = CanalInstanceConfig.find.query()
|
||||||
|
.setDisableLazyLoading(true)
|
||||||
|
.where()
|
||||||
|
.eq("name", name)
|
||||||
|
.findOne();
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
public Map<String, String> remoteInstanceLog(Long id, Long nodeId) {
|
public Map<String, String> remoteInstanceLog(Long id, Long nodeId) {
|
||||||
Map<String, String> result = new HashMap<>();
|
Map<String, String> result = new HashMap<>();
|
||||||
|
|
||||||
@@ -279,33 +285,19 @@ public class CanalInstanceServiceImpl implements CanalInstanceService {
|
|||||||
if (canalInstanceConfig == null) {
|
if (canalInstanceConfig == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Boolean resutl = null;
|
Boolean result = null;
|
||||||
if ("start".equals(option)) {
|
if ("start".equals(option)) {
|
||||||
if (nodeServer.getClusterId() == null) { // 非集群模式
|
if (nodeServer.getClusterId() == null) { // 非集群模式
|
||||||
return instanceOperation(id, "start");
|
return instanceOperation(id, "start");
|
||||||
// resutl = SimpleAdminConnectors.execute(nodeServer.getIp(),
|
} else {
|
||||||
// nodeServer.getAdminPort(),
|
throw new ServiceException("集群模式不允许指定server启动");
|
||||||
// adminConnector ->
|
|
||||||
// adminConnector.startInstance(canalInstanceConfig.getName()));
|
|
||||||
}
|
}
|
||||||
} else if ("stop".equals(option)) {
|
} else if ("stop".equals(option)) {
|
||||||
if (nodeServer.getClusterId() != null) {
|
if (nodeServer.getClusterId() != null) {
|
||||||
resutl = SimpleAdminConnectors.execute(nodeServer.getIp(),
|
// 集群模式,通知主动释放
|
||||||
|
result = SimpleAdminConnectors.execute(nodeServer.getIp(),
|
||||||
nodeServer.getAdminPort(),
|
nodeServer.getAdminPort(),
|
||||||
adminConnector -> adminConnector.stopInstance(canalInstanceConfig.getName()));
|
adminConnector -> adminConnector.releaseInstance(canalInstanceConfig.getName()));
|
||||||
|
|
||||||
NodeServer nodeServerTmp = nodeServer;
|
|
||||||
// 集群模式下停止实例后过五秒钟再次启动进行启动抢占
|
|
||||||
Thread thread = new Thread(() -> {
|
|
||||||
try {
|
|
||||||
Thread.sleep(5000);
|
|
||||||
SimpleAdminConnectors.execute(nodeServerTmp.getIp(),
|
|
||||||
nodeServerTmp.getAdminPort(),
|
|
||||||
adminConnector -> adminConnector.startInstance(canalInstanceConfig.getName()));
|
|
||||||
} catch (Throwable e) {
|
|
||||||
}
|
|
||||||
});
|
|
||||||
thread.start();
|
|
||||||
} else { // 非集群模式下直接将状态置为0
|
} else { // 非集群模式下直接将状态置为0
|
||||||
return instanceOperation(id, "stop");
|
return instanceOperation(id, "stop");
|
||||||
}
|
}
|
||||||
@@ -313,10 +305,10 @@ public class CanalInstanceServiceImpl implements CanalInstanceService {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resutl == null) {
|
if (result == null) {
|
||||||
resutl = false;
|
result = false;
|
||||||
}
|
}
|
||||||
return resutl;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean instanceOperation(Long id, String option) {
|
public boolean instanceOperation(Long id, String option) {
|
||||||
|
|||||||
@@ -1,19 +1,25 @@
|
|||||||
package com.alibaba.otter.canal.admin.service.impl;
|
package com.alibaba.otter.canal.admin.service.impl;
|
||||||
|
|
||||||
import com.alibaba.otter.canal.admin.common.DaemonThreadFactory;
|
|
||||||
import com.alibaba.otter.canal.admin.model.*;
|
|
||||||
import io.ebean.Query;
|
import io.ebean.Query;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import com.alibaba.otter.canal.admin.common.Threads;
|
||||||
import com.alibaba.otter.canal.admin.common.exception.ServiceException;
|
import com.alibaba.otter.canal.admin.common.exception.ServiceException;
|
||||||
import com.alibaba.otter.canal.admin.connector.AdminConnector;
|
import com.alibaba.otter.canal.admin.connector.AdminConnector;
|
||||||
import com.alibaba.otter.canal.admin.connector.SimpleAdminConnectors;
|
import com.alibaba.otter.canal.admin.connector.SimpleAdminConnectors;
|
||||||
|
import com.alibaba.otter.canal.admin.model.CanalConfig;
|
||||||
|
import com.alibaba.otter.canal.admin.model.CanalInstanceConfig;
|
||||||
|
import com.alibaba.otter.canal.admin.model.NodeServer;
|
||||||
|
import com.alibaba.otter.canal.admin.model.Pager;
|
||||||
import com.alibaba.otter.canal.admin.service.NodeServerService;
|
import com.alibaba.otter.canal.admin.service.NodeServerService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -123,12 +129,10 @@ public class NodeServerServiceImpl implements NodeServerService {
|
|||||||
return pager;
|
return pager;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExecutorService executorService = Executors.newFixedThreadPool(nodeServers.size(),
|
|
||||||
DaemonThreadFactory.daemonThreadFactory);
|
|
||||||
List<Future<Boolean>> futures = new ArrayList<>(nodeServers.size());
|
List<Future<Boolean>> futures = new ArrayList<>(nodeServers.size());
|
||||||
// get all nodes status
|
// get all nodes status
|
||||||
for (NodeServer ns : nodeServers) {
|
for (NodeServer ns : nodeServers) {
|
||||||
futures.add(executorService.submit(() -> {
|
futures.add(Threads.executorService.submit(() -> {
|
||||||
boolean status = SimpleAdminConnectors.execute(ns.getIp(), ns.getAdminPort(), AdminConnector::check);
|
boolean status = SimpleAdminConnectors.execute(ns.getIp(), ns.getAdminPort(), AdminConnector::check);
|
||||||
ns.setStatus(status ? "1" : "0");
|
ns.setStatus(status ? "1" : "0");
|
||||||
return !status;
|
return !status;
|
||||||
@@ -142,8 +146,6 @@ public class NodeServerServiceImpl implements NodeServerService {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
executorService.shutdownNow();
|
|
||||||
|
|
||||||
return pager;
|
return pager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,8 +159,9 @@ public class NodeServerServiceImpl implements NodeServerService {
|
|||||||
if (nodeServer == null) {
|
if (nodeServer == null) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
return SimpleAdminConnectors
|
return SimpleAdminConnectors.execute(nodeServer.getIp(),
|
||||||
.execute(nodeServer.getIp(), nodeServer.getAdminPort(), adminConnector -> adminConnector.canalLog(100));
|
nodeServer.getAdminPort(),
|
||||||
|
adminConnector -> adminConnector.canalLog(100));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean remoteOperation(Long id, String option) {
|
public boolean remoteOperation(Long id, String option) {
|
||||||
@@ -168,8 +171,7 @@ public class NodeServerServiceImpl implements NodeServerService {
|
|||||||
}
|
}
|
||||||
Boolean result = null;
|
Boolean result = null;
|
||||||
if ("start".equals(option)) {
|
if ("start".equals(option)) {
|
||||||
result = SimpleAdminConnectors
|
result = SimpleAdminConnectors.execute(nodeServer.getIp(), nodeServer.getAdminPort(), AdminConnector::start);
|
||||||
.execute(nodeServer.getIp(), nodeServer.getAdminPort(), AdminConnector::start);
|
|
||||||
} else if ("stop".equals(option)) {
|
} else if ("stop".equals(option)) {
|
||||||
result = SimpleAdminConnectors.execute(nodeServer.getIp(), nodeServer.getAdminPort(), AdminConnector::stop);
|
result = SimpleAdminConnectors.execute(nodeServer.getIp(), nodeServer.getAdminPort(), AdminConnector::stop);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import java.util.stream.Collectors;
|
|||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import com.alibaba.otter.canal.admin.common.exception.ServiceException;
|
||||||
import com.alibaba.otter.canal.admin.model.CanalConfig;
|
import com.alibaba.otter.canal.admin.model.CanalConfig;
|
||||||
import com.alibaba.otter.canal.admin.model.CanalInstanceConfig;
|
import com.alibaba.otter.canal.admin.model.CanalInstanceConfig;
|
||||||
import com.alibaba.otter.canal.admin.model.NodeServer;
|
import com.alibaba.otter.canal.admin.model.NodeServer;
|
||||||
@@ -28,7 +29,11 @@ public class PollingConfigServiceImpl implements PollingConfigServer {
|
|||||||
} else { // 单机模式
|
} else { // 单机模式
|
||||||
canalConfig = CanalConfig.find.query().where().eq("serverId", server.getId()).findOne();
|
canalConfig = CanalConfig.find.query().where().eq("serverId", server.getId()).findOne();
|
||||||
}
|
}
|
||||||
if (canalConfig != null && !canalConfig.getContentMd5().equals(md5)) { // 内容发生变化
|
if (canalConfig == null) {
|
||||||
|
throw new ServiceException("canal.properties config is empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!canalConfig.getContentMd5().equals(md5)) { // 内容发生变化
|
||||||
return canalConfig;
|
return canalConfig;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ spring:
|
|||||||
|
|
||||||
spring.datasource:
|
spring.datasource:
|
||||||
url: jdbc:mysql://127.0.0.1:3306/canal_manager?useUnicode=true&characterEncoding=UTF-8&useSSL=false
|
url: jdbc:mysql://127.0.0.1:3306/canal_manager?useUnicode=true&characterEncoding=UTF-8&useSSL=false
|
||||||
username: root
|
username: canal
|
||||||
password: 121212
|
password: canal
|
||||||
driver-class-name: com.mysql.jdbc.Driver
|
driver-class-name: com.mysql.jdbc.Driver
|
||||||
hikari:
|
hikari:
|
||||||
maximum-pool-size: 10
|
maximum-pool-size: 10
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
<!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1"><meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><link rel=icon href=/favicon.ico><title>Canal Admin</title><link href=/static/css/chunk-elementUI.18b11d0e.css rel=stylesheet><link href=/static/css/chunk-libs.5cf311f0.css rel=stylesheet><link href=/static/css/app.bb951cb3.css rel=stylesheet></head><body><noscript><strong>We're sorry but Canal Admin doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=/static/js/chunk-elementUI.667f4c87.js></script><script src=/static/js/chunk-libs.c04beefc.js></script><script>(function(e){function n(n){for(var r,c,f=n[0],a=n[1],i=n[2],d=0,h=[];d<f.length;d++)c=f[d],u[c]&&h.push(u[c][0]),u[c]=0;for(r in a)Object.prototype.hasOwnProperty.call(a,r)&&(e[r]=a[r]);l&&l(n);while(h.length)h.shift()();return o.push.apply(o,i||[]),t()}function t(){for(var e,n=0;n<o.length;n++){for(var t=o[n],r=!0,c=1;c<t.length;c++){var f=t[c];0!==u[f]&&(r=!1)}r&&(o.splice(n--,1),e=a(a.s=t[0]))}return e}var r={},c={runtime:0},u={runtime:0},o=[];function f(e){return a.p+"static/js/"+({}[e]||e)+"."+{"chunk-0dca2f22":"a2bc28b8","chunk-2301924a":"b0e97fa6","chunk-98f505d0":"aade2e3b","chunk-bd1d44ee":"c2f6b1a9","chunk-101fc062":"bc898027","chunk-14b5f7a4":"d0531bb5","chunk-22553be3":"21abed4f","chunk-37c49cbf":"64d26540","chunk-49959c8b":"6d226f70","chunk-4f09fed2":"ff28d88d","chunk-55380ff2":"681c71c9","chunk-69386cf0":"76d77f5c","chunk-7ec889b7":"295b8aad"}[e]+".js"}function a(n){if(r[n])return r[n].exports;var t=r[n]={i:n,l:!1,exports:{}};return e[n].call(t.exports,t,t.exports,a),t.l=!0,t.exports}a.e=function(e){var n=[],t={"chunk-2301924a":1,"chunk-98f505d0":1,"chunk-bd1d44ee":1,"chunk-101fc062":1,"chunk-14b5f7a4":1,"chunk-22553be3":1,"chunk-37c49cbf":1,"chunk-49959c8b":1,"chunk-4f09fed2":1,"chunk-69386cf0":1,"chunk-7ec889b7":1};c[e]?n.push(c[e]):0!==c[e]&&t[e]&&n.push(c[e]=new Promise(function(n,t){for(var r="static/css/"+({}[e]||e)+"."+{"chunk-0dca2f22":"31d6cfe0","chunk-2301924a":"160e7b4a","chunk-98f505d0":"5280f88f","chunk-bd1d44ee":"1528199a","chunk-101fc062":"fad9926f","chunk-14b5f7a4":"f3e06673","chunk-22553be3":"f3e06673","chunk-37c49cbf":"efc21a9c","chunk-49959c8b":"e8e2beee","chunk-4f09fed2":"70ec0b86","chunk-55380ff2":"31d6cfe0","chunk-69386cf0":"741ff14e","chunk-7ec889b7":"c0585512"}[e]+".css",u=a.p+r,o=document.getElementsByTagName("link"),f=0;f<o.length;f++){var i=o[f],d=i.getAttribute("data-href")||i.getAttribute("href");if("stylesheet"===i.rel&&(d===r||d===u))return n()}var h=document.getElementsByTagName("style");for(f=0;f<h.length;f++){i=h[f],d=i.getAttribute("data-href");if(d===r||d===u)return n()}var l=document.createElement("link");l.rel="stylesheet",l.type="text/css",l.onload=n,l.onerror=function(n){var r=n&&n.target&&n.target.src||u,o=new Error("Loading CSS chunk "+e+" failed.\n("+r+")");o.code="CSS_CHUNK_LOAD_FAILED",o.request=r,delete c[e],l.parentNode.removeChild(l),t(o)},l.href=u;var s=document.getElementsByTagName("head")[0];s.appendChild(l)}).then(function(){c[e]=0}));var r=u[e];if(0!==r)if(r)n.push(r[2]);else{var o=new Promise(function(n,t){r=u[e]=[n,t]});n.push(r[2]=o);var i,d=document.createElement("script");d.charset="utf-8",d.timeout=120,a.nc&&d.setAttribute("nonce",a.nc),d.src=f(e),i=function(n){d.onerror=d.onload=null,clearTimeout(h);var t=u[e];if(0!==t){if(t){var r=n&&("load"===n.type?"missing":n.type),c=n&&n.target&&n.target.src,o=new Error("Loading chunk "+e+" failed.\n("+r+": "+c+")");o.type=r,o.request=c,t[1](o)}u[e]=void 0}};var h=setTimeout(function(){i({type:"timeout",target:d})},12e4);d.onerror=d.onload=i,document.head.appendChild(d)}return Promise.all(n)},a.m=e,a.c=r,a.d=function(e,n,t){a.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:t})},a.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.t=function(e,n){if(1&n&&(e=a(e)),8&n)return e;if(4&n&&"object"===typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(a.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var r in e)a.d(t,r,function(n){return e[n]}.bind(null,r));return t},a.n=function(e){var n=e&&e.__esModule?function(){return e["default"]}:function(){return e};return a.d(n,"a",n),n},a.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},a.p="/",a.oe=function(e){throw console.error(e),e};var i=window["webpackJsonp"]=window["webpackJsonp"]||[],d=i.push.bind(i);i.push=n,i=i.slice();for(var h=0;h<i.length;h++)n(i[h]);var l=d;t()})([]);</script><script src=/static/js/app.cae6e777.js></script></body></html>
|
<!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1"><meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><link rel=icon href=/favicon.ico><title>Canal Admin</title><link href=/static/css/chunk-elementUI.18b11d0e.css rel=stylesheet><link href=/static/css/chunk-libs.5cf311f0.css rel=stylesheet><link href=/static/css/app.bb951cb3.css rel=stylesheet></head><body><noscript><strong>We're sorry but Canal Admin doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=/static/js/chunk-elementUI.667f4c87.js></script><script src=/static/js/chunk-libs.c04beefc.js></script><script>(function(e){function n(n){for(var r,c,f=n[0],a=n[1],i=n[2],h=0,d=[];h<f.length;h++)c=f[h],u[c]&&d.push(u[c][0]),u[c]=0;for(r in a)Object.prototype.hasOwnProperty.call(a,r)&&(e[r]=a[r]);l&&l(n);while(d.length)d.shift()();return o.push.apply(o,i||[]),t()}function t(){for(var e,n=0;n<o.length;n++){for(var t=o[n],r=!0,c=1;c<t.length;c++){var f=t[c];0!==u[f]&&(r=!1)}r&&(o.splice(n--,1),e=a(a.s=t[0]))}return e}var r={},c={runtime:0},u={runtime:0},o=[];function f(e){return a.p+"static/js/"+({}[e]||e)+"."+{"chunk-0dca2f22":"a2bc28b8","chunk-2301924a":"1774b851","chunk-98f505d0":"f3096ce7","chunk-bd1d44ee":"8c8282cc","chunk-101fc062":"372a5ca5","chunk-14b5f7a4":"013449e9","chunk-22553be3":"e6d72de5","chunk-37c49cbf":"92ebe0ae","chunk-49959c8b":"058266cb","chunk-4f09fed2":"d107437b","chunk-55380ff2":"430ee174","chunk-69386cf0":"bdbe3f0c","chunk-7ec889b7":"5f730d9b"}[e]+".js"}function a(n){if(r[n])return r[n].exports;var t=r[n]={i:n,l:!1,exports:{}};return e[n].call(t.exports,t,t.exports,a),t.l=!0,t.exports}a.e=function(e){var n=[],t={"chunk-2301924a":1,"chunk-98f505d0":1,"chunk-bd1d44ee":1,"chunk-101fc062":1,"chunk-14b5f7a4":1,"chunk-22553be3":1,"chunk-37c49cbf":1,"chunk-49959c8b":1,"chunk-4f09fed2":1,"chunk-69386cf0":1,"chunk-7ec889b7":1};c[e]?n.push(c[e]):0!==c[e]&&t[e]&&n.push(c[e]=new Promise(function(n,t){for(var r="static/css/"+({}[e]||e)+"."+{"chunk-0dca2f22":"31d6cfe0","chunk-2301924a":"160e7b4a","chunk-98f505d0":"5280f88f","chunk-bd1d44ee":"1528199a","chunk-101fc062":"fad9926f","chunk-14b5f7a4":"f3e06673","chunk-22553be3":"f3e06673","chunk-37c49cbf":"efc21a9c","chunk-49959c8b":"e8e2beee","chunk-4f09fed2":"70ec0b86","chunk-55380ff2":"31d6cfe0","chunk-69386cf0":"741ff14e","chunk-7ec889b7":"c0585512"}[e]+".css",u=a.p+r,o=document.getElementsByTagName("link"),f=0;f<o.length;f++){var i=o[f],h=i.getAttribute("data-href")||i.getAttribute("href");if("stylesheet"===i.rel&&(h===r||h===u))return n()}var d=document.getElementsByTagName("style");for(f=0;f<d.length;f++){i=d[f],h=i.getAttribute("data-href");if(h===r||h===u)return n()}var l=document.createElement("link");l.rel="stylesheet",l.type="text/css",l.onload=n,l.onerror=function(n){var r=n&&n.target&&n.target.src||u,o=new Error("Loading CSS chunk "+e+" failed.\n("+r+")");o.code="CSS_CHUNK_LOAD_FAILED",o.request=r,delete c[e],l.parentNode.removeChild(l),t(o)},l.href=u;var s=document.getElementsByTagName("head")[0];s.appendChild(l)}).then(function(){c[e]=0}));var r=u[e];if(0!==r)if(r)n.push(r[2]);else{var o=new Promise(function(n,t){r=u[e]=[n,t]});n.push(r[2]=o);var i,h=document.createElement("script");h.charset="utf-8",h.timeout=120,a.nc&&h.setAttribute("nonce",a.nc),h.src=f(e),i=function(n){h.onerror=h.onload=null,clearTimeout(d);var t=u[e];if(0!==t){if(t){var r=n&&("load"===n.type?"missing":n.type),c=n&&n.target&&n.target.src,o=new Error("Loading chunk "+e+" failed.\n("+r+": "+c+")");o.type=r,o.request=c,t[1](o)}u[e]=void 0}};var d=setTimeout(function(){i({type:"timeout",target:h})},12e4);h.onerror=h.onload=i,document.head.appendChild(h)}return Promise.all(n)},a.m=e,a.c=r,a.d=function(e,n,t){a.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:t})},a.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.t=function(e,n){if(1&n&&(e=a(e)),8&n)return e;if(4&n&&"object"===typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(a.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var r in e)a.d(t,r,function(n){return e[n]}.bind(null,r));return t},a.n=function(e){var n=e&&e.__esModule?function(){return e["default"]}:function(){return e};return a.d(n,"a",n),n},a.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},a.p="/",a.oe=function(e){throw console.error(e),e};var i=window["webpackJsonp"]=window["webpackJsonp"]||[],h=i.push.bind(i);i.push=n,i=i.slice();for(var d=0;d<i.length;d++)n(i[d]);var l=h;t()})([]);</script><script src=/static/js/app.eee35d99.js></script></body></html>
|
||||||
@@ -1 +0,0 @@
|
|||||||
.line[data-v-01afb045]{text-align:center}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
.wscn-http404-container[data-v-c095f994]{-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);position:absolute;top:40%;left:50%}.wscn-http404[data-v-c095f994]{position:relative;width:1200px;padding:0 50px;overflow:hidden}.wscn-http404 .pic-404[data-v-c095f994]{position:relative;float:left;width:600px;overflow:hidden}.wscn-http404 .pic-404__parent[data-v-c095f994]{width:100%}.wscn-http404 .pic-404__child[data-v-c095f994]{position:absolute}.wscn-http404 .pic-404__child.left[data-v-c095f994]{width:80px;top:17px;left:220px;opacity:0;-webkit-animation-name:cloudLeft-data-v-c095f994;animation-name:cloudLeft-data-v-c095f994;-webkit-animation-duration:2s;animation-duration:2s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-delay:1s;animation-delay:1s}.wscn-http404 .pic-404__child.mid[data-v-c095f994]{width:46px;top:10px;left:420px;opacity:0;-webkit-animation-name:cloudMid-data-v-c095f994;animation-name:cloudMid-data-v-c095f994;-webkit-animation-duration:2s;animation-duration:2s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-delay:1.2s;animation-delay:1.2s}.wscn-http404 .pic-404__child.right[data-v-c095f994]{width:62px;top:100px;left:500px;opacity:0;-webkit-animation-name:cloudRight-data-v-c095f994;animation-name:cloudRight-data-v-c095f994;-webkit-animation-duration:2s;animation-duration:2s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-delay:1s;animation-delay:1s}@-webkit-keyframes cloudLeft-data-v-c095f994{0%{top:17px;left:220px;opacity:0}20%{top:33px;left:188px;opacity:1}80%{top:81px;left:92px;opacity:1}to{top:97px;left:60px;opacity:0}}@keyframes cloudLeft-data-v-c095f994{0%{top:17px;left:220px;opacity:0}20%{top:33px;left:188px;opacity:1}80%{top:81px;left:92px;opacity:1}to{top:97px;left:60px;opacity:0}}@-webkit-keyframes cloudMid-data-v-c095f994{0%{top:10px;left:420px;opacity:0}20%{top:40px;left:360px;opacity:1}70%{top:130px;left:180px;opacity:1}to{top:160px;left:120px;opacity:0}}@keyframes cloudMid-data-v-c095f994{0%{top:10px;left:420px;opacity:0}20%{top:40px;left:360px;opacity:1}70%{top:130px;left:180px;opacity:1}to{top:160px;left:120px;opacity:0}}@-webkit-keyframes cloudRight-data-v-c095f994{0%{top:100px;left:500px;opacity:0}20%{top:120px;left:460px;opacity:1}80%{top:180px;left:340px;opacity:1}to{top:200px;left:300px;opacity:0}}@keyframes cloudRight-data-v-c095f994{0%{top:100px;left:500px;opacity:0}20%{top:120px;left:460px;opacity:1}80%{top:180px;left:340px;opacity:1}to{top:200px;left:300px;opacity:0}}.wscn-http404 .bullshit[data-v-c095f994]{position:relative;float:left;width:300px;padding:30px 0;overflow:hidden}.wscn-http404 .bullshit__oops[data-v-c095f994]{font-size:32px;line-height:40px;color:#1482f0;margin-bottom:20px;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}.wscn-http404 .bullshit__headline[data-v-c095f994],.wscn-http404 .bullshit__oops[data-v-c095f994]{font-weight:700;opacity:0;-webkit-animation-name:slideUp-data-v-c095f994;animation-name:slideUp-data-v-c095f994;-webkit-animation-duration:.5s;animation-duration:.5s}.wscn-http404 .bullshit__headline[data-v-c095f994]{font-size:20px;line-height:24px;color:#222;margin-bottom:10px;-webkit-animation-delay:.1s;animation-delay:.1s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}.wscn-http404 .bullshit__info[data-v-c095f994]{font-size:13px;line-height:21px;color:grey;margin-bottom:30px;-webkit-animation-delay:.2s;animation-delay:.2s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}.wscn-http404 .bullshit__info[data-v-c095f994],.wscn-http404 .bullshit__return-home[data-v-c095f994]{opacity:0;-webkit-animation-name:slideUp-data-v-c095f994;animation-name:slideUp-data-v-c095f994;-webkit-animation-duration:.5s;animation-duration:.5s}.wscn-http404 .bullshit__return-home[data-v-c095f994]{display:block;float:left;width:110px;height:36px;background:#1482f0;border-radius:100px;text-align:center;color:#fff;font-size:14px;line-height:36px;cursor:pointer;-webkit-animation-delay:.3s;animation-delay:.3s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}@-webkit-keyframes slideUp-data-v-c095f994{0%{-webkit-transform:translateY(60px);transform:translateY(60px);opacity:0}to{-webkit-transform:translateY(0);transform:translateY(0);opacity:1}}@keyframes slideUp-data-v-c095f994{0%{-webkit-transform:translateY(60px);transform:translateY(60px);opacity:0}to{-webkit-transform:translateY(0);transform:translateY(0);opacity:1}}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
.line[data-v-ae6e8604]{text-align:center}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
.line[data-v-250c9dcc]{text-align:center}
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
|||||||
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-1ef583f0"],{"7a8b":function(n,t,e){},b0a2:function(n,t,e){"use strict";e.r(t);var o=function(){var n=this,t=n.$createElement,e=n._self._c||t;return e("div",[e("el-form",{ref:"form",attrs:{model:n.form}},[e("div",{staticStyle:{"padding-left":"10px","padding-top":"20px"}},[e("el-form-item",[n._v("\n "+n._s(n.form.name)+" \n "),e("el-button",{attrs:{type:"primary"},on:{click:n.onSubmit}},[n._v("修改")]),n._v(" "),e("el-button",{attrs:{type:"warning"},on:{click:n.onCancel}},[n._v("重置")]),n._v(" "),e("el-button",{attrs:{type:"info"},on:{click:n.onBack}},[n._v("返回")])],1)],1),n._v(" "),e("editor",{attrs:{lang:"properties",theme:"chrome",width:"100%",height:800},on:{init:n.editorInit},model:{value:n.form.content,callback:function(t){n.$set(n.form,"content",t)},expression:"form.content"}})],1)],1)},a=[],c=(e("7f7f"),e("f546")),r={components:{editor:e("7c9e")},data:function(){return{form:{id:null,name:"",content:""}}},created:function(){this.loadCanalConfig()},methods:{editorInit:function(){e("2099"),e("be9d"),e("2968"),e("e0e5"),e("bb36"),e("0329"),e("95b8"),e("6a21")},loadCanalConfig:function(){var n=this;Object(c["b"])(this.$route.query.id).then(function(t){var e=t.data;n.form.id=e.id,n.form.name=e.name+"/instance.propertios",n.form.content=e.content})},onSubmit:function(){var n=this;this.$confirm("修改Instance配置可能会导致重启,是否继续?","确定修改",{confirmButtonText:"确定",cancelButtonText:"取消",type:"warning"}).then(function(){Object(c["h"])(n.form).then(function(t){"success"===t.data?(n.$message({message:"修改成功",type:"success"}),n.loadCanalConfig()):n.$message({message:"修改失败",type:"error"})})})},onCancel:function(){this.loadCanalConfig()},onBack:function(){history.go(-1)}}},i=r,u=(e("d213"),e("2877")),f=Object(u["a"])(i,o,a,!1,null,"01afb045",null);t["default"]=f.exports},d213:function(n,t,e){"use strict";var o=e("7a8b"),a=e.n(o);a.a},f546:function(n,t,e){"use strict";e.d(t,"d",function(){return a}),e.d(t,"b",function(){return c}),e.d(t,"h",function(){return r}),e.d(t,"a",function(){return i}),e.d(t,"c",function(){return u}),e.d(t,"f",function(){return f}),e.d(t,"g",function(){return s}),e.d(t,"e",function(){return l});var o=e("b775");function a(n){return Object(o["a"])({url:"/canal/instances",method:"get",params:n})}function c(n){return Object(o["a"])({url:"/canal/instance/"+n,method:"get"})}function r(n){return Object(o["a"])({url:"/canal/instance",method:"put",data:n})}function i(n){return Object(o["a"])({url:"/canal/instance",method:"post",data:n})}function u(n){return Object(o["a"])({url:"/canal/instance/"+n,method:"delete"})}function f(n,t){return Object(o["a"])({url:"/canal/instance/start/"+n+"/"+t,method:"put"})}function s(n,t){return Object(o["a"])({url:"/canal/instance/stop/"+n+"/"+t,method:"put"})}function l(n,t){return Object(o["a"])({url:"/canal/instance/log/"+n+"/"+t,method:"get"})}}}]);
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-238a81e9"],{"26fc":function(t,s,a){t.exports=a.p+"static/img/404_cloud.0f4bc32b.png"},"8cdb":function(t,s,a){"use strict";a.r(s);var e=function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("div",{staticClass:"wscn-http404-container"},[a("div",{staticClass:"wscn-http404"},[t._m(0),t._v(" "),a("div",{staticClass:"bullshit"},[a("div",{staticClass:"bullshit__oops"},[t._v("OOPS!")]),t._v(" "),t._m(1),t._v(" "),a("div",{staticClass:"bullshit__headline"},[t._v(t._s(t.message))]),t._v(" "),a("div",{staticClass:"bullshit__info"},[t._v("Please check that the URL you entered is correct, or click the button below to return to the homepage.")]),t._v(" "),a("a",{staticClass:"bullshit__return-home",attrs:{href:""}},[t._v("Back to home")])])])])},c=[function(){var t=this,s=t.$createElement,e=t._self._c||s;return e("div",{staticClass:"pic-404"},[e("img",{staticClass:"pic-404__parent",attrs:{src:a("a36b"),alt:"404"}}),t._v(" "),e("img",{staticClass:"pic-404__child left",attrs:{src:a("26fc"),alt:"404"}}),t._v(" "),e("img",{staticClass:"pic-404__child mid",attrs:{src:a("26fc"),alt:"404"}}),t._v(" "),e("img",{staticClass:"pic-404__child right",attrs:{src:a("26fc"),alt:"404"}})])},function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("div",{staticClass:"bullshit__info"},[t._v("All rights reserved\n "),a("a",{staticStyle:{color:"#20a0ff"},attrs:{href:"https://wallstreetcn.com",target:"_blank"}},[t._v("wallstreetcn")])])}],i={name:"Page404",computed:{message:function(){return"The webmaster said that you can not enter this page..."}}},l=i,n=(a("97ef"),a("2877")),r=Object(n["a"])(l,e,c,!1,null,"c095f994",null);s["default"]=r.exports},"97ef":function(t,s,a){"use strict";var e=a("b51e"),c=a.n(e);c.a},a36b:function(t,s,a){t.exports=a.p+"static/img/404.a57b6f31.png"},b51e:function(t,s,a){}}]);
|
|
||||||
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
|||||||
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-5560c396"],{1248:function(t,n,e){"use strict";e.r(n);var a=function(){var t=this,n=t.$createElement,e=t._self._c||n;return e("div",[e("el-form",{ref:"form",attrs:{model:t.form}},[e("div",{staticClass:"filter-container",staticStyle:{"padding-left":"10px","padding-top":"20px"}},[e("el-input",{staticClass:"filter-item",staticStyle:{width:"200px"},attrs:{placeholder:"Instance名称"},model:{value:t.form.name,callback:function(n){t.$set(t.form,"name",n)},expression:"form.name"}}),t._v("\n \n "),e("el-button",{staticClass:"filter-item",attrs:{type:"primary"},on:{click:t.onSubmit}},[t._v("保存")]),t._v(" "),e("el-button",{staticClass:"filter-item",attrs:{type:"info"},on:{click:t.onBack}},[t._v("返回")])],1),t._v(" "),e("editor",{attrs:{lang:"properties",theme:"chrome",width:"100%",height:800},on:{init:t.editorInit},model:{value:t.form.content,callback:function(n){t.$set(t.form,"content",n)},expression:"form.content"}})],1)],1)},c=[],r=(e("7f7f"),e("f546")),o={components:{editor:e("7c9e")},data:function(){return{form:{name:"",content:""}}},created:function(){},methods:{editorInit:function(){e("2099"),e("be9d"),e("2968"),e("e0e5"),e("bb36"),e("0329"),e("95b8"),e("6a21")},onSubmit:function(){var t=this;""!==this.form.name?this.$confirm("确定新建","确定新建",{confirmButtonText:"确定",cancelButtonText:"取消",type:"warning"}).then(function(){Object(r["a"])(t.form).then(function(n){"success"===n.data?(t.$message({message:"新建成功",type:"success"}),t.$router.push("/canalServer/canalInstances")):t.$message({message:"新建失败",type:"error"})})}):this.$message({message:"请输入Instance名称",type:"error"})},onBack:function(){history.go(-1)}}},i=o,s=(e("d881"),e("2877")),u=Object(s["a"])(i,a,c,!1,null,"ae6e8604",null);n["default"]=u.exports},"193c":function(t,n,e){},d881:function(t,n,e){"use strict";var a=e("193c"),c=e.n(a);c.a},f546:function(t,n,e){"use strict";e.d(n,"d",function(){return c}),e.d(n,"b",function(){return r}),e.d(n,"h",function(){return o}),e.d(n,"a",function(){return i}),e.d(n,"c",function(){return s}),e.d(n,"f",function(){return u}),e.d(n,"g",function(){return f}),e.d(n,"e",function(){return l});var a=e("b775");function c(t){return Object(a["a"])({url:"/canal/instances",method:"get",params:t})}function r(t){return Object(a["a"])({url:"/canal/instance/"+t,method:"get"})}function o(t){return Object(a["a"])({url:"/canal/instance",method:"put",data:t})}function i(t){return Object(a["a"])({url:"/canal/instance",method:"post",data:t})}function s(t){return Object(a["a"])({url:"/canal/instance/"+t,method:"delete"})}function u(t,n){return Object(a["a"])({url:"/canal/instance/start/"+t+"/"+n,method:"put"})}function f(t,n){return Object(a["a"])({url:"/canal/instance/stop/"+t+"/"+n,method:"put"})}function l(t,n){return Object(a["a"])({url:"/canal/instance/log/"+t+"/"+n,method:"get"})}}}]);
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-6f6d6145"],{"09a8":function(n,t,e){"use strict";e.r(t);var o=function(){var n=this,t=n.$createElement,e=n._self._c||t;return e("div",[e("el-form",{ref:"form",attrs:{model:n.form}},[e("div",{staticStyle:{"padding-left":"10px","padding-top":"20px"}},[e("el-form-item",[n._v("\n "+n._s(n.form.name)+" \n "),e("el-button",{attrs:{type:"primary"},on:{click:n.onSubmit}},[n._v("修改")]),n._v(" "),e("el-button",{attrs:{type:"warning"},on:{click:n.onCancel}},[n._v("重置")])],1)],1),n._v(" "),e("editor",{attrs:{lang:"properties",theme:"chrome",width:"100%",height:800},on:{init:n.editorInit},model:{value:n.form.content,callback:function(t){n.$set(n.form,"content",t)},expression:"form.content"}})],1)],1)},a=[],c=(e("7f7f"),e("b775"));function i(){return Object(c["a"])({url:"/canal/config",method:"get"})}function r(n){return Object(c["a"])({url:"/canal/config",method:"put",data:n})}var f={components:{editor:e("7c9e")},data:function(){return{form:{id:null,name:"",content:""}}},created:function(){this.loadCanalConfig()},methods:{editorInit:function(){e("2099"),e("be9d"),e("2968"),e("e0e5"),e("bb36"),e("0329"),e("95b8"),e("6a21")},loadCanalConfig:function(){var n=this;i().then(function(t){var e=t.data;n.form.id=e.id,n.form.name=e.name,n.form.content=e.content})},onSubmit:function(){var n=this;this.$confirm("修改Server主配置可能会导致Server重启,是否继续?","确定修改",{confirmButtonText:"确定",cancelButtonText:"取消",type:"warning"}).then(function(){r(n.form).then(function(t){"success"===t.data?(n.$message({message:"修改成功",type:"success"}),n.loadCanalConfig()):n.$message({message:"修改失败",type:"error"})})})},onCancel:function(){this.loadCanalConfig()}}},s=f,u=(e("fbdc"),e("2877")),l=Object(u["a"])(s,o,a,!1,null,"250c9dcc",null);t["default"]=l.exports},8351:function(n,t,e){},fbdc:function(n,t,e){"use strict";var o=e("8351"),a=e.n(o);a.a}}]);
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-7ec889b7"],{"11ec":function(t,n,e){},"7f19":function(t,n,e){"use strict";var c=e("11ec"),r=e.n(c);r.a},"7f84":function(t,n,e){"use strict";e.r(n);var c=function(){var t=this,n=t.$createElement,e=t._self._c||n;return e("div",[e("el-form",{ref:"form",attrs:{model:t.form}},[e("div",{staticStyle:{"padding-left":"10px","padding-right":"10px","padding-top":"20px"}},[e("el-form-item",[t._v("\n "+t._s(t.form.instance)+" \n "),e("el-button",{attrs:{type:"primary"},on:{click:t.onRefresh}},[t._v("刷新")]),t._v(" "),e("el-button",{attrs:{type:"info"},on:{click:t.onBack}},[t._v("返回")])],1),t._v(" "),e("el-input",{attrs:{rows:35,readonly:"readonly",type:"textarea"},model:{value:t.form.desc,callback:function(n){t.$set(t.form,"desc",n)},expression:"form.desc"}})],1)])],1)},r=[],a=e("f546"),o={data:function(){return{form:{instance:"",desc:""}}},created:function(){this.fetchData()},methods:{fetchData:function(){var t=this;Object(a["e"])(this.$route.query.id,this.$route.query.nodeId).then(function(n){t.form.instance=n.data.instance+".log",t.form.desc=n.data.log})},onRefresh:function(){this.fetchData()},onBack:function(){history.go(-1)}}},u=o,i=(e("7f19"),e("2877")),f=Object(i["a"])(u,c,r,!1,null,"0b80198c",null);n["default"]=f.exports},f546:function(t,n,e){"use strict";e.d(n,"d",function(){return r}),e.d(n,"b",function(){return a}),e.d(n,"h",function(){return o}),e.d(n,"a",function(){return u}),e.d(n,"c",function(){return i}),e.d(n,"f",function(){return f}),e.d(n,"g",function(){return s}),e.d(n,"e",function(){return d});var c=e("b775");function r(t){return Object(c["a"])({url:"/canal/instances",method:"get",params:t})}function a(t){return Object(c["a"])({url:"/canal/instance/"+t,method:"get"})}function o(t){return Object(c["a"])({url:"/canal/instance",method:"put",data:t})}function u(t){return Object(c["a"])({url:"/canal/instance",method:"post",data:t})}function i(t){return Object(c["a"])({url:"/canal/instance/"+t,method:"delete"})}function f(t,n){return Object(c["a"])({url:"/canal/instance/start/"+t+"/"+n,method:"put"})}function s(t,n){return Object(c["a"])({url:"/canal/instance/stop/"+t+"/"+n,method:"put"})}function d(t,n){return Object(c["a"])({url:"/canal/instance/log/"+t+"/"+n,method:"get"})}}}]);
|
|
||||||
File diff suppressed because one or more lines are too long
@@ -72,7 +72,7 @@
|
|||||||
<el-dropdown-item @click.native="handleDelete(scope.row)">删除</el-dropdown-item>
|
<el-dropdown-item @click.native="handleDelete(scope.row)">删除</el-dropdown-item>
|
||||||
<el-dropdown-item @click.native="handleStart(scope.row)">启动</el-dropdown-item>
|
<el-dropdown-item @click.native="handleStart(scope.row)">启动</el-dropdown-item>
|
||||||
<el-dropdown-item @click.native="handleStop(scope.row)">停止</el-dropdown-item>
|
<el-dropdown-item @click.native="handleStop(scope.row)">停止</el-dropdown-item>
|
||||||
<el-dropdown-item @click.native="handleInstances(scope.row)">实例</el-dropdown-item>
|
<el-dropdown-item @click.native="handleInstances(scope.row)">详情</el-dropdown-item>
|
||||||
<el-dropdown-item @click.native="handleLog(scope.row)">日志</el-dropdown-item>
|
<el-dropdown-item @click.native="handleLog(scope.row)">日志</el-dropdown-item>
|
||||||
</el-dropdown-menu>
|
</el-dropdown-menu>
|
||||||
</el-dropdown>
|
</el-dropdown>
|
||||||
@@ -113,7 +113,7 @@
|
|||||||
<el-button type="primary" @click="dataOperation()">确定</el-button>
|
<el-button type="primary" @click="dataOperation()">确定</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<el-dialog :visible.sync="dialogInstances" title="实例列表" width="800px">
|
<el-dialog :visible.sync="dialogInstances" title="instance 列表" width="800px">
|
||||||
<div class="filter-container">
|
<div class="filter-container">
|
||||||
<el-button class="filter-item" type="info" @click="activeInstances()">刷新列表</el-button>
|
<el-button class="filter-item" type="info" @click="activeInstances()">刷新列表</el-button>
|
||||||
</div>
|
</div>
|
||||||
@@ -310,6 +310,10 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleConfig(row) {
|
handleConfig(row) {
|
||||||
|
if (row.canalCluster !== null) {
|
||||||
|
this.$message({ message: '集群模式Server不允许单独变更配置,请在集群配置变更', type: 'error' })
|
||||||
|
return
|
||||||
|
}
|
||||||
this.$router.push('/canalServer/nodeServer/config?serverId=' + row.id)
|
this.$router.push('/canalServer/nodeServer/config?serverId=' + row.id)
|
||||||
},
|
},
|
||||||
handleUpdate(row) {
|
handleUpdate(row) {
|
||||||
@@ -374,7 +378,7 @@ export default {
|
|||||||
this.$message({ message: '当前Server不是启动状态,无法停止', type: 'error' })
|
this.$message({ message: '当前Server不是启动状态,无法停止', type: 'error' })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.$confirm('停止 Server 服务', '确定停止Server服务', {
|
this.$confirm('停止Server服务会导致所有Instance都停止服务', '确定停止Server服务', {
|
||||||
confirmButtonText: '确定',
|
confirmButtonText: '确定',
|
||||||
cancelButtonText: '取消',
|
cancelButtonText: '取消',
|
||||||
type: 'warning'
|
type: 'warning'
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ public class ServerRunningData implements Serializable {
|
|||||||
|
|
||||||
private static final long serialVersionUID = 92260481691855281L;
|
private static final long serialVersionUID = 92260481691855281L;
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
private Long cid;
|
private Long cid;
|
||||||
private String address;
|
private String address;
|
||||||
private boolean active = true;
|
private boolean active = true;
|
||||||
@@ -23,8 +24,7 @@ public class ServerRunningData implements Serializable {
|
|||||||
public ServerRunningData(){
|
public ServerRunningData(){
|
||||||
}
|
}
|
||||||
|
|
||||||
public ServerRunningData(Long cid, String address){
|
public ServerRunningData(String address){
|
||||||
this.cid = cid;
|
|
||||||
this.address = address;
|
this.address = address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,6 @@ public class ServerRunningMonitor extends AbstractCanalLifeCycle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!runningData.isActive() && isMine(runningData.getAddress())) { // 说明出现了主动释放的操作,并且本机之前是active
|
if (!runningData.isActive() && isMine(runningData.getAddress())) { // 说明出现了主动释放的操作,并且本机之前是active
|
||||||
release = true;
|
|
||||||
releaseRunning();// 彻底释放mainstem
|
releaseRunning();// 彻底释放mainstem
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,7 +115,7 @@ public class ServerRunningMonitor extends AbstractCanalLifeCycle {
|
|||||||
if (zkClient != null) {
|
if (zkClient != null) {
|
||||||
releaseRunning(); // 尝试一下release
|
releaseRunning(); // 尝试一下release
|
||||||
} else {
|
} else {
|
||||||
processActiveExit(); // 没有zk,直接启动
|
processActiveExit(); // 没有zk,直接退出
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,8 +184,8 @@ public class ServerRunningMonitor extends AbstractCanalLifeCycle {
|
|||||||
boolean result = isMine(activeData.getAddress());
|
boolean result = isMine(activeData.getAddress());
|
||||||
if (!result) {
|
if (!result) {
|
||||||
logger.warn("canal is running in node[{}] , but not in node[{}]",
|
logger.warn("canal is running in node[{}] , but not in node[{}]",
|
||||||
activeData.getCid(),
|
activeData.getAddress(),
|
||||||
serverData.getCid());
|
serverData.getAddress());
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
} catch (ZkNoNodeException e) {
|
} catch (ZkNoNodeException e) {
|
||||||
@@ -204,6 +203,7 @@ public class ServerRunningMonitor extends AbstractCanalLifeCycle {
|
|||||||
|
|
||||||
private boolean releaseRunning() {
|
private boolean releaseRunning() {
|
||||||
if (check()) {
|
if (check()) {
|
||||||
|
release = true;
|
||||||
String path = ZookeeperPathUtils.getDestinationServerRunning(destination);
|
String path = ZookeeperPathUtils.getDestinationServerRunning(destination);
|
||||||
zkClient.delete(path);
|
zkClient.delete(path);
|
||||||
mutex.set(false);
|
mutex.set(false);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import com.alibaba.otter.canal.common.zookeeper.ZookeeperPathUtils;
|
|||||||
import com.alibaba.otter.canal.common.zookeeper.running.ServerRunningData;
|
import com.alibaba.otter.canal.common.zookeeper.running.ServerRunningData;
|
||||||
import com.alibaba.otter.canal.common.zookeeper.running.ServerRunningListener;
|
import com.alibaba.otter.canal.common.zookeeper.running.ServerRunningListener;
|
||||||
import com.alibaba.otter.canal.common.zookeeper.running.ServerRunningMonitor;
|
import com.alibaba.otter.canal.common.zookeeper.running.ServerRunningMonitor;
|
||||||
|
|
||||||
@Ignore
|
@Ignore
|
||||||
public class ServerRunningTest extends AbstractZkTest {
|
public class ServerRunningTest extends AbstractZkTest {
|
||||||
|
|
||||||
@@ -38,7 +39,7 @@ public class ServerRunningTest extends AbstractZkTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testOneServer() {
|
public void testOneServer() {
|
||||||
final CountDownLatch countLatch = new CountDownLatch(2);
|
final CountDownLatch countLatch = new CountDownLatch(2);
|
||||||
ServerRunningMonitor runningMonitor = buildServerRunning(countLatch, 1L, "127.0.0.1", 2088);
|
ServerRunningMonitor runningMonitor = buildServerRunning(countLatch, "127.0.0.1", 2088);
|
||||||
runningMonitor.start();
|
runningMonitor.start();
|
||||||
sleep(2000L);
|
sleep(2000L);
|
||||||
runningMonitor.stop();
|
runningMonitor.stop();
|
||||||
@@ -52,9 +53,9 @@ public class ServerRunningTest extends AbstractZkTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testMultiServer() {
|
public void testMultiServer() {
|
||||||
final CountDownLatch countLatch = new CountDownLatch(30);
|
final CountDownLatch countLatch = new CountDownLatch(30);
|
||||||
final ServerRunningMonitor runningMonitor1 = buildServerRunning(countLatch, 1L, "127.0.0.1", 2088);
|
final ServerRunningMonitor runningMonitor1 = buildServerRunning(countLatch, "127.0.0.1", 2088);
|
||||||
final ServerRunningMonitor runningMonitor2 = buildServerRunning(countLatch, 2L, "127.0.0.1", 2089);
|
final ServerRunningMonitor runningMonitor2 = buildServerRunning(countLatch, "127.0.0.1", 2089);
|
||||||
final ServerRunningMonitor runningMonitor3 = buildServerRunning(countLatch, 3L, "127.0.0.1", 2090);
|
final ServerRunningMonitor runningMonitor3 = buildServerRunning(countLatch, "127.0.0.1", 2090);
|
||||||
final ExecutorService executor = Executors.newFixedThreadPool(3);
|
final ExecutorService executor = Executors.newFixedThreadPool(3);
|
||||||
executor.submit(new Runnable() {
|
executor.submit(new Runnable() {
|
||||||
|
|
||||||
@@ -110,29 +111,29 @@ public class ServerRunningTest extends AbstractZkTest {
|
|||||||
sleep(30000L);
|
sleep(30000L);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ServerRunningMonitor buildServerRunning(final CountDownLatch countLatch, final Long cid, final String ip,
|
private ServerRunningMonitor buildServerRunning(final CountDownLatch countLatch, final final String ip,
|
||||||
final int port) {
|
final int port) {
|
||||||
ServerRunningData serverData = new ServerRunningData(cid, ip + ":" + port);
|
ServerRunningData serverData = new ServerRunningData(ip + ":" + port);
|
||||||
ServerRunningMonitor runningMonitor = new ServerRunningMonitor(serverData);
|
ServerRunningMonitor runningMonitor = new ServerRunningMonitor(serverData);
|
||||||
runningMonitor.setDestination(destination);
|
runningMonitor.setDestination(destination);
|
||||||
runningMonitor.setListener(new ServerRunningListener() {
|
runningMonitor.setListener(new ServerRunningListener() {
|
||||||
|
|
||||||
public void processActiveEnter() {
|
public void processActiveEnter() {
|
||||||
System.out.println(String.format("cid:%s ip:%s:%s has start", cid, ip, port));
|
System.out.println(String.format("cid:%s ip:%s:%s has start", ip, port));
|
||||||
countLatch.countDown();
|
countLatch.countDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void processActiveExit() {
|
public void processActiveExit() {
|
||||||
System.out.println(String.format("cid:%s ip:%s:%s has stop", cid, ip, port));
|
System.out.println(String.format("cid:%s ip:%s:%s has stop", ip, port));
|
||||||
countLatch.countDown();
|
countLatch.countDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void processStart() {
|
public void processStart() {
|
||||||
System.out.println(String.format("cid:%s ip:%s:%s processStart", cid, ip, port));
|
System.out.println(String.format("cid:%s ip:%s:%s processStart", ip, port));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void processStop() {
|
public void processStop() {
|
||||||
System.out.println(String.format("cid:%s ip:%s:%s processStop", cid, ip, port));
|
System.out.println(String.format("cid:%s ip:%s:%s processStop", ip, port));
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ if "%OS%" == "Windows_NT" set ENV_PATH=%~dp0%
|
|||||||
|
|
||||||
set conf_dir=%ENV_PATH%\..\conf
|
set conf_dir=%ENV_PATH%\..\conf
|
||||||
set canal_conf=%conf_dir%\canal.properties
|
set canal_conf=%conf_dir%\canal.properties
|
||||||
set logback_configurationFile=%conf_dir%\logback.xml
|
set canal_local_conf=%conf_dir%\canal_local.properties
|
||||||
|
@rem set logback_configurationFile=%conf_dir%\logback.xml
|
||||||
|
|
||||||
set CLASSPATH=%conf_dir%
|
set CLASSPATH=%conf_dir%
|
||||||
set CLASSPATH=%conf_dir%\..\lib\*;%CLASSPATH%
|
set CLASSPATH=%conf_dir%\..\lib\*;%CLASSPATH%
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ case "`uname`" in
|
|||||||
esac
|
esac
|
||||||
base=${bin_abs_path}/..
|
base=${bin_abs_path}/..
|
||||||
canal_conf=$base/conf/canal.properties
|
canal_conf=$base/conf/canal.properties
|
||||||
|
canal_local_conf=$base/conf/canal_local.properties
|
||||||
logback_configurationFile=$base/conf/logback.xml
|
logback_configurationFile=$base/conf/logback.xml
|
||||||
export LANG=en_US.UTF-8
|
export LANG=en_US.UTF-8
|
||||||
export BASE=$base
|
export BASE=$base
|
||||||
@@ -48,21 +49,29 @@ in
|
|||||||
;;
|
;;
|
||||||
1 )
|
1 )
|
||||||
var=$*
|
var=$*
|
||||||
if [ -f $var ] ; then
|
if [ "$var" = "local" ]; then
|
||||||
canal_conf=$var
|
canal_conf=$canal_local_conf
|
||||||
else
|
else
|
||||||
echo "THE PARAMETER IS NOT CORRECT.PLEASE CHECK AGAIN."
|
if [ -f $var ] ; then
|
||||||
exit
|
canal_conf=$var
|
||||||
|
else
|
||||||
|
echo "THE PARAMETER IS NOT CORRECT.PLEASE CHECK AGAIN."
|
||||||
|
exit
|
||||||
|
fi
|
||||||
fi;;
|
fi;;
|
||||||
2 )
|
2 )
|
||||||
var=$1
|
var=$1
|
||||||
if [ -f $var ] ; then
|
if [ "$var" = "local" ]; then
|
||||||
canal_conf=$var
|
canal_conf=$canal_local_conf
|
||||||
else
|
else
|
||||||
if [ "$1" = "debug" ]; then
|
if [ -f $var ] ; then
|
||||||
DEBUG_PORT=$2
|
canal_conf=$var
|
||||||
DEBUG_SUSPEND="n"
|
else
|
||||||
JAVA_DEBUG_OPT="-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=$DEBUG_PORT,server=y,suspend=$DEBUG_SUSPEND"
|
if [ "$1" = "debug" ]; then
|
||||||
|
DEBUG_PORT=$2
|
||||||
|
DEBUG_SUSPEND="n"
|
||||||
|
JAVA_DEBUG_OPT="-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=$DEBUG_PORT,server=y,suspend=$DEBUG_SUSPEND"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
fi;;
|
fi;;
|
||||||
* )
|
* )
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ import com.google.common.collect.MigrateMap;
|
|||||||
*/
|
*/
|
||||||
public class CanalController {
|
public class CanalController {
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(CanalController.class);
|
private static final Logger logger = LoggerFactory.getLogger(CanalController.class);
|
||||||
private Long cid;
|
private Long cid;
|
||||||
private String ip;
|
private String ip;
|
||||||
private String registerIp;
|
private String registerIp;
|
||||||
@@ -54,11 +54,10 @@ public class CanalController {
|
|||||||
private int adminPort;
|
private int adminPort;
|
||||||
// 默认使用spring的方式载入
|
// 默认使用spring的方式载入
|
||||||
private Map<String, InstanceConfig> instanceConfigs;
|
private Map<String, InstanceConfig> instanceConfigs;
|
||||||
private Map<String, String> runningInstances = new MapMaker().makeMap();
|
|
||||||
private InstanceConfig globalInstanceConfig;
|
private InstanceConfig globalInstanceConfig;
|
||||||
private Map<String, PlainCanalConfigClient> managerClients;
|
private Map<String, PlainCanalConfigClient> managerClients;
|
||||||
// 监听instance config的变化
|
// 监听instance config的变化
|
||||||
private boolean autoScan = true;
|
private boolean autoScan = true;
|
||||||
private InstanceAction defaultAction;
|
private InstanceAction defaultAction;
|
||||||
private Map<InstanceMode, InstanceConfigMonitor> instanceConfigMonitors;
|
private Map<InstanceMode, InstanceConfigMonitor> instanceConfigMonitors;
|
||||||
private CanalServerWithEmbedded embededCanalServer;
|
private CanalServerWithEmbedded embededCanalServer;
|
||||||
@@ -153,91 +152,88 @@ public class CanalController {
|
|||||||
zkclientx.createPersistent(ZookeeperPathUtils.CANAL_CLUSTER_ROOT_NODE, true);
|
zkclientx.createPersistent(ZookeeperPathUtils.CANAL_CLUSTER_ROOT_NODE, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
final ServerRunningData serverData = new ServerRunningData(cid, registerIp + ":" + port);
|
final ServerRunningData serverData = new ServerRunningData(registerIp + ":" + port);
|
||||||
ServerRunningMonitors.setServerData(serverData);
|
ServerRunningMonitors.setServerData(serverData);
|
||||||
ServerRunningMonitors
|
ServerRunningMonitors.setRunningMonitors(MigrateMap.makeComputingMap(new Function<String, ServerRunningMonitor>() {
|
||||||
.setRunningMonitors(MigrateMap.makeComputingMap(new Function<String, ServerRunningMonitor>() {
|
|
||||||
|
|
||||||
public ServerRunningMonitor apply(final String destination) {
|
public ServerRunningMonitor apply(final String destination) {
|
||||||
ServerRunningMonitor runningMonitor = new ServerRunningMonitor(serverData);
|
ServerRunningMonitor runningMonitor = new ServerRunningMonitor(serverData);
|
||||||
runningMonitor.setDestination(destination);
|
runningMonitor.setDestination(destination);
|
||||||
runningMonitor.setListener(new ServerRunningListener() {
|
runningMonitor.setListener(new ServerRunningListener() {
|
||||||
|
|
||||||
public void processActiveEnter() {
|
public void processActiveEnter() {
|
||||||
try {
|
try {
|
||||||
MDC.put(CanalConstants.MDC_DESTINATION, String.valueOf(destination));
|
MDC.put(CanalConstants.MDC_DESTINATION, String.valueOf(destination));
|
||||||
embededCanalServer.start(destination);
|
embededCanalServer.start(destination);
|
||||||
if (canalMQStarter != null) {
|
if (canalMQStarter != null) {
|
||||||
canalMQStarter.startDestination(destination);
|
canalMQStarter.startDestination(destination);
|
||||||
}
|
|
||||||
runningInstances.put(destination, destination);
|
|
||||||
} finally {
|
|
||||||
MDC.remove(CanalConstants.MDC_DESTINATION);
|
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
MDC.remove(CanalConstants.MDC_DESTINATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void processActiveExit() {
|
|
||||||
try {
|
|
||||||
MDC.put(CanalConstants.MDC_DESTINATION, String.valueOf(destination));
|
|
||||||
if (canalMQStarter != null) {
|
|
||||||
canalMQStarter.stopDestination(destination);
|
|
||||||
}
|
|
||||||
embededCanalServer.stop(destination);
|
|
||||||
runningInstances.remove(destination);
|
|
||||||
} finally {
|
|
||||||
MDC.remove(CanalConstants.MDC_DESTINATION);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void processStart() {
|
|
||||||
try {
|
|
||||||
if (zkclientx != null) {
|
|
||||||
final String path = ZookeeperPathUtils.getDestinationClusterNode(destination,
|
|
||||||
registerIp + ":" + port);
|
|
||||||
initCid(path);
|
|
||||||
zkclientx.subscribeStateChanges(new IZkStateListener() {
|
|
||||||
|
|
||||||
public void handleStateChanged(KeeperState state) throws Exception {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void handleNewSession() throws Exception {
|
|
||||||
initCid(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleSessionEstablishmentError(Throwable error) throws Exception {
|
|
||||||
logger.error("failed to connect to zookeeper", error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
MDC.remove(CanalConstants.MDC_DESTINATION);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void processStop() {
|
|
||||||
try {
|
|
||||||
MDC.put(CanalConstants.MDC_DESTINATION, String.valueOf(destination));
|
|
||||||
if (zkclientx != null) {
|
|
||||||
final String path = ZookeeperPathUtils.getDestinationClusterNode(destination,
|
|
||||||
registerIp + ":" + port);
|
|
||||||
releaseCid(path);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
MDC.remove(CanalConstants.MDC_DESTINATION);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
if (zkclientx != null) {
|
|
||||||
runningMonitor.setZkClient(zkclientx);
|
|
||||||
}
|
}
|
||||||
// 触发创建一下cid节点
|
|
||||||
runningMonitor.init();
|
public void processActiveExit() {
|
||||||
return runningMonitor;
|
try {
|
||||||
|
MDC.put(CanalConstants.MDC_DESTINATION, String.valueOf(destination));
|
||||||
|
if (canalMQStarter != null) {
|
||||||
|
canalMQStarter.stopDestination(destination);
|
||||||
|
}
|
||||||
|
embededCanalServer.stop(destination);
|
||||||
|
} finally {
|
||||||
|
MDC.remove(CanalConstants.MDC_DESTINATION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void processStart() {
|
||||||
|
try {
|
||||||
|
if (zkclientx != null) {
|
||||||
|
final String path = ZookeeperPathUtils.getDestinationClusterNode(destination,
|
||||||
|
registerIp + ":" + port);
|
||||||
|
initCid(path);
|
||||||
|
zkclientx.subscribeStateChanges(new IZkStateListener() {
|
||||||
|
|
||||||
|
public void handleStateChanged(KeeperState state) throws Exception {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleNewSession() throws Exception {
|
||||||
|
initCid(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleSessionEstablishmentError(Throwable error) throws Exception {
|
||||||
|
logger.error("failed to connect to zookeeper", error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
MDC.remove(CanalConstants.MDC_DESTINATION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void processStop() {
|
||||||
|
try {
|
||||||
|
MDC.put(CanalConstants.MDC_DESTINATION, String.valueOf(destination));
|
||||||
|
if (zkclientx != null) {
|
||||||
|
final String path = ZookeeperPathUtils.getDestinationClusterNode(destination,
|
||||||
|
registerIp + ":" + port);
|
||||||
|
releaseCid(path);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
MDC.remove(CanalConstants.MDC_DESTINATION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
if (zkclientx != null) {
|
||||||
|
runningMonitor.setZkClient(zkclientx);
|
||||||
}
|
}
|
||||||
}));
|
// 触发创建一下cid节点
|
||||||
|
runningMonitor.init();
|
||||||
|
return runningMonitor;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
// 初始化monitor机制
|
// 初始化monitor机制
|
||||||
autoScan = BooleanUtils.toBoolean(getProperty(properties, CanalConstants.CANAL_AUTO_SCAN));
|
autoScan = BooleanUtils.toBoolean(getProperty(properties, CanalConstants.CANAL_AUTO_SCAN));
|
||||||
@@ -284,13 +280,26 @@ public class CanalController {
|
|||||||
|
|
||||||
logger.info("auto notify reload {} successful.", destination);
|
logger.info("auto notify reload {} successful.", destination);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void release(String destination) {
|
||||||
|
// 此处的release,代表强制释放,主要针对HA机制释放运行,让给其他机器抢占
|
||||||
|
InstanceConfig config = instanceConfigs.get(destination);
|
||||||
|
if (config != null) {
|
||||||
|
ServerRunningMonitor runningMonitor = ServerRunningMonitors.getRunningMonitor(destination);
|
||||||
|
if (runningMonitor.isStart()) {
|
||||||
|
runningMonitor.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("auto notify release {} successful.", destination);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
instanceConfigMonitors = MigrateMap.makeComputingMap(new Function<InstanceMode, InstanceConfigMonitor>() {
|
instanceConfigMonitors = MigrateMap.makeComputingMap(new Function<InstanceMode, InstanceConfigMonitor>() {
|
||||||
|
|
||||||
public InstanceConfigMonitor apply(InstanceMode mode) {
|
public InstanceConfigMonitor apply(InstanceMode mode) {
|
||||||
int scanInterval = Integer
|
int scanInterval = Integer.valueOf(getProperty(properties, CanalConstants.CANAL_AUTO_SCAN_INTERVAL));
|
||||||
.valueOf(getProperty(properties, CanalConstants.CANAL_AUTO_SCAN_INTERVAL));
|
|
||||||
|
|
||||||
if (mode.isSpring()) {
|
if (mode.isSpring()) {
|
||||||
SpringInstanceConfigMonitor monitor = new SpringInstanceConfigMonitor();
|
SpringInstanceConfigMonitor monitor = new SpringInstanceConfigMonitor();
|
||||||
@@ -366,7 +375,7 @@ public class CanalController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (config.getMode().isManager()) {
|
if (config.getMode().isManager()) {
|
||||||
PlainCanalInstanceGenerator instanceGenerator = new PlainCanalInstanceGenerator(properties);
|
PlainCanalInstanceGenerator instanceGenerator = new PlainCanalInstanceGenerator();
|
||||||
instanceGenerator.setCanalConfigClient(managerClients.get(config.getManagerAddress()));
|
instanceGenerator.setCanalConfigClient(managerClients.get(config.getManagerAddress()));
|
||||||
instanceGenerator.setSpringXml(config.getSpringXml());
|
instanceGenerator.setSpringXml(config.getSpringXml());
|
||||||
return instanceGenerator.generate(destination);
|
return instanceGenerator.generate(destination);
|
||||||
@@ -386,7 +395,7 @@ public class CanalController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private PlainCanalConfigClient getManagerClient(String managerAddress) {
|
private PlainCanalConfigClient getManagerClient(String managerAddress) {
|
||||||
return new PlainCanalConfigClient(managerAddress, this.adminUser, this.adminPasswd, null, adminPort);
|
return new PlainCanalConfigClient(managerAddress, this.adminUser, this.adminPasswd, this.registerIp, adminPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initInstanceConfig(Properties properties) {
|
private void initInstanceConfig(Properties properties) {
|
||||||
@@ -398,8 +407,7 @@ public class CanalController {
|
|||||||
InstanceConfig oldConfig = instanceConfigs.put(destination, config);
|
InstanceConfig oldConfig = instanceConfigs.put(destination, config);
|
||||||
|
|
||||||
if (oldConfig != null) {
|
if (oldConfig != null) {
|
||||||
logger
|
logger.warn("destination:{} old config:{} has replace by new config:{}", destination, oldConfig, config);
|
||||||
.warn("destination:{} old config:{} has replace by new config:{}", destination, oldConfig, config);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -595,7 +603,4 @@ public class CanalController {
|
|||||||
return instanceConfigs;
|
return instanceConfigs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, String> getRunningInstances() {
|
|
||||||
return runningInstances;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,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.common.utils.AddressUtils;
|
||||||
import com.alibaba.otter.canal.common.utils.NamedThreadFactory;
|
import com.alibaba.otter.canal.common.utils.NamedThreadFactory;
|
||||||
import com.alibaba.otter.canal.instance.manager.plain.PlainCanal;
|
import com.alibaba.otter.canal.instance.manager.plain.PlainCanal;
|
||||||
import com.alibaba.otter.canal.instance.manager.plain.PlainCanalConfigClient;
|
import com.alibaba.otter.canal.instance.manager.plain.PlainCanalConfigClient;
|
||||||
@@ -27,7 +28,7 @@ public class CanalLauncher {
|
|||||||
private static final Logger logger = LoggerFactory.getLogger(CanalLauncher.class);
|
private static final Logger logger = LoggerFactory.getLogger(CanalLauncher.class);
|
||||||
public static final CountDownLatch runningLatch = new CountDownLatch(1);
|
public static final CountDownLatch runningLatch = new CountDownLatch(1);
|
||||||
private static ScheduledExecutorService executor = Executors.newScheduledThreadPool(1,
|
private static ScheduledExecutorService executor = Executors.newScheduledThreadPool(1,
|
||||||
new NamedThreadFactory("canal-server-scan"));
|
new NamedThreadFactory("canal-server-scan"));
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
try {
|
try {
|
||||||
@@ -49,55 +50,54 @@ public class CanalLauncher {
|
|||||||
if (StringUtils.isNotEmpty(managerAddress)) {
|
if (StringUtils.isNotEmpty(managerAddress)) {
|
||||||
String user = properties.getProperty(CanalConstants.CANAL_ADMIN_USER);
|
String user = properties.getProperty(CanalConstants.CANAL_ADMIN_USER);
|
||||||
String passwd = properties.getProperty(CanalConstants.CANAL_ADMIN_PASSWD);
|
String passwd = properties.getProperty(CanalConstants.CANAL_ADMIN_PASSWD);
|
||||||
String adminPort = properties.getProperty(CanalConstants.CANAL_ADMIN_PORT, "11110");
|
String adminPort = properties.getProperty(CanalConstants.CANAL_ADMIN_PORT);
|
||||||
|
String registerIp = properties.getProperty(CanalConstants.CANAL_REGISTER_IP);
|
||||||
|
if (StringUtils.isEmpty(adminPort)) {
|
||||||
|
adminPort = "11110";
|
||||||
|
}
|
||||||
|
if (StringUtils.isEmpty(registerIp)) {
|
||||||
|
registerIp = AddressUtils.getHostIp();
|
||||||
|
}
|
||||||
final PlainCanalConfigClient configClient = new PlainCanalConfigClient(managerAddress,
|
final PlainCanalConfigClient configClient = new PlainCanalConfigClient(managerAddress,
|
||||||
user,
|
user,
|
||||||
passwd,
|
passwd,
|
||||||
"",
|
registerIp,
|
||||||
Integer.parseInt(adminPort));
|
Integer.parseInt(adminPort));
|
||||||
PlainCanal canalConfig = configClient.findServer(null);
|
PlainCanal canalConfig = configClient.findServer(null);
|
||||||
if (canalConfig != null) {
|
if (canalConfig == null) {
|
||||||
properties = canalConfig.getProperties();
|
throw new IllegalArgumentException("managerAddress:" + managerAddress
|
||||||
// 用本地配置覆盖
|
+ " can't not found config for [" + registerIp + ":" + adminPort
|
||||||
properties.put(CanalConstants.CANAL_ADMIN_MANAGER, managerAddress);
|
+ "]");
|
||||||
properties.put(CanalConstants.CANAL_ADMIN_USER, user);
|
|
||||||
properties.put(CanalConstants.CANAL_ADMIN_PASSWD, passwd);
|
|
||||||
properties.put(CanalConstants.CANAL_ADMIN_PORT, adminPort);
|
|
||||||
int scanIntervalInSecond = Integer
|
|
||||||
.parseInt(properties.getProperty(CanalConstants.CANAL_AUTO_SCAN_INTERVAL, "5"));
|
|
||||||
executor.scheduleWithFixedDelay(new Runnable() {
|
|
||||||
|
|
||||||
private PlainCanal lastCanalConfig;
|
|
||||||
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
if (lastCanalConfig == null) {
|
|
||||||
lastCanalConfig = configClient.findServer(null);
|
|
||||||
} else {
|
|
||||||
PlainCanal newCanalConfig = configClient.findServer(lastCanalConfig.getMd5());
|
|
||||||
if (newCanalConfig != null) {
|
|
||||||
// 远程配置canal.properties修改重新加载整个应用
|
|
||||||
canalStater.stop();
|
|
||||||
Properties properties1 = newCanalConfig.getProperties();
|
|
||||||
// 用本地配置覆盖
|
|
||||||
properties1.put(CanalConstants.CANAL_ADMIN_MANAGER, managerAddress);
|
|
||||||
properties1.put(CanalConstants.CANAL_ADMIN_USER, user);
|
|
||||||
properties1.put(CanalConstants.CANAL_ADMIN_PASSWD, passwd);
|
|
||||||
properties1.put(CanalConstants.CANAL_ADMIN_PORT, adminPort);
|
|
||||||
canalStater.setProperties(properties1);
|
|
||||||
canalStater.start();
|
|
||||||
|
|
||||||
lastCanalConfig = newCanalConfig;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Throwable e) {
|
|
||||||
logger.error("scan failed", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}, 0, scanIntervalInSecond, TimeUnit.SECONDS);
|
|
||||||
}
|
}
|
||||||
|
properties = canalConfig.getProperties();
|
||||||
|
int scanIntervalInSecond = Integer.valueOf(properties.getProperty(CanalConstants.CANAL_AUTO_SCAN_INTERVAL,
|
||||||
|
"5"));
|
||||||
|
executor.scheduleWithFixedDelay(new Runnable() {
|
||||||
|
|
||||||
|
private PlainCanal lastCanalConfig;
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
if (lastCanalConfig == null) {
|
||||||
|
lastCanalConfig = configClient.findServer(null);
|
||||||
|
} else {
|
||||||
|
PlainCanal newCanalConfig = configClient.findServer(lastCanalConfig.getMd5());
|
||||||
|
if (newCanalConfig != null) {
|
||||||
|
// 远程配置canal.properties修改重新加载整个应用
|
||||||
|
canalStater.stop();
|
||||||
|
canalStater.setProperties(newCanalConfig.getProperties());
|
||||||
|
canalStater.start();
|
||||||
|
|
||||||
|
lastCanalConfig = newCanalConfig;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Throwable e) {
|
||||||
|
logger.error("scan failed", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}, 0, scanIntervalInSecond, TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
canalStater.setProperties(properties);
|
canalStater.setProperties(properties);
|
||||||
@@ -118,4 +118,5 @@ public class CanalLauncher {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
package com.alibaba.otter.canal.deployer;
|
package com.alibaba.otter.canal.deployer;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileFilter;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
@@ -17,9 +13,6 @@ import com.alibaba.otter.canal.kafka.CanalKafkaProducer;
|
|||||||
import com.alibaba.otter.canal.rocketmq.CanalRocketMQProducer;
|
import com.alibaba.otter.canal.rocketmq.CanalRocketMQProducer;
|
||||||
import com.alibaba.otter.canal.server.CanalMQStarter;
|
import com.alibaba.otter.canal.server.CanalMQStarter;
|
||||||
import com.alibaba.otter.canal.spi.CanalMQProducer;
|
import com.alibaba.otter.canal.spi.CanalMQProducer;
|
||||||
import com.google.common.base.Function;
|
|
||||||
import com.google.common.base.Joiner;
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Canal server 启动类
|
* Canal server 启动类
|
||||||
@@ -76,40 +69,8 @@ public class CanalStater {
|
|||||||
if (canalMQProducer != null) {
|
if (canalMQProducer != null) {
|
||||||
// disable netty
|
// disable netty
|
||||||
System.setProperty(CanalConstants.CANAL_WITHOUT_NETTY, "true");
|
System.setProperty(CanalConstants.CANAL_WITHOUT_NETTY, "true");
|
||||||
String autoScan = CanalController.getProperty(properties, CanalConstants.CANAL_AUTO_SCAN);
|
|
||||||
// 设置为raw避免ByteString->Entry的二次解析
|
// 设置为raw避免ByteString->Entry的二次解析
|
||||||
System.setProperty("canal.instance.memory.rawEntry", "false");
|
System.setProperty("canal.instance.memory.rawEntry", "false");
|
||||||
if ("true".equals(autoScan)) {
|
|
||||||
String rootDir = CanalController.getProperty(properties, CanalConstants.CANAL_CONF_DIR);
|
|
||||||
if (StringUtils.isEmpty(rootDir)) {
|
|
||||||
rootDir = "../conf";
|
|
||||||
}
|
|
||||||
File rootdir = new File(rootDir);
|
|
||||||
if (rootdir.exists()) {
|
|
||||||
File[] instanceDirs = rootdir.listFiles(new FileFilter() {
|
|
||||||
|
|
||||||
public boolean accept(File pathname) {
|
|
||||||
String filename = pathname.getName();
|
|
||||||
return pathname.isDirectory() && !"spring".equalsIgnoreCase(filename)
|
|
||||||
&& !"metrics".equalsIgnoreCase(filename);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (instanceDirs != null && instanceDirs.length > 0) {
|
|
||||||
List<String> instances = Lists.transform(Arrays.asList(instanceDirs),
|
|
||||||
new Function<File, String>() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String apply(File instanceDir) {
|
|
||||||
return instanceDir.getName();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
System.setProperty(CanalConstants.CANAL_DESTINATIONS, Joiner.on(",").join(instances));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
String destinations = CanalController.getProperty(properties, CanalConstants.CANAL_DESTINATIONS);
|
|
||||||
System.setProperty(CanalConstants.CANAL_DESTINATIONS, destinations);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info("## start the canal server.");
|
logger.info("## start the canal server.");
|
||||||
@@ -136,7 +97,8 @@ public class CanalStater {
|
|||||||
if (canalMQProducer != null) {
|
if (canalMQProducer != null) {
|
||||||
canalMQStarter = new CanalMQStarter(canalMQProducer);
|
canalMQStarter = new CanalMQStarter(canalMQProducer);
|
||||||
MQProperties mqProperties = buildMQProperties(properties);
|
MQProperties mqProperties = buildMQProperties(properties);
|
||||||
canalMQStarter.start(mqProperties);
|
String destinations = CanalController.getProperty(properties, CanalConstants.CANAL_DESTINATIONS);
|
||||||
|
canalMQStarter.start(mqProperties, destinations);
|
||||||
controller.setCanalMQStarter(canalMQStarter);
|
controller.setCanalMQStarter(canalMQStarter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.alibaba.otter.canal.deployer.admin;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -14,7 +15,6 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
import com.alibaba.otter.canal.admin.CanalAdmin;
|
import com.alibaba.otter.canal.admin.CanalAdmin;
|
||||||
import com.alibaba.otter.canal.common.utils.FileUtils;
|
import com.alibaba.otter.canal.common.utils.FileUtils;
|
||||||
import com.alibaba.otter.canal.deployer.CanalController;
|
|
||||||
import com.alibaba.otter.canal.deployer.CanalStater;
|
import com.alibaba.otter.canal.deployer.CanalStater;
|
||||||
import com.alibaba.otter.canal.deployer.InstanceConfig;
|
import com.alibaba.otter.canal.deployer.InstanceConfig;
|
||||||
import com.alibaba.otter.canal.deployer.monitor.InstanceAction;
|
import com.alibaba.otter.canal.deployer.monitor.InstanceAction;
|
||||||
@@ -102,32 +102,18 @@ public class CanalAdminController implements CanalAdmin {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getInstances() {
|
|
||||||
try {
|
|
||||||
CanalController controller = canalStater.getController();
|
|
||||||
if (controller != null) {
|
|
||||||
Map<String, InstanceConfig> instanceConfigs = controller.getInstanceConfigs();
|
|
||||||
if (instanceConfigs != null) {
|
|
||||||
return Joiner.on(",").join(instanceConfigs.keySet());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Throwable e) {
|
|
||||||
logger.error(e.getMessage(), e);
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getRunningInstances() {
|
public String getRunningInstances() {
|
||||||
try {
|
try {
|
||||||
CanalController controller = canalStater.getController();
|
Map<String, CanalInstance> instances = CanalServerWithEmbedded.instance().getCanalInstances();
|
||||||
if (controller != null) {
|
List<String> runningInstances = new ArrayList<String>();
|
||||||
Map<String, String> instanceConfigs = controller.getRunningInstances();
|
instances.forEach((destination, instance) -> {
|
||||||
if (instanceConfigs != null) {
|
if (instance.isStart()) {
|
||||||
return Joiner.on(",").join(instanceConfigs.keySet());
|
runningInstances.add(destination);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
|
return Joiner.on(",").join(runningInstances);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
logger.error(e.getMessage(), e);
|
logger.error(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
@@ -173,6 +159,20 @@ public class CanalAdminController implements CanalAdmin {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean releaseInstance(String destination) {
|
||||||
|
try {
|
||||||
|
InstanceAction instanceAction = getInstanceAction(destination);
|
||||||
|
if (instanceAction != null) {
|
||||||
|
instanceAction.release(destination);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
logger.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean restartInstance(String destination) {
|
public boolean restartInstance(String destination) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -13,6 +13,11 @@ public interface InstanceAction {
|
|||||||
*/
|
*/
|
||||||
void start(String destination);
|
void start(String destination);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主动释放destination运行
|
||||||
|
*/
|
||||||
|
void release(String destination);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 停止destination
|
* 停止destination
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#################################################
|
#################################################
|
||||||
######### common argument #############
|
######### common argument #############
|
||||||
#################################################
|
#################################################
|
||||||
canal.id = 1
|
|
||||||
# tcp bind ip
|
# tcp bind ip
|
||||||
canal.ip =
|
canal.ip =
|
||||||
# register ip to zookeeper
|
# register ip to zookeeper
|
||||||
@@ -12,12 +11,6 @@ canal.metrics.pull.port = 11112
|
|||||||
# canal.user = canal
|
# canal.user = canal
|
||||||
# canal.passwd = E3619321C1A937C46A0D8BD1DAC39F93B27D4458
|
# canal.passwd = E3619321C1A937C46A0D8BD1DAC39F93B27D4458
|
||||||
|
|
||||||
# canal admin config
|
|
||||||
#canal.admin.manager = 127.0.0.1:8089
|
|
||||||
canal.admin.port = 11110
|
|
||||||
canal.admin.user = admin
|
|
||||||
canal.admin.passwd = 4ACFE3202A5FF5CF467898FC58AAB1D615029441
|
|
||||||
|
|
||||||
canal.zkServers =
|
canal.zkServers =
|
||||||
# flush data to zk
|
# flush data to zk
|
||||||
canal.zookeeper.flush.period = 1000
|
canal.zookeeper.flush.period = 1000
|
||||||
|
|||||||
8
deployer/src/main/resources/canal_local.properties
Normal file
8
deployer/src/main/resources/canal_local.properties
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# register ip
|
||||||
|
canal.register.ip =
|
||||||
|
|
||||||
|
# canal admin config
|
||||||
|
canal.admin.manager = 127.0.0.1:8089
|
||||||
|
canal.admin.port = 11110
|
||||||
|
canal.admin.user = admin
|
||||||
|
canal.admin.passwd = 4ACFE3202A5FF5CF467898FC58AAB1D615029441
|
||||||
139
deployer/src/main/resources/canal_manager.properties
Normal file
139
deployer/src/main/resources/canal_manager.properties
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
#################################################
|
||||||
|
######### common argument #############
|
||||||
|
#################################################
|
||||||
|
# tcp bind ip
|
||||||
|
canal.ip =
|
||||||
|
# register ip to zookeeper
|
||||||
|
canal.register.ip =
|
||||||
|
canal.port = 11111
|
||||||
|
canal.metrics.pull.port = 11112
|
||||||
|
# canal instance user/passwd
|
||||||
|
canal.user = canal
|
||||||
|
canal.passwd = E3619321C1A937C46A0D8BD1DAC39F93B27D4458
|
||||||
|
|
||||||
|
# canal admin config
|
||||||
|
canal.admin.manager = 127.0.0.1:8089
|
||||||
|
canal.admin.port = 11110
|
||||||
|
canal.admin.user = admin
|
||||||
|
canal.admin.passwd = 4ACFE3202A5FF5CF467898FC58AAB1D615029441
|
||||||
|
|
||||||
|
canal.zkServers =
|
||||||
|
# flush data to zk
|
||||||
|
canal.zookeeper.flush.period = 1000
|
||||||
|
canal.withoutNetty = false
|
||||||
|
# tcp, kafka, RocketMQ
|
||||||
|
canal.serverMode = tcp
|
||||||
|
# flush meta cursor/parse position to file
|
||||||
|
canal.file.data.dir = ${canal.conf.dir}
|
||||||
|
canal.file.flush.period = 1000
|
||||||
|
## memory store RingBuffer size, should be Math.pow(2,n)
|
||||||
|
canal.instance.memory.buffer.size = 16384
|
||||||
|
## memory store RingBuffer used memory unit size , default 1kb
|
||||||
|
canal.instance.memory.buffer.memunit = 1024
|
||||||
|
## meory store gets mode used MEMSIZE or ITEMSIZE
|
||||||
|
canal.instance.memory.batch.mode = MEMSIZE
|
||||||
|
canal.instance.memory.rawEntry = true
|
||||||
|
|
||||||
|
## detecing config
|
||||||
|
canal.instance.detecting.enable = false
|
||||||
|
#canal.instance.detecting.sql = insert into retl.xdual values(1,now()) on duplicate key update x=now()
|
||||||
|
canal.instance.detecting.sql = select 1
|
||||||
|
canal.instance.detecting.interval.time = 3
|
||||||
|
canal.instance.detecting.retry.threshold = 3
|
||||||
|
canal.instance.detecting.heartbeatHaEnable = false
|
||||||
|
|
||||||
|
# support maximum transaction size, more than the size of the transaction will be cut into multiple transactions delivery
|
||||||
|
canal.instance.transaction.size = 1024
|
||||||
|
# mysql fallback connected to new master should fallback times
|
||||||
|
canal.instance.fallbackIntervalInSeconds = 60
|
||||||
|
|
||||||
|
# network config
|
||||||
|
canal.instance.network.receiveBufferSize = 16384
|
||||||
|
canal.instance.network.sendBufferSize = 16384
|
||||||
|
canal.instance.network.soTimeout = 30
|
||||||
|
|
||||||
|
# binlog filter config
|
||||||
|
canal.instance.filter.druid.ddl = true
|
||||||
|
canal.instance.filter.query.dcl = false
|
||||||
|
canal.instance.filter.query.dml = false
|
||||||
|
canal.instance.filter.query.ddl = false
|
||||||
|
canal.instance.filter.table.error = false
|
||||||
|
canal.instance.filter.rows = false
|
||||||
|
canal.instance.filter.transaction.entry = false
|
||||||
|
|
||||||
|
# binlog format/image check
|
||||||
|
canal.instance.binlog.format = ROW,STATEMENT,MIXED
|
||||||
|
canal.instance.binlog.image = FULL,MINIMAL,NOBLOB
|
||||||
|
|
||||||
|
# binlog ddl isolation
|
||||||
|
canal.instance.get.ddl.isolation = false
|
||||||
|
|
||||||
|
# parallel parser config
|
||||||
|
canal.instance.parser.parallel = true
|
||||||
|
## concurrent thread number, default 60% available processors, suggest not to exceed Runtime.getRuntime().availableProcessors()
|
||||||
|
#canal.instance.parser.parallelThreadSize = 16
|
||||||
|
## disruptor ringbuffer size, must be power of 2
|
||||||
|
canal.instance.parser.parallelBufferSize = 256
|
||||||
|
|
||||||
|
# table meta tsdb info
|
||||||
|
canal.instance.tsdb.enable = true
|
||||||
|
canal.instance.tsdb.dir = ${canal.file.data.dir:../conf}/${canal.instance.destination:}
|
||||||
|
canal.instance.tsdb.url = jdbc:h2:${canal.instance.tsdb.dir}/h2;CACHE_SIZE=1000;MODE=MYSQL;
|
||||||
|
canal.instance.tsdb.dbUsername = canal
|
||||||
|
canal.instance.tsdb.dbPassword = canal
|
||||||
|
# dump snapshot interval, default 24 hour
|
||||||
|
canal.instance.tsdb.snapshot.interval = 24
|
||||||
|
# purge snapshot expire , default 360 hour(15 days)
|
||||||
|
canal.instance.tsdb.snapshot.expire = 360
|
||||||
|
|
||||||
|
# aliyun ak/sk , support rds/mq
|
||||||
|
canal.aliyun.accessKey =
|
||||||
|
canal.aliyun.secretKey =
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
######### destinations #############
|
||||||
|
#################################################
|
||||||
|
canal.destinations =
|
||||||
|
# conf root dir
|
||||||
|
canal.conf.dir = ../conf
|
||||||
|
# auto scan instance dir add/remove and start/stop instance
|
||||||
|
canal.auto.scan = true
|
||||||
|
canal.auto.scan.interval = 5
|
||||||
|
|
||||||
|
canal.instance.tsdb.spring.xml = classpath:spring/tsdb/h2-tsdb.xml
|
||||||
|
#canal.instance.tsdb.spring.xml = classpath:spring/tsdb/mysql-tsdb.xml
|
||||||
|
|
||||||
|
canal.instance.global.mode = manager
|
||||||
|
canal.instance.global.lazy = false
|
||||||
|
canal.instance.global.manager.address = ${canal.admin.manager}
|
||||||
|
#canal.instance.global.spring.xml = classpath:spring/memory-instance.xml
|
||||||
|
canal.instance.global.spring.xml = classpath:spring/file-instance.xml
|
||||||
|
#canal.instance.global.spring.xml = classpath:spring/default-instance.xml
|
||||||
|
|
||||||
|
##################################################
|
||||||
|
######### MQ #############
|
||||||
|
##################################################
|
||||||
|
canal.mq.servers = 127.0.0.1:6667
|
||||||
|
canal.mq.retries = 0
|
||||||
|
canal.mq.batchSize = 16384
|
||||||
|
canal.mq.maxRequestSize = 1048576
|
||||||
|
canal.mq.lingerMs = 100
|
||||||
|
canal.mq.bufferMemory = 33554432
|
||||||
|
canal.mq.canalBatchSize = 50
|
||||||
|
canal.mq.canalGetTimeout = 100
|
||||||
|
canal.mq.flatMessage = true
|
||||||
|
canal.mq.compressionType = none
|
||||||
|
canal.mq.acks = all
|
||||||
|
#canal.mq.properties. =
|
||||||
|
canal.mq.producerGroup = test
|
||||||
|
# Set this value to "cloud", if you want open message trace feature in aliyun.
|
||||||
|
canal.mq.accessChannel = local
|
||||||
|
# aliyun mq namespace
|
||||||
|
#canal.mq.namespace =
|
||||||
|
|
||||||
|
##################################################
|
||||||
|
######### Kafka Kerberos Info #############
|
||||||
|
##################################################
|
||||||
|
canal.mq.kafka.kerberos.enable = false
|
||||||
|
canal.mq.kafka.kerberos.krb5FilePath = "../conf/kerberos/krb5.conf"
|
||||||
|
canal.mq.kafka.kerberos.jaasFilePath = "../conf/kerberos/jaas.conf"
|
||||||
@@ -13,8 +13,6 @@ import com.alibaba.otter.canal.instance.manager.plain.PlainCanal;
|
|||||||
import com.alibaba.otter.canal.instance.manager.plain.PlainCanalConfigClient;
|
import com.alibaba.otter.canal.instance.manager.plain.PlainCanalConfigClient;
|
||||||
import com.alibaba.otter.canal.instance.spring.SpringCanalInstanceGenerator;
|
import com.alibaba.otter.canal.instance.spring.SpringCanalInstanceGenerator;
|
||||||
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 基于manager生成对应的{@linkplain CanalInstance}
|
* 基于manager生成对应的{@linkplain CanalInstance}
|
||||||
*
|
*
|
||||||
@@ -28,11 +26,6 @@ public class PlainCanalInstanceGenerator implements CanalInstanceGenerator {
|
|||||||
private PlainCanalConfigClient canalConfigClient;
|
private PlainCanalConfigClient canalConfigClient;
|
||||||
private String defaultName = "instance";
|
private String defaultName = "instance";
|
||||||
private BeanFactory beanFactory;
|
private BeanFactory beanFactory;
|
||||||
private Properties canalConfig;
|
|
||||||
|
|
||||||
public PlainCanalInstanceGenerator(Properties canalConfig){
|
|
||||||
this.canalConfig = canalConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CanalInstance generate(String destination) {
|
public CanalInstance generate(String destination) {
|
||||||
synchronized (CanalInstanceGenerator.class) {
|
synchronized (CanalInstanceGenerator.class) {
|
||||||
@@ -41,11 +34,8 @@ public class PlainCanalInstanceGenerator implements CanalInstanceGenerator {
|
|||||||
if (canal == null) {
|
if (canal == null) {
|
||||||
throw new CanalException("instance : " + destination + " config is not found");
|
throw new CanalException("instance : " + destination + " config is not found");
|
||||||
}
|
}
|
||||||
Properties properties = canal.getProperties();
|
|
||||||
properties.putAll(canalConfig);
|
|
||||||
// 设置动态properties,替换掉本地properties
|
// 设置动态properties,替换掉本地properties
|
||||||
com.alibaba.otter.canal.instance.spring.support.PropertyPlaceholderConfigurer.propertiesLocal
|
com.alibaba.otter.canal.instance.spring.support.PropertyPlaceholderConfigurer.propertiesLocal.set(canal.getProperties());
|
||||||
.set(properties);
|
|
||||||
// 设置当前正在加载的通道,加载spring查找文件时会用到该变量
|
// 设置当前正在加载的通道,加载spring查找文件时会用到该变量
|
||||||
System.setProperty("canal.instance.destination", destination);
|
System.setProperty("canal.instance.destination", destination);
|
||||||
this.beanFactory = getBeanFactory(springXml);
|
this.beanFactory = getBeanFactory(springXml);
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ package com.alibaba.otter.canal.instance.manager.plain;
|
|||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.UnknownHostException;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -46,14 +44,10 @@ public class PlainCanalConfigClient extends AbstractCanalLifeCycle implements Ca
|
|||||||
this.user = user;
|
this.user = user;
|
||||||
this.passwd = passwd;
|
this.passwd = passwd;
|
||||||
this.httpHelper = new HttpHelper();
|
this.httpHelper = new HttpHelper();
|
||||||
if (StringUtils.isNotEmpty(localIp)) {
|
if (StringUtils.isEmpty(localIp)) {
|
||||||
this.localIp = localIp;
|
this.localIp = "127.0.0.1";// 本地测试用
|
||||||
} else {
|
} else {
|
||||||
try {
|
this.localIp = localIp;
|
||||||
this.localIp = InetAddress.getLocalHost().getHostAddress();
|
|
||||||
} catch (UnknownHostException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
this.adminPort = adminPort;
|
this.adminPort = adminPort;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,13 +41,6 @@ public interface CanalAdmin {
|
|||||||
*/
|
*/
|
||||||
boolean restart();
|
boolean restart();
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取所有当前节点下所有实例
|
|
||||||
*
|
|
||||||
* @return 实例信息
|
|
||||||
*/
|
|
||||||
String getInstances();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取所有当前节点下运行中的实例
|
* 获取所有当前节点下运行中的实例
|
||||||
*
|
*
|
||||||
@@ -79,6 +72,14 @@ public interface CanalAdmin {
|
|||||||
*/
|
*/
|
||||||
boolean stopInstance(String destination);
|
boolean stopInstance(String destination);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过实例名释放,主要针对cluster模式有效(通知当前主机释放instance运行交给其他人来抢占)
|
||||||
|
*
|
||||||
|
* @param destination 实例名
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
boolean releaseInstance(String destination);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过实例名重启实例
|
* 通过实例名重启实例
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -58,9 +58,6 @@ public class SessionHandler extends SimpleChannelHandler {
|
|||||||
case "list":
|
case "list":
|
||||||
message = canalAdmin.getRunningInstances();
|
message = canalAdmin.getRunningInstances();
|
||||||
break;
|
break;
|
||||||
case "instances":
|
|
||||||
message = canalAdmin.getInstances();
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
byte[] errorBytes = AdminNettyUtils.errorPacket(301,
|
byte[] errorBytes = AdminNettyUtils.errorPacket(301,
|
||||||
MessageFormatter.format("ServerAdmin action={} is unknown", action).getMessage());
|
MessageFormatter.format("ServerAdmin action={} is unknown", action).getMessage());
|
||||||
@@ -83,6 +80,9 @@ public class SessionHandler extends SimpleChannelHandler {
|
|||||||
case "stop":
|
case "stop":
|
||||||
message = canalAdmin.stopInstance(destination) ? "1" : "0";
|
message = canalAdmin.stopInstance(destination) ? "1" : "0";
|
||||||
break;
|
break;
|
||||||
|
case "release":
|
||||||
|
message = canalAdmin.releaseInstance(destination) ? "1" : "0";
|
||||||
|
break;
|
||||||
case "restart":
|
case "restart":
|
||||||
message = canalAdmin.restartInstance(destination) ? "1" : "0";
|
message = canalAdmin.restartInstance(destination) ? "1" : "0";
|
||||||
break;
|
break;
|
||||||
@@ -132,11 +132,9 @@ public class SessionHandler extends SimpleChannelHandler {
|
|||||||
}
|
}
|
||||||
} catch (Throwable exception) {
|
} catch (Throwable exception) {
|
||||||
byte[] errorBytes = AdminNettyUtils.errorPacket(400,
|
byte[] errorBytes = AdminNettyUtils.errorPacket(400,
|
||||||
MessageFormatter
|
MessageFormatter.format("something goes wrong with channel:{}, exception={}",
|
||||||
.format("something goes wrong with channel:{}, exception={}",
|
ctx.getChannel(),
|
||||||
ctx.getChannel(),
|
ExceptionUtils.getStackTrace(exception)).getMessage());
|
||||||
ExceptionUtils.getStackTrace(exception))
|
|
||||||
.getMessage());
|
|
||||||
AdminNettyUtils.write(ctx.getChannel(), errorBytes);
|
AdminNettyUtils.write(ctx.getChannel(), errorBytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ public class CanalMQStarter {
|
|||||||
this.canalMQProducer = canalMQProducer;
|
this.canalMQProducer = canalMQProducer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void start(MQProperties properties) {
|
public synchronized void start(MQProperties properties, String destinations) {
|
||||||
try {
|
try {
|
||||||
if (running) {
|
if (running) {
|
||||||
return;
|
return;
|
||||||
@@ -60,8 +60,8 @@ public class CanalMQStarter {
|
|||||||
executorService = Executors.newCachedThreadPool();
|
executorService = Executors.newCachedThreadPool();
|
||||||
logger.info("## start the MQ workers.");
|
logger.info("## start the MQ workers.");
|
||||||
|
|
||||||
String[] destinations = StringUtils.split(System.getProperty("canal.destinations"), ",");
|
String[] dsts = StringUtils.split(destinations, ",");
|
||||||
for (String destination : destinations) {
|
for (String destination : dsts) {
|
||||||
destination = destination.trim();
|
destination = destination.trim();
|
||||||
CanalMQRunnable canalMQRunnable = new CanalMQRunnable(destination);
|
CanalMQRunnable canalMQRunnable = new CanalMQRunnable(destination);
|
||||||
canalMQWorks.put(destination, canalMQRunnable);
|
canalMQWorks.put(destination, canalMQRunnable);
|
||||||
|
|||||||
Reference in New Issue
Block a user