有一天,同事突然说zk客户端连接不上服务器。考虑到最近业务代码没有改动,怀疑是运维同学操作不当,赶紧联系运维同学,果然最近做了改动。为了避免扩大影响范围,先让运维同学回滚变更,回滚后才能正常访问。向运维同学询问复现问题后,得到了变更过程:由于zk集群中有一台服务器存在性能风险,需要变更为新的实例。于是运维先把新机器加入zk集群,在旧服务器上修改配置,一台一台重启。重启后,新zk的角色就是leader。意想不到的结果是,使用mntr命令查看,所有机器状态都正常,但是zk客户端无法访问,一访问就卡死。测试环境可以稳定复现问题。故障排除1猜测是zk端口没有监听成功。登录服务器,使用netstat查看服务器打开的三个端口状态是否正常。您也可以使用telnet来测试您是否可以连接。2猜测是同步节点数少于一半,或者follower无法连接到leader触发重选,不过很快排除,因为上面提到使用mntr命令查看节点状态是正常的,从日志中找不到对应的日志记录。3然后我们用stat观察服务端的连接状态,运行zk客户端发现服务端已经收到了客户端的请求,但是还没有响应消息。看来原因是zkserver没有处理客户端的请求。跟踪到这里后,应该进入源码了。由于对zk源码不熟悉,所以请教了某大佬,建议大家看一下zk请求处理类CommitProcessor。我们在CommitProcessor中找到了原因,代码如下:publicvoidshutdown(){LOG.info("Shuttingdown");halt();if(workerPool!=null){workerPool.join(workerShutdownTimeoutMS);}if(nextProcessor!=null){nextProcessor.shutdown();}}在shutdown中调用workerPool.join来实际关闭请求处理开关,但不会将workerPool设置为null。在start方法中会根据workerPool==null创建WorkerService并开始处理请求。修改后重新验证解决。
