天啦噜!生产机器链接数飙升到上万,背后发生了什么?

我的博客地址 studyidea.cn,点击查看更多原创文章html

0x00. 翻车现场

那是个月黑风高的夜晚,小黑哥成功将新版本发布到了生产,当心翼翼检查了应用日志,后续测试小姐姐验收成功。java

恩,小黑哥我仍是一如既往的稳~apache

接着小黑哥就跑到楼下食堂吃个夜宵,谁知正吃到一半,线上运维同窗发来几条告警信息,服务器链接数过多警告,链接数已经飙升到上万。编程

天啦撸,赶忙放下正在啃的鸡腿,火速跑到工位上查看问题。数组

0x01. 历尽艰辛,深刻排查

打开电脑,首先确认生产交易一切还正常。查看这段时间日志,发现并无什么异常状况,日志都是正常输出。没办法只好再次走查这次改动的代码,发现全是业务代码,并无任何与网络链接有关的代码改动。服务器

问题真的请奇怪,一时半会想不到解决方案,只好先实施重启大法。重启事后,链接数降低了,到达了正常阈值。可是不一会链接数持续升高,不一会仍是升到上万。网络

这下重启解决不了办法,只好从应用出发,找找到底什么问题。架构

这个应用是一个路由服务,会根据上游系统指定路由编码,将交易分发到下游子系统。架构图以下:并发

以前在这篇文章路由系统演化史讲过,路由系统使用 Dubbo API ,代码以下:框架

因为咱们还有另一套系统,也部署这个应用,可是该系统生产机器链接数却不多。交叉比对了两套系统应用的系统配置值,只有 connections 设置不同,当前有问题的系统设置为 1000,另一个系统为 10

大体找到缘由,也将 connections 设置为 10,重启应用,生产机器链接数恢复正常。

0x02. 抽丝剥茧,还原通过

首先咱们来看下 connections 这个配置的做用,能够直接查看官方文档dubbo.apache.org/zh-cn/docs/…

下面配置来源于:dubbo:reference

总共能够在三个地方配置 connections 参数,分别为:dubbo:referencedubbo:consumerdubbo:provider

注意:图中标示地方实际上与源码存在出入。截止 Dubbo 2.7.3 版本,图中 ① 处,dubbo:consumer 文档上显示为 100,实际源码默认配置为 0,这点须要注意。另外 ② 处文字描述存在问题,目前 connections 参数主要对 dubbo 协议有用,http 短链接协议还未使用该配置

其中 reference.connections 为服务级别的配置,若未配置将会使用 consumer.connections 配置值。另外这个参数若在 provider.connections 配置,其对服务提供者无效,参数将经过注册中心传递给消费者成为其默认配置。三者实际做用顺序以下:

Debug 源码,connections 最终会在 DubboProtocol#getClients 被使用,方法源码以下:

Dubbo 协议默认将会使用 **Netty **与服务提供者创建长链接

首先将会获取 connections 配置,规则如上图,若其大于 0,创建 connections 数量的长链接。

若是一个提供者对外暴露 10 个接口,且其有两个节点。消费者端引入提供者全部服务,配置 connections=1000。当消费者启动以后,将会马上建立 1000x2x10=20000 链接。这就是生产机器链接数飙升的根本缘由

路由服务使用 Dubbo API 编程,服务启动成功以后,只有上游系统调用路由服务时, Dubbo 才会与与下游服务提供者创建链接,因此现象看起来服务链接数是慢慢激增。

若是未设置 connections 参数,Dubbo 将会建立共享链接(shareconnections)。消费者调用的服务若为同一个服务提供者(IP+PORT 区分),这些服务接口将会共享这些链接。

shareconnections 能够在 dubbo:consumer 配置中配置,也能够在启动 JVM 参数加入以下配置:

-Dshareconnections=10
复制代码

若是消费者须要调用同个服务提供者应用的 10 个服务接口,服务提供者提供两个节点,shareconnections=1000,消费者服务启动以后,仅会建立 1000*2=2000 链接。

这么对比,shareconnectionsconnections 创建连不是一个量级。

2.1 使用链接

消费者调用服务时,将会随机从链接数组中取一个链接使用,代码位于 DubboInvoker#doInvoke

2.2 如何正确配置链接数

首先咱们来看下单一长链接性能,文档地址:dubbo.apache.org/zh-cn/docs/…

对于只有少数消费者场景,咱们可使用默认配置,即不配置 connections 参数 。若调用同一个提供者服务过多,能够考虑适当多配增长 shareconnections。最后若某一服务接口调用量特别大,能够考虑为这个服务单独配置 connections

0x03. 触类旁通,聊聊其余配置

Dubbo 还有不少配置项,下面着重介绍一些配置参数。

3.1 dubbo.provider.executes

该参数用来控制每一个方法最大并行数。若是该值设置为 10 ,每一个服务方法若已有 10 个请求正在处理,第 11 个服务请求将会抛出异常,直到以前服务调用完成,正在请求数量小于 10 未知。

一旦设置 executes>0,Dubbo 将会经过 SPI 机制启用 ExecuteLimitFilter,源码仍是比较简单。

3.2 dubbo.reference.actives

这个参数将会控制消费者每一个服务每一个方法最大并发数。能够经过 dubbo:method.actives 单独为服务方法设置。若是该值为 10,一旦某个服务某个方法并发数超过 10,第 11 个服务将会等待,若在超时时间内其余请求执行结束,计数值减值小于阈值,第 11 个请求将会被执行,否者将会抛错。

dubbo.provider 上也能够配置这个值,其将会与 connections 同样,将会传递给消费者。

原理等同上面方法,将会启用 ActiveLimitFilter,源码以下 :

这里须要注意 actives 引发超时与服务端超时区别。

3.3 dubbo.protocol.accepts

服务提供者最大链接数,若是设置 accepts=10,一旦服务提供者链接数大于 10,其他新增链接将会被拒绝。

方法源码以下:

服务提供者断开链接,消费端将会打印链接断开日志。另外消费者会定时检查长链接可用性,若不可用,将会从新发起链接。因此在消费者端就会看到链接断开,重连,而后又被服务提供者断开的现象。

0x04. 总结

本文经过一次生产链接数过多的现象,详细剖析定位问题的缘由。做为一个合格的开发,对于开源框架,咱们不只要会熟练使用,也要了解其底层实现,相关参数设置。一旦参数设置不合理就可能引起生产事故。

另外对于生产系统,监控系统很是重要。好比上面的问题,若是没有监控发现,小黑哥可能一时半会都不知道有这个问题存在,毕竟平时也不会太关注链接数这个指标。


好快,已经在家呆了两周了。哎,出不去,又进不来。之后回想,2020 真是一个使人难忘的一年。。。好了,10 号要正视开工了。

欢迎关注个人公众号:程序通事,得到平常干货推送。若是您对个人专题内容感兴趣,也能够关注个人博客:studyidea.cn

相关文章
相关标签/搜索