重新连接后如何避免双重连接关闭?

Posted

技术标签:

【中文标题】重新连接后如何避免双重连接关闭?【英文标题】:How to avoid double connection close upon regaining connectivity? 【发布时间】:2017-12-04 23:34:12 【问题描述】:

在这些情况下:

    客户端失去与 zk 的网络连接。 一分钟过去了。 客户端重新获得与 zk 的网络连接。

我得到以下恐慌:

panic: close of closed channel

goroutine 2849 [running]:
github.com/samuel/go-zookeeper/zk.(*Conn).Close(0xc420795180)
  github.com/samuel/go-zookeeper/zk/conn.go:253 47
github.com/curator-go/curator.(*handleHolder).internalClose(0xc4203058f0, 0xc420302470, 0x0)
  github.com/curator-go/curator/state.go:136 +0x8d
github.com/curator-go/curator.(*handleHolder).closeAndReset(0xc4203058f0, 0xc42587cd00, 0x1e)
  github.com/curator-go/curator/state.go:122 +0x2f
github.com/curator-go/curator.(*connectionState).reset(0xc420302420, 0x1b71d87, 0xf)
  github.com/curator-go/curator/state.go:234 +0x55
github.com/curator-go/curator.(*connectionState).handleExpiredSession(0xc420302420)
  github.com/curator-go/curator/state.go:351 +0xd9
github.com/curator-go/curator.(*connectionState).checkState(0xc420302420, 0xffffff90, 0x0, 0x0, 0xc425ed2600, 0xed0e5250a)
  github.com/curator-go/curator/state.go:318 +0x9c
github.com/curator-go/curator.(*connectionState).process(0xc420302420, 0xc425ed2680)
  github.com/curator-go/curator/state.go:299 +0x16d
created by github.com/curator-go/curator.(*Watchers).Fire
  github.com/curator-go/curator/watcher.go:64 +0x96

这是详细的事件顺序:

    客户端失去与 zk 的网络连接。 一分钟过去了。 客户端重新获得与 zk 的网络连接。 goroutine A 调用s.ReregisterAll() -> Conn() -> checkTimeout() -> reset (bc 1 分钟过去了) -> closeAndReset() -> conn.Close() 可以阻塞一秒钟 goroutine B 处理zk.StateExpired(zk 集群发送这个 bc,它认为这个客户端已经死了,因为它在 2 期间没有 ping。) -> reset -> closeAndReset() -> conn.Close() 导致恐慌因为conn.Close() 已经关闭了连接的c.shouldQuit 通道并且s.zooKeeper.getZookeeperConnection 从未被goroutine A 调用,因为它正在阻塞第二个所以没有新的连接。

我尝试的一个简单的解决方案是在reset 上使用互斥锁,但现在我得到的helper.GetConnectionString() 等于空字符串。当客户端丢失然后重新获得网络连接时,避免这种崩溃并尝试进入良好状态的最佳方法是什么?是否应该在github.com/samuel/go-zookeeper 的不让您关闭已经关闭的连接的实现中进行修复?

(我已经提交了这个问题here,但该项目似乎缺乏讨论,所以我问这个问题。)

【问题讨论】:

我不熟悉这些库,但是在仔细阅读了代码之后,我有一个问题。您是否需要它完全丢弃zk.Conn 并拨打一个新的,或者您是否需要它保留并允许重新连接。如果你想丢弃,那么你的问题可能出在github.com/curator-go/curator,否则问题出在github.com/samuel/go-zookeeper。我不确定我在这里是否真的能帮上大忙,但这可能是您可以通过其他库解决的问题。 我认为两者都行。这种区别对我来说是解决这个问题的一个很好的起点。 我认为解决这个问题的简单方法是 make fork of go-zookeeper ,因为这个问题很久以前就提出了。 github.com/samuel/go-zookeeper/issues/148 我同意 @mattn 的观点,即分叉并为您的用例修复它可能是短期内最简单的解决方案,但除非您完全了解你所做的改变。谨慎使用,尽量减少修改,并尽可能进行测试。 【参考方案1】:

zk.Conn 有一个 State() 方法,它返回一个枚举“State”,它是以下之一:

type State int32
const (
    StateUnknown           State = -1
    StateDisconnected      State = 0
    StateConnecting        State = 1
    StateAuthFailed        State = 4
    StateConnectedReadOnly State = 5
    StateSaslAuthenticated State = 6
    StateExpired           State = -112

    StateConnected  = State(100)
    StateHasSession = State(101)
)

goroutine B 调用 conn.Close() 时“conn”处于什么状态?

一种可能的解决方案是在 goroutine B 中添加一个开关,如果您在 conn.StateConnecting 中,则不要调用 conn.Close()。

【讨论】:

以上是关于重新连接后如何避免双重连接关闭?的主要内容,如果未能解决你的问题,请参考以下文章

OpenOffice.org 关闭后如何重新连接?

socket.io 1.2.1 如何在重新连接后修复双重事件

数据库连接失败时,如何捕捉错误,避免弹出错误提示,以便下次自动重新连接

Python:远程服务器关闭后自动重新连接 ssh 隧道

Socket.io - nodejs 服务器端。重新连接后传输关闭

加入 *** 后 AWS RDP 断开连接 [关闭]