性能文章>What?一个 Dubbo 服务启动要两个小时!>

What?一个 Dubbo 服务启动要两个小时!原创

1年前
711219

前言

前几天在测试环境碰到一个非常奇怪的与 dubbo 相关的问题,事后我在网上搜索了一圈并没有发现类似的帖子或文章,于是便有了这篇。

希望对还未碰到或正在碰到的朋友有所帮助。

现象

现象是这样的,有一天测试在测试环境重新部署一个 dubbo 应用的时候发现应用“启动不起来”。

但过几个小时候之后又能自己慢慢恢复,并能够对外提供 dubbo 服务。

image.png

但其实经过我后续排查发现刚开始其实并不是启动不起来,而是启动速度非常缓慢,所以当应用长时间启动后才会对外提供服务。而这个速度慢到居然要花费 2 个小时。

导致的一个结果是测试完全不敢在测试环境发版验证了,每验证一个功能修复一个 bug 就得等上两个小时,这谁受得了😂。

而且经过多次观察,确实每次都是花费两小时左右应用才能启动起来。

尝试解决

最后测试顶不住了,只能让我这个“事故报告撰写专家”来看看。

当我得知这个问题的现象时其实完全没当一回事:

都不用想,这不就是主线程阻塞了嘛,先看看是否在初始化的时候数据库、Zookeeper 之类的连不上导致阻塞了-------来之多次事故处理的经验告诉我。

于是我把这事打回给测试让他先找运维排查下,不到万不得已不要影响我 Touch fish🐳。

第二天一早看到测试同学的微信头像跳动时我都已经准备接受又一句 “膜拜大佬👍” 的回复时,却收到 “网络一切正常,没人动过,再不解决就要罢工了🤬”。

好吧,忽悠不过去了。

首先这类问题的排查方向应该不会错,就是主线程阻塞了,至于是啥导致的阻塞就不能像之前那样瞎猜了。

我将应用重启后用 jstack pid 将线程快照打印到终端,直接拉到最后看看 main 线程到底在干啥。

前几次的快照都是很正常:

加载 Spring ---->连接 Zookeeper —> 连接 Redis,都是依次执行下来没有阻塞。

隔了一段后应用确实还没起来,我再次 jstack 后得到如下信息:

image.png

翻源码

我一直等了十几分钟再多次 jstack 得到的快照得到的信息都是一样的。

如图所示可见主线程是卡在了 dubbo 的某个方法 ServiceConfig.java 的 303 行中。

于是我找到此处的源码:

image.png

简单来说这里的逻辑就是要获取本机的 IP 将其注册到 Zookeeper 中用于其他服务调用。

image.png

再往下跟就如堆栈中一样是卡在了 Inet4AddressImpl.getLocalHostName 处。

但这是一个 native 方法,我们应用也根本干涉不了,最终的现象就是调用这个本地方法非常耗时。

于是这问题貌似也阻塞在这儿了,没有太多办法。

最终解决

既然这是一个 native 方法,那说明和应用本身没有啥关系(确实也是这样,这个问题是突然间出现的。)

那是否是服务器本身的问题呢,想到在 native 方法里是获取本机的 hostname,那是否和这个 hostname 有关系呢。

image.png

这是在我自己的阿里云服务器上测试,真正的测试环境不是这个名字。

拿到服务器 hostname 后再尝试 ping 这个 hostname,奇怪的现象发生了:

命令刚开始会卡住一段时间(大概几十秒),然后才会输出 hostname 对应的 ip 以及对应的延迟。

而当我直接 ping 这个 ip 时却能快速响应后面的输出。

最后我尝试在 /etc/hosts 配置文件中加入了对应的 host 配置:

xx.xx.xx.xx(ip) hostname
再次 ping hostname 的效果就和直接 ping ip 一样了。

于是我再次重启应用,一切都正常了。

总结

最后根据我调整的内容尝试分析下本次问题的原因:

Dubbo 在启动获取本地 ip 时,是通过服务器 hostname 从 dns 服务器返回当前的 ip 地址。

由于 dns 服务器或者是本地服务器与 dns 服务器之间存在网络问题,导致这个过程的时间被拉长(猜测)。

我在本地的 host 文件中配置后,就相当于本地有一个缓存,优先取本地配置的 ip ,避免了和 dns 服务器交互的过程,所以速度提升了。

虽然问题得到解决了,但还是有几个疑问:

第一个是为什么和 DNS 服务器的交互会这么慢,即便是慢也没有像应用那样需要 2 个小时才能返回,这里我也没搞得太清楚,有相关经验的朋友可以留言讨论。

第二就是 Dubbo 在这个依赖外部获取资源时健壮性是否可以做的更好,虽说我这问题估计也几人碰到。

对于这种长时间没有启动成功的问题是否可以加上提示,比如直接抛出异常退出程序,将问题可能的原因告诉开发者,方便排查问题。

请先登录,再评论

[45 一个InetAddress.getLocalHost导致SpringBoot启动延迟问题排查]
(https://blog.csdn.net/u011039332/article/details/102802468), 问题的原因和我的这个差不多, 不过我那个 从dns获取不到数据 5秒之后就超时了

1年前

为你推荐

字符串字面量长度是有限制的
前言 偶然在一次单元测试中写了一个非常长的字符串字面量。 正文 在一次单元测试中,我写了一个很长的字符串字面量,大概10万个字符左右,编译时,编译器给出了异常告警 `java: constant
多次字符串相加一定要用StringBuilder而不用-吗?
今天在写一个读取Java class File并进行分析的Demo时,偶然发现了下面这个场景(基于oracle jdk 1.8.0_144): ``` package test; public c
如何通过反射获得方法的真实参数名(以及扩展研究)
前段时间,在做一个小的工程时,遇到了需要通过反射获得方法真实参数名的场景,在这里我遇到了一些小小的问题,后来在部门老大的指导下,我解决了这个问题。通过解决这个问题,附带着我了解到了很多新的知识,我觉得
高吞吐、低延迟 Java 应用的 GC 优化实践
本篇原文作者是 LinkedIn 的 Swapnil Ghike,这篇文章讲述了 LinkedIn 的 Feed 产品的 GC 优化过程,虽然文章写作于 April 8, 2014,但其中的很多内容和
「每日五分钟,玩转 JVM」:久识你名,初居我心
聊聊 JVMJVM,一个熟悉又陌生的名词,从认识Java的第一天起,我们就会听到这个名字,在参加工作的前一两年,面试的时候还会经常被问到JDK,JRE,JVM这三者的区别。JVM可以说和我们是老朋友了
据说99.99%的人都会答错的类加载的问题
概述首先还是把问题抛给大家,这个问题也是我厂同学在做一个性能分析产品的时候碰到的一个问题。 同一个类加载器对象是否可以加载同一个类文件多次并且得到多个Class对象而都可以被java层使用吗请仔细注意
Java多线程——并发测试
编写并发程序时候,可以采取和串行程序相同的编程方式。唯一的难点在于,并发程序存在不确定性,这种不确定性会令程序出错的地方远比串行程序多,出现的方式也没有固定规则。那么如何在测试中,尽可能的暴露出这些问
Java多线程知识小抄集(一)
本文主要整理笔者遇到的Java多线程的相关知识点,适合速记,故命名为“小抄集”。本文没有特别重点,每一项针对一个多线程知识做一个概要性总结,也有一些会带一点例子,习题方便理解和记忆。 1.interr