作者:十眠
为什么有了无损下线,还需要无损上线?无损上线可以解决哪些问题?
本篇文章将一一回答这些问题。
无损上线功能不得不说是一个客户打磨出来的功能
我们将从一次发布问题的排查与解决的过程说起。
背景
阿里云内部某应用中心服务在发布过程中出现了大量的 5xx 超时异常。初步怀疑是无损下线问题,于是很快便接入了 MSE 提供的无损下线功能。但是接入无损下线功能后继续发布,应用的发布过程依然存在大量的超时报错。根据业务方同学的反馈,大概应用在启动后 5 秒左右,会有大量超时请求。
无损下线功能未生效?
于是拉了相关的同学开始排查。应用的调用情况如下:gateway - > A -> C 。
发布的应用为 C 应用,发布过程中出现大量超时报错。我们通过相关日志与应用的启动情况,整理如下线索:
【服务端视角】:找了一台 C 应用的机器 xxx.xxx.xxx.60 观察
第一阶段:xxx.xxx.xxx.60 (C 应用)下线阶段
- 20:27:51 开始重启,执行重启脚本
-
- 同时观察到执行了 sendReadOnlyEvent 动作,表明服务端发送只读事件,客户端不会再请求该服务端
- 在 sendReadOnlyEvent 后,开始陆续执行注销服务动作
- 20:27:54 注销所有 provider seivce 完成
- 20:28:15 应用收到 kill -15 信号
第二阶段:xxx.xxx.xxx.60 (C 应用)上线阶段
- 20:28:34 服务端重新启动
- 20:29:19 在 Dubbo 注册中心控制台观察到 xxx.xxx.xxx.60 注册完毕
- 20:29:19,257 日志中看到 start NettyServer
【客户端视角】:找了一台 A 应用的机器 XXX.XXX.XXX.142 观察
- 20:27:51 received readOnly event,收到服务端发送的只读事件,此时该客户端不会请求至 XXX.XXX.XXX.60 机器
- 20:27:56 close [xxx.xxx.xxx.142:0 -> /XXX.XXX.XXX.60:20880] ,关闭channel连接
业务日志报错信息
同时搜 C 应用的机器 XXX.XXX.XXX.60 的报错相关的日志,共 237 条日志
其中最早的 time: 2020-07-30 20:29:26,524
其中最晚的 time: 2020-07-30 20:29:59,788
结论
观察这些迹象可以初步得出结论:
- 无损下线过程均符合预期,并且下线过程中并没有出现任何报错
- 报错期间处于服务端应用成功启动后且注册成功后,与业务方观察的现象一致
这时候怀疑是上线期间的问题,同时排查服务端相关日志,发在报错期间,服务端线程被打满:
问题定位为上线过程中的问题,与无损下线无关。
无损上线实践
我们帮助用户解决问题的思路:帮助用户发现问题的本质、找到问题的通用性、解决问题、将解决通用问题的能力产品化。
发现用户 Dubbo 版本比较低,缺少自动打线程堆栈的能力:
- 通过 MSE 增加 Dubbo 线程池满自动 JStack 能力
这是每次发布必现的问题,通过观察线程池满时的 JStack 日志,有助于我们定位问题。
阻塞在异步连接等资源准备上
初步观察 JStack 日志,发现不少线程阻塞在 taril/druid 等异步连接资源准备上:
同时我们云上也有有客户遇到过,应用启动后一段时间内 Dubbo 线程池满的问题,后经过排查由于 Redis 连接池中的连接未提前建立,流量进来后大量线程阻塞在 Redis 连接建立上。
连接池通过异步线程保持连接数量