草庐IT

ZK首次连接失败,第二次连接成功的问题排查和解决

醉酒思凡尘 2023-05-01 原文

ZK首次连接失败问题

问题

项目中配置zk后,启动时zk第一次链接总是失败,过一会后又会链接成功。异常如下:

17:04:22.932 [Curator-Framework-0] WARN  o.a.c.r.ExponentialBackoffRetry - [getSleepTimeMs,74] - Sleep extension too large (1100). Pinning to 500
17:04:23.433 [Curator-Framework-0] WARN  o.a.c.r.ExponentialBackoffRetry - [getSleepTimeMs,74] - Sleep extension too large (1350). Pinning to 500
17:04:23.935 [Curator-Framework-0] WARN  o.a.c.r.ExponentialBackoffRetry - [getSleepTimeMs,74] - Sleep extension too large (3300). Pinning to 500
17:04:24.438 [Curator-Framework-0] WARN  o.a.c.r.ExponentialBackoffRetry - [getSleepTimeMs,74] - Sleep extension too large (3750). Pinning to 500
17:04:24.939 [Curator-Framework-0] WARN  o.a.c.r.ExponentialBackoffRetry - [getSleepTimeMs,74] - Sleep extension too large (24450). Pinning to 500
17:04:25.440 [Curator-Framework-0] WARN  o.a.c.r.ExponentialBackoffRetry - [getSleepTimeMs,74] - Sleep extension too large (50350). Pinning to 500
17:04:25.943 [Curator-Framework-0] INFO  o.a.c.f.s.ConnectionStateManager - [postState,250] - State change: SUSPENDED
17:04:25.945 [Curator-Framework-0] ERROR o.a.c.f.i.CuratorFrameworkImpl - [logError,690] - Background operation retry gave up
org.apache.zookeeper.KeeperException$ConnectionLossException: KeeperErrorCode = ConnectionLoss
	at org.apache.zookeeper.KeeperException.create(KeeperException.java:102)
	at org.apache.curator.framework.imps.CuratorFrameworkImpl.checkBackgroundRetry(CuratorFrameworkImpl.java:851)
	at org.apache.curator.framework.imps.CuratorFrameworkImpl.performBackgroundOperation(CuratorFrameworkImpl.java:999)
	at org.apache.curator.framework.imps.CuratorFrameworkImpl.backgroundOperationsLoop(CuratorFrameworkImpl.java:952)
	at org.apache.curator.framework.imps.CuratorFrameworkImpl.access$300(CuratorFrameworkImpl.java:66)
	at org.apache.curator.framework.imps.CuratorFrameworkImpl$4.call(CuratorFrameworkImpl.java:342)
	at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266)
	at java.util.concurrent.FutureTask.run(FutureTask.java)
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)
17:04:25.946 [Curator-Framework-0] ERROR o.a.c.f.i.CuratorFrameworkImpl - [logError,690] - Background retry gave up

项目版本

<springboot.version>2.5.14</springboot.version>
<spring.cloud.version>2020.0.6</spring.cloud.version>
<org.apache.curator.version>5.1.0</org.apache.curator.version>
<zookeeper.version>3.6.0</zookeeper.version>


