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

前言

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

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

现象

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

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

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

而这个速度慢到居然要花费 2 个小时

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

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

尝试解决

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

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

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

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

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

好吧,忽悠不过去了。

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

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

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

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

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

翻源码

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

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

于是我找到此处的源码:

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

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

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

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

最终解决

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

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

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

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

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

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

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

xx.xx.xx.xx(ip) hostname

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

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

总结

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

  • Dubbo 在启动获取本地 ip 时,是通过服务器 hostnamedns 服务器返回当前的 ip 地址。
  • 由于 dns 服务器或者是本地服务器与 dns 服务器之间存在网络问题,导致这个过程的时间被拉长(猜测)。
  • 我在本地的 host 文件中配置后,就相当于本地有一个缓存,优先取本地配置的 ip ,避免了和 dns 服务器交互的过程,所以速度提升了。

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

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

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

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

你的点赞与分享是对我最大的支持

原文地址:https://www.cnblogs.com/crossoverJie/p/11135619.html

时间: 2024-08-29 13:41:33

What?一个 Dubbo 服务启动要两个小时!的相关文章

DUBBO服务启动过程

Dubbo的启动主要是发布服务的过程,起到核心作用的就是ServiceConfig(ServiceConfig就是我们在Dubbo的配置文件中配置的dubbo:service这些配置项对应的实体类).服务的启动初始位置也基本是在这里,下面我们来看看具体的实现内容. 讲基本内容前首先理清楚几个名词概念: Invoker:Invoker的概念我们在动态代理的时候就接触过,中文的意思大概是执行者,这里其实可以理解为具体方法的执行者.其核心内容大致如下: Class<T> getInterface()

dubbo服务启动正常,但是访问不到服务,在监测中心也找不服务的原因之一

配置文件没有加全. 之前加载spring配置文件是指定的文件,后面发现自己的配置文件不止一个,导致项目出错,虽然启动没有报错,在zookeeper也能找到对应的服务节点,但是在这个接口明显是访问不到的,所以在监控中心是不存在对应的服务接口. 原文地址:https://www.cnblogs.com/hirampeng/p/10236705.html

从头开始搭建一个dubbo+zookeeper平台 【转】

本篇主要是来分享从头开始搭建一个dubbo+zookeeper平台的过程,其中会简要介绍下dubbo服务的作用.   注册中心的选择   dubbo支持多种类型的注册中心: 这里我们选择zookeeper,其实类型的优点缺点可详细查看文档. 1:zookeeper的安装,还是采用docker这一招鲜的run命令来安装zookeeper docker run -dit --name zookeeper --hostname zookeeper-host -v /data:/data -p 2181

C# windows服务启动winform程序不显示UI问题解决

由于工作需要写一个解决winform程序自动更新下载重启的自动更新程序,之前用控制台全部实现,然而换成windows  service出现了两个问题,一个是路径问题(http://baidu.com),一个是服务启动其他winform程序不显示UI问题. 本篇解决UI显示问题. 以下为引用尤尼博文(原文地址:http://www.cnblogs.com/luxilin/p/3347212.html): 我开发的系统中有一接口程序(这里就称Task,是一个C#的Console Applicatio

我所经历的一次Dubbo服务雪崩,这是一个漫长的故事

在一个处理用户点击广告的高并发服务上找到了问题.看到服务打印的日记后我完全蒙了,全是jedis读超时,Read time out!一直用的是亚马逊的Redis服务,很难想象Jedis会读超时. 看了服务的负载均衡统计,发现并发增长了一倍,从每分钟3到4万的请求数,增长到8.6万,很显然,是并发翻倍导致的服务雪崩. 服务的部署: 处理广告点击的服务:2台2核8g的实例,每台部署一个节点(服务).下文统称服务A 规则匹配服务(Rpc远程调用服务提供者):2个节点,2台2核4g实例.下文统称服务B 还

JavaWeb 服务启动时,在后台老板启动加载一个线程

avaWeb 服务启动时,在后台启动加载一个线程JavaWeb 服务启动时,在后台启动加载一个线程. 目前,我所掌握的一共有两种方法,第一种是监听(Listener),第二种是配置随项目启动而启动的Servlet. 下面对这两种方法做一简单的介绍,(Mark一下,防止以后急用又忘记了): 监听(Listener) 首先,我们创建一个监听的类,继承ServletContextListener,如下: 源码复制打印    package com.wxp.thread;    import javax

Dubbo[一个分布式服务框架

http://alibaba.github.io/dubbo-doc-static/User+Guide-zh.htm#UserGuide-zh-API%E9%85%8D%E7%BD%AE http://alibaba.github.io/dubbo-doc-static/Home-zh.htm Dubbo是什么? Dubbo[]是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案. 其核心部分包含: 远程通讯: 提供对多种基于长连接的NIO框架抽象封装

简述uwsgi使用一个服务启动多个文件的用法

[场景篇] 为了节省端口的占用,将N个flask应用服务——每个对应一个文件(web.py.django也一样)合并为一个端口服务来启用 [寻思篇] 通常的做法:每个文件配置一个xml 或者 ini文件,然后依次启动uwsgi(uwsgi -x {xml文件名}),形如: <uwsgi> <wsgi-file>/home/yxgly/code/doraemon/DsBag/GET_DATA/Get_Data_Api.py</wsgi-file> <callable

源码分析Dubbo服务消费端启动流程

通过前面文章详解,我们知道Dubbo服务消费者标签dubbo:reference最终会在Spring容器中创建一个对应的ReferenceBean实例,而ReferenceBean实现了Spring生命周期接口:InitializingBean,接下来应该看一下其afterPropertiesSet方法的实现. 1.源码分析ReferenceBean#afterPropertiesSet ReferenceBean#afterPropertiesSet if (getConsumer() ==