-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
AllConnectConnectionHolder心跳重试线程优化讨论 #1442
Comments
关于2 。看了下应该是说如果一台都没有,他会做一个关闭动作, closeTransports(),这个动作应该会触发 all/alive/retry的clear
也就是说这里update完,你们的empty情况应该会做alive和retry的清理的。 所以没有做 update是因为做了close。然后参考这个bug,有没有可能因为日志级别被设置成 warn disable 导致没有做 close transport? |
是的,我们这个日志是info级别,所以这个函数没进去 if (LOGGER.isWarnEnabled(consumerConfig.getAppName())) { 那么,是否会考虑将该BUG解决 |
会的,下个版本就修一下。不过Info级别理论上应该是 warn enable 的🤔 |
我刚debug了源码,发现在 之前还有一个!ProviderHelper.isEmpty(oldProviderGroup)的判断,这个if,在provider只有一台,且重启的情况下,是不会命中上述的代码的,所以,这个还是一个bug。 |
这个场景下, oldProviderGroup 应该是不为空的?有一个 provider的数据? 他可能会进来多次,第一次应该是provider重启导致 client需要更新为空,本次更新应该是 oldProviderGroup.len == 1 -> providerGroupToUpdate.len == 0, 并在本次做了 closeTransports? 按理说这样才是符合预期的 |
我debug之后,流程如下: |
嗯,看了下这里 oldProviderGroup是个浅拷贝,只是个对SingleGroupAddressHolder.providerGroup的引用,所以SingleGroupAddressHolder.providerGroup 更新时 oldProviderGroup 指向的内容也更新了。 这里应该是 oldProviderGroup 失去了 作为 old 的意义。从设计初衷来看这里可能要考虑做个深拷贝。 |
另外我提到的第一点,【建议com.alipay.sofa.rpc.client.AllConnectConnectionHolder#startReconnectThread 机制加上最大重试次数,若失败次数超过x.则将该连接彻底移除。】,是否会考虑呢 |
这个还需要详细评估一下。provideGroup数据是来自注册中心的,一般情况下我们应该是去信任注册中心传递来的元数据。没有收到注册中心数据的情况下移除连接,可能会在其他一些情况下引发问题。 |
明白,不过其实只要解决了oldProviderGroup 被覆盖的问题,就不存在这个最大重试次数的必要性了。 |
… && adjust the location of method called [closeTransports();] (sofastack#1442) - sofastack#1442
Your question
Consumer中,ConnectConnectionHolder负责管理所有provider的长连接。
其中,com.alipay.sofa.rpc.client.AllConnectConnectionHolder#startReconnectThread 函数,会启动一个异步线程,每隔一段时间去检查的长连接是否健康。
如果AllConnectConnectionHolder中的aliveConnections(存活的客户端列表)无法连接,就会将该长连接从aliveConnections中移除,加入到retryConnections(失败待重试的客户端列表)中,假如retryConnections中的连接恢复正常,会把该长连接从retryConnections中移除,加回至 aliveConnections中。
这段逻辑见:com.alipay.sofa.rpc.client.AllConnectConnectionHolder#doReconnect 函数。
如果retryConnection一直没连上, transport.connect();函数底层会调用至com/alipay/sofa/rpc/transport/bolt/ReuseBoltClientConnectionManager#getConnection方法,该方法会打印warn日志:
get connection failed in url
正常情况,很难去执行到AllConnectConnectionHolder的重试线程,因为provider从注册中心下线,注册中心会向consumer主动推送,consumer会去摘除该长连接。
但我们在实战中,有两个场景碰到了此类问题,会导致以上get connection failed in url的warn日志疯狂打印,造成困扰。
Your scenes
目前,我们服务都是以容器化部署,若宿主机的资源不足,在重启provider服务的时候,原provider的容器ip可能会发生变化。
情况1:
假如consumer没收到注册中心老provider ip下线节点的通知,就会复现get connection failed in url 疯狂打印的场景。
补充说明:因为宿主机ip分配问题,老的provider ip已经永远消失,provider是以一个新的ip注册到注册中心,但老的provider ip仍一直保留在AllConnectConnectionHolder中的retryConnections中,所以会导致warn日志疯狂打印。
情况2:
注册中心摘除provider节点代码设计不合理。
背景:灰度环境和测试环境集群只有一台provider
通过分析源码,定位到consumer摘除provider下线节点的代码在:
com.alipay.sofa.rpc.client.AbstractCluster#updateProviders 函数。
但是该函数做了一个判断:
如果provider中一个节点都没有,只做了 addressHolder.updateProviders(providerGroup);并没有去做 connectionHolder.updateProviders(providerGroup); 而connectionHolder.updateProviders(providerGroup); 底层是会把下线节点从aliveConnections或者retryConnections中删除。 删除的代码在:AllConnectConnectionHolder#remove函数中。
这样会导致,即使consumer收到了provider下线的通知,因为provider在灰度和测试环境只有一台机器,provider重启过程中,就命中了ProviderHelper.isEmpty(providerGroup) 分支,并不会去执行connectionHolder.updateProviders(providerGroup);函数。 该下线的IP一直还在 AllConnectConnectionHolder中的retryConnections属性中。
假如灰度环境或者测试环境的provider ip发生了变化,但老的provider ip仍一直保留在AllConnectConnectionHolder中的retryConnections中,也会导致warn日志疯狂打印。
Your advice
1、建议com.alipay.sofa.rpc.client.AllConnectConnectionHolder#startReconnectThread 机制加上最大重试次数,若失败次数超过x.则将该连接彻底移除。
2、没懂为何provider一台机器没有的情况下,不去执行connectionHolder.updateProviders(providerGroup)函数,希望作者可以解释下如此设计的原因。
Environment
-windows/mac
The text was updated successfully, but these errors were encountered: