Docker部署Dubbo-SpingBoot假死的踩坑经历 – 记忆角落

Docker部署Dubbo-SpingBoot假死的踩坑经历

/ 0评 / 2

Docker部署Dubbo-SpingBoot假死的踩坑经历

描述

最近公司需要把一些java程序都全面转到Docker容器部署启动,而其中sys的Springboot服务启动异常的慢,就是无法显示以下启动过程耗时多长,内置Tomcat 也一直等待无法启动成功...正常情况下启动完成后出现以下情况:

2022-08-24 12:33:28.368 | INFO  | o.a.c.h.Http11NioProtocol: 173 | Starting ProtocolHandler ["http-nio-10001"]
2022-08-24 12:33:28.391 | INFO  | o.s.b.w.e.t.TomcatWebServer: 202 | Tomcat started on port(s): 10001 (http) with context path ''
2022-08-24 12:33:28.395 | INFO  | c.x.s.SysApplication: 59 | Started SysApplication in 16.628 seconds (JVM running for 17.347)

问题分析

通过Arthas去监控,发现是nacos一直tw,开始就怀疑是否是容器网络之间无法互通造成的,因为之前需求POC验证时候我这边是直接nacos和Springboot服务都在一个单独桥接网络中,这次是直接默认在docker0的默认桥接网络上。但问题就只是在sys服务中才出现,其他的服务能快速启动,再结合nacos日志,已排查是nacos问题。

期间也怀疑过是否为服务器内核与docker版本问题,也进行了升级到centos7.9,docker也是最新版本,依旧是看运气的能启动(可能过个30分钟/或者半天即可启动完成),这种不稳定的因素其实还是有问题

诡异的是,当怀疑是否有可能是容器镜像问题时候,启动一个基础的openjdk8/java8镜像,单独把jar包丢进去运行就能正常快速启动。

于是乎,从怀疑nacos-->服务器内核-->容器镜像,当自己也没办法时候,就看到启动一个基础镜像容器中的/etc/hosts和我正常映射/etc/hosts文件是有区分的

镜像容器

image-20220824144724561

宿主机

image-20220824144648371

于是乎,不挂载/etc/hosts文件,卧槽...正常启动了...那证明是sys服务中是需要获取到主机名才能正常的启动,否则需要等待一段时间才行。

后就梳理了一下sys服务的启动逻辑

image-20220824145353129

启动除了Nacos,就剩下是Dubbo了。于是乎仔细观察sys启动过程的日志发现 hostname是"UNKNOWN"

image-20220824145705462

那就测试了挂载/etc/hosts,运行容器时,额外指定hostname名称--hostname localhost,启动正常了。问题也就定位到是Dubbo无法获取到主机名,因为如果不指定主机名,容器中的主机名就是 容器id,但挂载/etc/hosts后,原来容器的文件已经被覆盖,且无法找到主机名对应的ip。因此一直等待...?

具体Dubbo代码分析

img

这个方法源码比较长,看起来比较费劲,不过好在这个方法注释上已经写明白 IP 地址查找顺序。

Register & bind IP address for service provider, can be configured separately. Configuration priority: environment variables -> java system properties -> host property in config file -> /etc/hosts -> default network address -> first available network address

查找顺序如图所示:

img

解析过程,Dubbo 将会过滤无用 IP,过滤规则如下:

image-20200201203655297

下面将结合图示讲解查找顺序,只要其中一步读取 IP 符合上述规则,方法就会返回。

第一步将会调用 ServiceConfig#getValueFromConfigenvironment variablesjava system properties 配置 IP 地址。

img

这种方式通过在 JVM 启动参数中显示指定 IP

-DDUBBO_IP_TO_BIND=1.2.3.4

第二步通过读取 Dubbo 配置文件配置变量获取 IP

<!-- protocol 指定整个 Dubbo 应用服务默认 IP -->
<dubbo:protocol host="1.2.3.4"/>
<!-- provider 指定 Dubbo 应用具体某个服务默认 IP -->
<dubbo:provider host="1.2.3.4"/>

第三步通过调用 InetAddress.getLocalHost().getHostAddress() 获取本地 IP。该方法将会获取机器 hostname,然后再在 /etc/hosts 配置文件中查找 hostname 对应的配置 IP。

img

第四步通过 socket 连接注册中心从而获取本机 IP。

如果上述几步都不成功,Dubbo 将会轮询本机所有网卡,直到找到合适的 IP 地址。

img

总结

这次的问题其实不大(也就花费了3天时间折腾),就是 hosts 文件配置错误,Dubbo一直轮询都找不到hostname对应的ip,导致卡死状态,因此在docker run时,指定主机名即可

参考

Dubbo代码分析参考:https://www.cnblogs.com/goodAndyxublog/p/12319868.html

发表评论

您的电子邮箱地址不会被公开。