Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

客户端高可用存在bug #171

Closed
lulu2panpan opened this issue Apr 25, 2016 · 7 comments
Closed

客户端高可用存在bug #171

lulu2panpan opened this issue Apr 25, 2016 · 7 comments
Labels
Milestone

Comments

@lulu2panpan
Copy link
Collaborator

问题场景

1,canal有两台服务器c1和c2,c1处于激活状态
2,客户端使用ClusterCanalConnector进行消费,也是两台服务器d1和d2,d1处于激活状态
3,c1发生宕机,此时d1会执行【ClusterCanalConnector】的restart()方法。restart中有三步:
第一步,disconnect,会释放running节点;
第二步,线程休眠5秒钟;
第三步,尝试重连,重连的时候会执行initRunning()方法。
4,在d1释放running节点后,d2会被立即触发,执行initRunning()方法,initRunning中也有两大步:
第一步,抢占running节点
第二步,执行processActiveEnter()方法,该方法肯定会报错,因为此时d2连接的canal也是c1,执行initRunning的zk线程会异常退出,此时d2的mutex变量仍然为false,并且没有释放running节点
5,d1后续的重连都没意义了,因为d2没有释放running节点,所以d1的mutext变成了false
6,最终结果是d1和d2都阻塞了
7,此时关闭d2,d1的initRunning方法会被触发,但d1的processActiveEnter方法仍然会报错,d1仍然无法恢复消费

@agapple
Copy link
Member

agapple commented Apr 25, 2016

  1. 确认一下canal的版本
  2. 你的第4步,d2启动链接的canal是c1是因为时效性问题么?d2未能及时发现c2已经是主?

如果可以明确重现,是否有修复的代码?

@lulu2panpan
Copy link
Collaborator Author

canal版本是1.0.20
很容易重现的,出现上述现象的原因在于【ClientRunningMonitor】的【initRunning方法】没有对【processActiveEnter()】抛出的异常做处理,把Zk上的running节点占住了没有释放,导致两个客户端的mutex都为false,都没有机会执行了。

修复代码正在写,涉及到高可用的代码比较绕,还没写好,您可以看看有没有简便的修改方法。

@lulu2panpan
Copy link
Collaborator Author

还有就是SimpleCanalConnector类中的doConnect方法
private InetSocketAddress doConnect() throws CanalClientException {
try {
channel = SocketChannel.open();
channel.socket().setSoTimeout(soTimeout);
channel.connect(address);

channel.connect(address);//此处的address应该即时取一次,否则D2永远没机会拿到最新的canal-server的ip

@lulu2panpan
Copy link
Collaborator Author

你的第4步,d2启动链接的canal是c1是因为时效性问题么?d2未能及时发现c2已经是主?

是的,没能发现,原因就在于这段代码

channel.connect(address);//此处的address应该即时取一次,否则D2永远没机会拿到最新的canal-server的ip

@agapple
Copy link
Member

agapple commented Apr 26, 2016

看了下代码,如果第4步,d2启动链接时拿到的是c1,会在initRunning执行doConnect时执行失败,原本期望是通过客户端发起restart操作来处理,而d2因为是热备,可能是在异步initRunning回调时报错,无法触发client端的restart而导致长时间挂起

@agapple
Copy link
Member

agapple commented Apr 26, 2016

想了下一种比较简单的改法

  1. initRunning针对执行异常时,主动释放running节点,通过异步回调来进行重试
  2. SimpleCanalConnector的doConnect方法动态获取address地址

@lulu2panpan
Copy link
Collaborator Author

是的,就是这么改的。
机器上没装git客户端
改造的代码发你邮箱了,jianghang115@gmail.com
抽时间看下吧

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants