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

mysql长时间没数据,可能导致canal与mysql的连接读操作永远阻塞 #188

Closed
chelubaiq opened this issue Jun 18, 2016 · 21 comments

Comments

@chelubaiq
Copy link

canal从mysql读binlog事件时,建的连接设置了读超时时间: channel.socket().setSoTimeout(this.soTimeout); ,soTimeout用了30s。

读binlog事件时,用了SocketChannel.read(buffer)方法,soTimeout对这个SocketChannel的read方法无效,永远不会超时,参考http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4614802。

如果mysql有一段时间没数据(比如一个小时),这个连接失效了(可能因为防火墙问题,参考http://www.tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html的2.4. 虽然设置了channel.socket().setKeepAlive(true),但是linux系统默认的keepalive配置时间太长、不起作用。),但canal还在永远阻塞read。

所以是不是用sock.socket().getInputStream()这个来read比较好,如果在soTimeout内没读到数据,就超时了,强制重新建立连接。

@agapple
Copy link
Member

agapple commented Jun 21, 2016

目前设计时依赖于MySQL数据库的空闲链接超时机制,默认是8小时会断开链接,你的链接失效是指半开链接么?这个客户端能获取到EOFException

@tianshazzq
Copy link

这个问题在我自己的测试环境中很容易重现,mysql版本:5.5.14 wait_timeout设为8小时,canal版本1.0.22,如果mysql半个小时无数据更新,canal就无法读取新的bin-log,重启canalServer后就正常了。难道跟数据库的配置有关系,还是其他原因?期望能得到指导。

@tianshazzq
Copy link

PS:CanalServer没有任何的错误日志,不好分析问题。。。

@agapple
Copy link
Member

agapple commented Jul 18, 2016

暂时性解决方案,可以开启下心跳SQL. 这问题还真没遇到过

@chelubaiq
Copy link
Author

mysql的slave连接master读数据的默认超时时间(slave_net_timeout)是3600s(时间太长),超时后重建连接,参考http://dev.mysql.com/doc/refman/5.6/en/replication-options-slave.html#sysvar_slave_net_timeout

mysql5.5后好像引入了master/slave之间的heartbeat binlog event,master没binlog event空闲一段时间后(超过MASTER_HEARTBEAT_PERIOD)就发送给slave heartbeat事件。参考:
https://www.percona.com/blog/2011/12/29/actively-monitoring-replication-connectivity-with-mysqls-heartbeat/
http://dev.mysql.com/doc/refman/5.6/en/change-master-to.html里的MASTER_HEARTBEAT_PERIOD

MASTER_HEARTBEAT_PERIOD的默认配置是slave_net_timeout/2,默认是1800s,时间都太长了。

@tianshazzq 可以测试下这些参数试试。

canal程序想要支持默认配置、不出问题,最好还是像开头说的那样自己控制超时时间、连接空闲一段时间(比如最多1min?)后重新建连接。

@githubcjh
Copy link

mysql与canl-server的tcp连接闪断,canl-server并不知情,导致后续的binlog无法通知到canal-server,这个怎么破?

@agapple
Copy link
Member

agapple commented Nov 28, 2016

建议开启canal心跳设置,会定时更新数据库来产生心跳binlog,如果指定时间没收到心跳信息可以尝试重建链接

@flying-penguins
Copy link

mysql到canal的连接异常了,比如mysql宕机这种情况,canal是被动接收数据的,自然是不会知道任何链路是否正常的状态;关键是canal是否实现了空闲后有无重连的机制或者mysql异常重连?如若实现了配置哪个参数?

@agapple
Copy link
Member

agapple commented Dec 6, 2016

canal基于被动监听式的是没法感知socket被server断开的,最重要还是开启心跳binlog,或者升级mysql5.6(mysql针对空闲链接会定时发送心跳binlog事件来维持tcp链接)

@flying-penguins
Copy link

flying-penguins commented Dec 6, 2016

在Mysql宕机后重启这种情况下面的,开启心跳没什么用吧?我们需要在canal中实现mysql这个参数slave_net_timeout所需要实现的功能。

@dwoon
Copy link

dwoon commented Jan 18, 2017

@agapple 把数据库断开时间改成了2分钟,并且开启了心跳检查。长时间(2分钟以上)没有数据后新插入数据,canal server会获取不到 (过不定时间后canal server又能获取到数据10~30分钟不等)。debug看心跳数据都是能正常收发。日志里没有任何异常输出

detecing config

canal.instance.detecting.enable = true
#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

@lan1994
Copy link

lan1994 commented May 15, 2017

mysql与canl-server的tcp连接闪断,canl-server并不知情,导致后续的binlog无法通知到canal-server,这个怎么破?

这个问题你怎么解决的,我现在也遇到了这个问题 @githubcjh

@shuhaoc
Copy link

shuhaoc commented Nov 29, 2017

刚刚踩到一个坑,canal.instance.memory.buffer.size设置过小,导致主库执行大事务时,canal堵住

@agapple
Copy link
Member

agapple commented Dec 4, 2017

buffer.size建议设置>1024

@mailzyok
Copy link

确实有这个问题,不知道楼主解决了这个问题么? 改为inputstream是可以的,sotimeout生效了,但是长时间没有数据,inputstream 阻塞在read那里时不会响应thread.interrupt(),event parser那里需要做一些改动先close socket再调用thread.interrupt(),但是总感觉这个方法和canal的nio设计有些矛盾。但是问题是现实存在的。虽然是nio但是读的时候用的是阻塞的模式

@mailzyok
Copy link

buffer size能解决这个问题??

@gdutliuyun827
Copy link

解决方案就是在读取mysql binlog变更的地方加个超时就好,不然就只能依赖tcp的keeplive机制;我不太懂java,已经没用这一套了,自己开发了一套。

@vamdt
Copy link

vamdt commented Mar 16, 2018

SocketChannel.read(buffer)此方法的确不会报超时异常(https://stackoverflow.com/questions/2866557/timeout-for-socketchannel-doesnt-work#answer-9150513),目前本人使用1.0.24版本,暂时将DirectLogFetcher使用的SocketChannel转为ReadableByteChannel,可使socket timeout 生效,抛出SocketTimeoutException。

@agapple
Copy link
Member

agapple commented Mar 16, 2018

@vamdt BioSocketChannelPool.java,基于原生Socket操作,soTimeout参数验证也可以生效

@vamdt
Copy link

vamdt commented Mar 19, 2018

@agapple OK,暂时使用体验上感觉1.0.24更稳,等1.0.26正式发布再试试看BIO的。

@agapple
Copy link
Member

agapple commented Oct 24, 2018

推荐v1.1.1版本,基于原生Socket的bio操作,增加了超时重连机制

@agapple agapple closed this as completed Oct 24, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests