当前位置: 首页 > 科技观察

NacosClient1.4.1版本踩坑记录

时间:2023-03-16 10:22:31 科技观察

本文转载自微信公众号《桐人的技术分享》,作者kiritomoe。转载本文请联系桐人的技术分享公众号。这个问题是本周才发现的。收到MSENacos用户反馈,线上Nacos不可用,服务下线,日志中有大量报错。本文主要记录该问题的排查过程及解决方法。首先,看看用户报错的情况。日志如下:另外,用户反馈的业务日志中有大量报错找不到服务地址,说明Nacos服务下线了。马上查看了服务器的监控,发现用户的MSENacos集群正常,cpu/内存等指标都有下降,没有任何异常行为,排除了服务器异常的可能。然后他将注意力集中在客户身上。老实说,这是我第一次看到这个错误报告。查看异常堆栈,字面意思就是域名解析有问题。此次报错持续了10分钟左右,随即要求用户在服务节点上使用ping、dig等工具确认域名解析是否正常,测试未发现异常。继续让用户telnetmse-xx.com8848,发现telnet也能通过。根据这些现象,大概可以判断是用户机器存在短期域名解析问题,导致短期访问MSENacos。但是不断有用户反映,部分重启的机器已经恢复,但是没有重启的机器仍然出现调用错误。不然重启大法就好了,但也加深了问题的诡异。就在我一头雾水的时候,另一个用户上来发现了同样的问题,而且由于第二个用户同时也使用了redis,所以除了nacos的域名解析问题之外,redis的域名解析错误是也在错误日志中报告。至此,我已经证实了我之前的猜测,根本原因肯定是域名解析出了问题,影响了这两个用户。但问题是,为什么短暂的域名解析失败(10分钟左右)会导致Nacos问题持续存在?而且只有重启才能恢复。通过分析这两个用户的共性,我和同事最终将可疑点锁定在了Nacos客户端版本上。经过对比发现,用户都报同样的错误,而且都是nacos-client版本1.4.1。Nacos1.4.1版本引入的bug在问题出现时出现。Nacos1.x的最新版本已经是Nacos1.4.2。查看版本1.4.1的源代码并跟踪堆栈附近的问题。上面的代码是访问Nacos服务器端的一段代码,进入595行查找。我们成功找到了栈中的直接错误,也就是这个IsIPv4的判断触发器。splitIPPortStr方法的主要逻辑是从Nacos连接字符串中过滤出连接地址,主要是判断默认端口号。如果用户不携带8848,则默认带8848。但问题恰恰在这里:InetAddress.getByName(addr)是一个内置方法,描述如下:给定一个主机的名称,根据系统上配置的名称服务返回一个其IP地址数组。意思是传递一个域名给操作系统,返回一串IP。这不是域名解析是的!我当时很好奇,你说你判断IPv4格式,为什么要这样判断?直接判断IPv4pattern不就好了吗?而这段代码恰恰是造成问题的凶手之一。我们来看看1.4.2。这个逻辑已经修好了,直接改成了正则判断。但问题仍然存在。域名解析短时间失败。为什么所有的服务都下线了,解析恢复后,服务还是没有上线?继续跟踪这段代码,发现代码callServer会是com.alibaba。Nacos.client.naming.beat.BeatReactor用于维护自身和Nacos的心跳。但是由于上面的域名解析失败,抛出的异常是IllegalArgumentException,并没有被内层方法转化为NacosException,导致心跳线程没有捕捉到异常,彻底停止发送心跳!这也成功地解释了为什么短命域名如果解析失败,所有服务都会下线。(nacos使用心跳维护和服务端生存状态)改进建议修改isIPv6和isIPv4的判断方式为正则匹配。如上所述,这已在1.4.2中修复。心跳线程必须保证下一次心跳的提交不会异常中断。第二点,也已经定下来了。综上所述,nacos-client1.4.1存在严重bug。如果客户端与NacosServer之间出现短期域名解析问题,心跳将永久丢失,从而导致所有服务下线。即使网络恢复,心跳也不会自动恢复。域名解析失败常见于K8s环境下网络抖动或coreDNS访问超时等场景。为避免域名解析对Nacos造成较大影响,请务必检查应用代码中使用的nacos-client版本。该问题仅在1.4.1版本存在,低版本不受该问题影响。建议使用1.4.1的用户升级到1.4.2以避免此问题。使用SpringCloud/Dubbo的用户??需要确认实际框架使用的nacos-client版本。你可以通过显式指定nacos-client的版本来覆盖框架的默认版本。Dubbo用户要格外小心。Dubbo2.7.11版本默认使用nacos-client1.4.1。一定要明确指定nacos-client的版本为1.4.2。Dubbo也将在下一个版本中替换默认版本的Nacos。