<dependency>
    <groupId>org.apache.zookeeper</groupId>
    <artifactId>zookeeper</artifactId>
    <version>${zookeeper.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-dependencies</artifactId>
    <version>${spring.cloud.version}</version>
</dependency>

异常原因分析

zk默认的connectionTimeout是15s(可以配置,这里用默认的),zk在这个时间之内没有连接成功,就会报出这个异常。经排查,链接超时,代码卡在解析ip的地方,1134行。

SaslServerPrincipal.getServerPrincipal(addr, clientConfig) 在进行解析配置的zk地址时,使用Sasl来进行解析。继续追查发现,使用 Inet6AddressImpl来解析,具体实现方法,是一个Native方法。

这里就比较奇怪了,项目只是配置了一个ip地址,却要默认进行 Inet6 来进行解析。主要原因,是 1129 行的 clientConfig.isSaslClientEnabled(),在 ZKClientConfig 中,这个参数默认为true。为啥默认是true,请看 https://issues.apache.org/jira/browse/ZOOKEEPER-1657

并且 spring cloud 在自动配置 zk CuratorFramework 的时候,使用了默认的 DefaultZookeeperFactory 构造器。

这里并没有传入 ZKClientConfig,因此,Zookeeper 将会使用默认的ZKClientConfig 来进行配置。默认的如下所示:

解决办法

关闭 saslClientEnabled 即可。

  1. 添加 -Dzookeeper.sasl.client=false
java -jar -Dzookeeper.sasl.client=false xxx.jar
  1. 让spring cloud 在自动配置 zk CuratorFramework 的时候,不要使用默认的 DefaultZookeeperFactory。
    zk 自动配置源码如下:

    源码中画红框处,可以使用自定义的CuratorFramework 提供者。因此我们对项目进行改造,实现 CuratorFrameworkCustomizer 接口,使用自定义的 DefaultZookeeperFactory ,并且配置 ENABLE_CLIENT_SASL_KEY 为 false 即可。
@Configuration
public class ZookeeperConfigurer implements CuratorFrameworkCustomizer {
    @Override
    public void customize(CuratorFrameworkFactory.Builder builder) {
        builder.zookeeperFactory(new DefaultZookeeperFactory());
    }

    public class DefaultZookeeperFactory implements ZookeeperFactory {
        public DefaultZookeeperFactory() {
        }

        @Override
        public ZooKeeper newZooKeeper(String connectString, int sessionTimeout, Watcher watcher, boolean canBeReadOnly) throws Exception {
            ZKClientConfig zkClientConfig = new ZKClientConfig();
            zkClientConfig.setProperty(ZKClientConfig.ENABLE_CLIENT_SASL_KEY, "false");
            return new ZooKeeper(connectString, sessionTimeout, watcher, canBeReadOnly, zkClientConfig);
        }
    }
}

重启项目,发现zk首次链接失败的问题,已经解决。

有关ZK首次连接失败,第二次连接成功的问题排查和解决的更多相关文章

  1. ruby - 续集在添加关联时访问many_to_many连接表 - 2

    我正在使用Sequel构建一个愿望list系统。我有一个wishlists和itemstable和一个items_wishlists连接表(该名称是续集选择的名称)。items_wishlists表还有一个用于facebookid的额外列(因此我可以存储opengraph操作),这是一个NOTNULL列。我还有Wishlist和Item具有续集many_to_many关联的模型已建立。Wishlist类也有:selectmany_to_many关联的选项设置为select:[:items.*,:items_wishlists__facebook_action_id].有没有一种方法可以

  2. ruby - 无法在 60 秒内获得稳定的 Firefox 连接 (127.0.0.1 :7055) - 2

    我使用的是Firefox版本36.0.1和Selenium-Webdrivergem版本2.45.0。我能够创建Firefox实例,但无法使用脚本继续进行进一步的操作无法在60秒内获得稳定的Firefox连接(127.0.0.1:7055)错误。有人能帮帮我吗? 最佳答案 我遇到了同样的问题。降级到firefoxv33后一切正常。您可以找到旧版本here 关于ruby-无法在60秒内获得稳定的Firefox连接(127.0.0.1:7055),我们在StackOverflow上找到一个类

  3. ruby - 即使失败也继续进行多主机测试 - 2

    我已经构建了一些serverspec代码来在多个主机上运行一组测试。问题是当任何测试失败时,测试会在当前主机停止。即使测试失败,我也希望它继续在所有主机上运行。Rakefile:namespace:specdotask:all=>hosts.map{|h|'spec:'+h.split('.')[0]}hosts.eachdo|host|begindesc"Runserverspecto#{host}"RSpec::Core::RakeTask.new(host)do|t|ENV['TARGET_HOST']=hostt.pattern="spec/cfengine3/*_spec.r

  4. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  5. ruby-on-rails - 创建 ruby​​ 数据库时惰性符号绑定(bind)失败 - 2

    我正在尝试在Rails上安装ruby​​,到目前为止一切都已安装,但是当我尝试使用rakedb:create创建数据库时,我收到一个奇怪的错误:dyld:lazysymbolbindingfailed:Symbolnotfound:_mysql_get_client_infoReferencedfrom:/Library/Ruby/Gems/1.8/gems/mysql2-0.3.11/lib/mysql2/mysql2.bundleExpectedin:flatnamespacedyld:Symbolnotfound:_mysql_get_client_infoReferencedf

  6. ruby - 正则表达式在哪个位置失败? - 2

    我需要一个非常简单的字符串验证器来显示第一个符号与所需格式不对应的位置。我想使用正则表达式,但在这种情况下,我必须找到与表达式相对应的字符串停止的位置,但我找不到可以做到这一点的方法。(这一定是一种相当简单的方法……也许没有?)例如,如果我有正则表达式:/^Q+E+R+$/带字符串:"QQQQEEE2ER"期望的结果应该是7 最佳答案 一个想法:你可以做的是标记你的模式并用可选的嵌套捕获组编写它:^(Q+(E+(R+($)?)?)?)?然后你只需要计算你获得的捕获组的数量就可以知道正则表达式引擎在模式中停止的位置,你可以确定匹配结束

  7. ruby - 使用 rbenv 和 ruby​​-build 构建 ruby​​ 失败,出现 undefined symbol : SSLv2_method - 2

    我正在尝试在配备ARMv7处理器的SynologyDS215j上安装ruby​​2.2.4或2.3.0。我用了optware-ng安装gcc、make、openssl、openssl-dev和zlib。我根据README中的说明安装了rbenv(版本1.0.0-19-g29b4da7)和ruby​​-build插件。.这些是随optware-ng安装的软件包及其版本binutils-2.25.1-1gcc-5.3.0-6gconv-modules-2.21-3glibc-opt-2.21-4libc-dev-2.21-1libgmp-6.0.0a-1libmpc-1.0.2-1libm

  8. ruby - 我的 Ruby IRC 机器人没有连接到 IRC 服务器。我究竟做错了什么? - 2

    require"socket"server="irc.rizon.net"port="6667"nick="RubyIRCBot"channel="#0x40"s=TCPSocket.open(server,port)s.print("USERTesting",0)s.print("NICK#{nick}",0)s.print("JOIN#{channel}",0)这个IRC机器人没有连接到IRC服务器,我做错了什么? 最佳答案 失败并显示此消息::irc.shakeababy.net461*USER:Notenoughparame

  9. ruby-on-rails - Ruby 的 'open_uri' 是否在读取或失败后可靠地关闭套接字? - 2

    一段时间以来,我一直在使用open_uri下拉ftp路径作为数据源,但突然发现我几乎连续不断地收到“530抱歉,允许的最大客户端数(95)已经连接。”我不确定我的代码是否有问题,或者是否是其他人在访问服务器,不幸的是,我无法真正确定谁有问题。本质上,我正在读取FTPURI:defself.read_uri(uri)beginuri=open(uri).readuri=="Error"?nil:urirescueOpenURI::HTTPErrornilendend我猜我需要在这里添加一些额外的错误处理代码...我想确保我采取一切预防措施来关闭所有连接,这样我的连接就不是问题所在,但是我

  10. ruby-on-rails - 连接字符串时如何在 <%=%> block 内输出 html_safe? - 2

    考虑一下:现在这些情况:#output:http://domain.com/?foo=1&bar=2#output:http://domain.com/?foo=1&bar=2#output:http://domain.com/?foo=1&bar=2#output:http://domain.com/?foo=1&bar=2我需要用其他字符串输出URL。我如何保证&符号不会被转义?由于我无法控制的原因,我无法发送&。求助!把我的头发拉到这里:\编辑:为了澄清,我实际上有一个像这样的数组:@images=[{:id=>"fooid",:url=>"http://

随机推荐