mirror of
https://github.com/alibaba/canal.git
synced 2026-11-04 00:30:15 +08:00
fixed issue #171 , client HA bug , modify SimpleCanalConnector
This commit is contained in:
@@ -10,5 +10,7 @@ import java.net.SocketAddress;
|
|||||||
*/
|
*/
|
||||||
public interface CanalNodeAccessStrategy {
|
public interface CanalNodeAccessStrategy {
|
||||||
|
|
||||||
|
SocketAddress currentNode();
|
||||||
|
|
||||||
SocketAddress nextNode();
|
SocketAddress nextNode();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,11 +41,17 @@ public class ClusterCanalConnector implements CanalConnector {
|
|||||||
|
|
||||||
public void connect() throws CanalClientException {
|
public void connect() throws CanalClientException {
|
||||||
while (currentConnector == null) {
|
while (currentConnector == null) {
|
||||||
SocketAddress nextAddress = this.accessStrategy.nextNode();
|
|
||||||
int times = 0;
|
int times = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
currentConnector = new SimpleCanalConnector(nextAddress, username, password, destination, accessStrategy);
|
currentConnector = new SimpleCanalConnector(null, username, password, destination) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SocketAddress getAddress() {
|
||||||
|
return accessStrategy.nextNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
currentConnector.setSoTimeout(soTimeout);
|
currentConnector.setSoTimeout(soTimeout);
|
||||||
if (filter != null) {
|
if (filter != null) {
|
||||||
currentConnector.setFilter(filter);
|
currentConnector.setFilter(filter);
|
||||||
@@ -57,7 +63,7 @@ public class ClusterCanalConnector implements CanalConnector {
|
|||||||
currentConnector.connect();
|
currentConnector.connect();
|
||||||
break;
|
break;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.warn("failed to connect to:{} after retry {} times", currentConnector.getAddress(), times);
|
logger.warn("failed to connect to:{} after retry {} times", accessStrategy.currentNode(), times);
|
||||||
currentConnector.disconnect();
|
currentConnector.disconnect();
|
||||||
currentConnector = null;
|
currentConnector = null;
|
||||||
// retry for #retryTimes for each node when trying to
|
// retry for #retryTimes for each node when trying to
|
||||||
|
|||||||
@@ -62,6 +62,11 @@ public class ClusterNodeAccessStrategy implements CanalNodeAccessStrategy {
|
|||||||
initRunning(this.zkClient.readData(runningPath, true));
|
initRunning(this.zkClient.readData(runningPath, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SocketAddress currentNode() {
|
||||||
|
return nextNode();
|
||||||
|
}
|
||||||
|
|
||||||
public SocketAddress nextNode() {
|
public SocketAddress nextNode() {
|
||||||
if (runningAddress != null) {// 如果服务已经启动,直接选择当前正在工作的节点
|
if (runningAddress != null) {// 如果服务已经启动,直接选择当前正在工作的节点
|
||||||
return runningAddress;
|
return runningAddress;
|
||||||
@@ -109,4 +114,5 @@ public class ClusterNodeAccessStrategy implements CanalNodeAccessStrategy {
|
|||||||
return zkClient;
|
return zkClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.alibaba.otter.canal.client.CanalConnector;
|
import com.alibaba.otter.canal.client.CanalConnector;
|
||||||
import com.alibaba.otter.canal.client.CanalNodeAccessStrategy;
|
|
||||||
import com.alibaba.otter.canal.client.impl.running.ClientRunningData;
|
import com.alibaba.otter.canal.client.impl.running.ClientRunningData;
|
||||||
import com.alibaba.otter.canal.client.impl.running.ClientRunningListener;
|
import com.alibaba.otter.canal.client.impl.running.ClientRunningListener;
|
||||||
import com.alibaba.otter.canal.client.impl.running.ClientRunningMonitor;
|
import com.alibaba.otter.canal.client.impl.running.ClientRunningMonitor;
|
||||||
@@ -70,21 +69,18 @@ public class SimpleCanalConnector implements CanalConnector {
|
|||||||
// 读写数据分别使用不同的锁进行控制,减小锁粒度,读也需要排他锁,并发度容易造成数据包混乱,反序列化失败
|
// 读写数据分别使用不同的锁进行控制,减小锁粒度,读也需要排他锁,并发度容易造成数据包混乱,反序列化失败
|
||||||
private Object readDataLock = new Object();
|
private Object readDataLock = new Object();
|
||||||
private Object writeDataLock = new Object();
|
private Object writeDataLock = new Object();
|
||||||
private CanalNodeAccessStrategy accessStrategy;
|
|
||||||
|
|
||||||
public SimpleCanalConnector(SocketAddress address, String username, String password, String destination,
|
public SimpleCanalConnector(SocketAddress address, String username, String password, String destination){
|
||||||
CanalNodeAccessStrategy accessStrategy){
|
this(address, username, password, destination, 60000);
|
||||||
this(address, username, password, destination, 60000, accessStrategy);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public SimpleCanalConnector(SocketAddress address, String username, String password, String destination,
|
public SimpleCanalConnector(SocketAddress address, String username, String password, String destination,
|
||||||
int soTimeout, CanalNodeAccessStrategy accessStrategy){
|
int soTimeout){
|
||||||
this.address = address;
|
this.address = address;
|
||||||
this.username = username;
|
this.username = username;
|
||||||
this.password = password;
|
this.password = password;
|
||||||
this.soTimeout = soTimeout;
|
this.soTimeout = soTimeout;
|
||||||
this.clientIdentity = new ClientIdentity(destination, (short) 1001);
|
this.clientIdentity = new ClientIdentity(destination, (short) 1001);
|
||||||
this.accessStrategy = accessStrategy;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void connect() throws CanalClientException {
|
public void connect() throws CanalClientException {
|
||||||
@@ -127,11 +123,12 @@ public class SimpleCanalConnector implements CanalConnector {
|
|||||||
|
|
||||||
private InetSocketAddress doConnect() throws CanalClientException {
|
private InetSocketAddress doConnect() throws CanalClientException {
|
||||||
try {
|
try {
|
||||||
if (accessStrategy != null) {
|
|
||||||
address = accessStrategy.nextNode();//实时获取一下最新的running节点,lubiao
|
|
||||||
}
|
|
||||||
channel = SocketChannel.open();
|
channel = SocketChannel.open();
|
||||||
channel.socket().setSoTimeout(soTimeout);
|
channel.socket().setSoTimeout(soTimeout);
|
||||||
|
SocketAddress address = getAddress();
|
||||||
|
if (address == null) {
|
||||||
|
address = getNextAddress();
|
||||||
|
}
|
||||||
channel.connect(address);
|
channel.connect(address);
|
||||||
Packet p = Packet.parseFrom(readNextPacket(channel));
|
Packet p = Packet.parseFrom(readNextPacket(channel));
|
||||||
if (p.getVersion() != 1) {
|
if (p.getVersion() != 1) {
|
||||||
@@ -441,6 +438,10 @@ public class SimpleCanalConnector implements CanalConnector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SocketAddress getNextAddress() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public SocketAddress getAddress() {
|
public SocketAddress getAddress() {
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,4 +32,9 @@ public class SimpleNodeAccessStrategy implements CanalNodeAccessStrategy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SocketAddress currentNode() {
|
||||||
|
return nodes.get(index);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import com.alibaba.otter.canal.common.utils.BooleanMutex;
|
|||||||
import com.alibaba.otter.canal.common.utils.JsonUtils;
|
import com.alibaba.otter.canal.common.utils.JsonUtils;
|
||||||
import com.alibaba.otter.canal.common.zookeeper.ZkClientx;
|
import com.alibaba.otter.canal.common.zookeeper.ZkClientx;
|
||||||
import com.alibaba.otter.canal.common.zookeeper.ZookeeperPathUtils;
|
import com.alibaba.otter.canal.common.zookeeper.ZookeeperPathUtils;
|
||||||
|
import com.alibaba.otter.canal.protocol.exception.CanalClientException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* clinet running控制
|
* clinet running控制
|
||||||
@@ -121,8 +122,9 @@ public class ClientRunningMonitor extends AbstractCanalLifeCycle {
|
|||||||
initRunning();
|
initRunning();
|
||||||
} else {
|
} else {
|
||||||
activeData = JsonUtils.unmarshalFromByte(bytes, ClientRunningData.class);
|
activeData = JsonUtils.unmarshalFromByte(bytes, ClientRunningData.class);
|
||||||
if(activeData.getAddress().contains(":") && isMine(activeData.getAddress())){
|
// 如果发现已经存在,判断一下是否自己,避免活锁
|
||||||
mutex.set(true);
|
if (activeData.getAddress().contains(":") && isMine(activeData.getAddress())) {
|
||||||
|
mutex.set(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (ZkNoNodeException e) {
|
} catch (ZkNoNodeException e) {
|
||||||
@@ -130,10 +132,13 @@ public class ClientRunningMonitor extends AbstractCanalLifeCycle {
|
|||||||
true); // 尝试创建父节点
|
true); // 尝试创建父节点
|
||||||
initRunning();
|
initRunning();
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
logger.error(MessageFormat.format("There is an error when execute initRunning method, with destination [{0}].",destination),t);
|
logger.error(MessageFormat.format("There is an error when execute initRunning method, with destination [{0}].",
|
||||||
zkClient.delete(path);
|
destination),
|
||||||
throw new RuntimeException("something goes wrong in initRunning method. ",t);
|
t);
|
||||||
}
|
// 出现任何异常尝试release
|
||||||
|
releaseRunning();
|
||||||
|
throw new CanalClientException("something goes wrong in initRunning method. ", t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user