开发者社区> 超努力的写代码> 正文

从时延毛刺问题定位到 Netty 的性能统计设计(上)

简介: 从时延毛刺问题定位到 Netty 的性能统计设计(上)
+关注继续查看

一、背景:


通常情况下,用户以黑盒的方式使用Netty,通过Netty完成协议消息的读取和发送,以及编解码操作,不需要关注Netty的底层实现细节。


在高并发场景下,往往需要统计系统的关键性能KPI数据,结合日志、告警等对故障进行定位分析,如果对Netty的底层实现细节不了解,获取哪些关键性能数据,以及数据正确的获取方式都将成为难点。错误或者不准确的数据可能误导定位思路和方向,导致问题迟迟不能得到正确解决。

 


二、时延毛刺故障排查的艰辛历程:

 

问题现象:某电商生产环境在业务高峰期,偶现服务调用时延突刺问题,时延突然增大的服务没有固定规律,问题发生的比例虽然很低,但是对客户的体验影响很大,需要尽快定位出问题原因并解决。

 

  • 时延毛刺问题初步分析:

服务调用时延增大,但并不是异常,因此运行日志并不会打印ERROR日志,单靠传统的日志无法进行有效问题定位。利用分布式消息跟踪系统,进行分布式环境的故障定界。


通过对服务调用时延进行排序和过滤,找出时延增大的服务调用链详细信息,发现业务服务端处理很快,但是消费者统计数据却显示服务端处理非常慢,调用链两端看到的数据不一致,怎么回事?


对调用链的详情进行分析发现,服务端打印的时延是业务服务接口调用的耗时,并没有包含:


(1)服务端读取请求消息、对消息做解码,以及内部消息投递、在线程池消息队列排队等待的时间。

(2)响应消息编码时间、消息队列发送排队时间以及消息写入到Socket发送缓冲区的时间。


服务调用链的工作原理如下:


微信图片_20220121194245.jpg


图1 服务调用链工作原理


将调用链中的消息调用过程详细展开,以服务端读取请求和发送响应消息为例进行说明,如下图所示:


微信图片_20220121194301.jpg


图2 服务端调用链详情


对于服务端的处理耗时,除了业务服务自身调用的耗时之外,还应该包含服务框架的处理时间,具体如下:


(1)请求消息的解码(反序列化)时间。

(2)请求消息在业务线程池中排队等待执行时间。

(3)响应消息编码(序列化)时间。

(4)响应消息ByteBuf在发送队列的排队时间。


由于服务端调用链只采集了业务服务接口的调用耗时,没有包含服务框架本身的调度和处理时间,导致无法对故障进行定界:服务端没有统计服务框架的处理时间,因此不排除问题出在消息发送队列或者业务线程池队列积压而导致时延变大。

 

  • 服务调用链改进:


对服务调用链埋点进行优化,具体措施如下:


(1)包含客户端和服务端消息编码和解码的耗时。

(2)包含请求和应答消息在队列中的排队时间。

(3)包含应答消息在通信线程发送队列(数组)中的排队时间。


同时,为了方便问题定位,增加打印输出Netty的性能统计日志,主要包括:

(1)当前系统的总链路数、以及每个链路的状态。

(2)每条链路接收的总字节数、周期T接收的字节数、消息接收吞吐量。

(3)每条链路发送的总字节数、周期T发送的字节数、消息发送吞吐量。


对服务调用链优化之后,上线运行一段时间,通过分析比对Netty性能统计日志、调用链日志,发现双方的数据并不一致,Netty性能统计日志统计到的数据与前端门户看到的也不一致,因此怀疑是新增的性能统计功能存在BUG,需要继续对问题进行定位。

 

  • 都是同步思维惹的祸:

 

传统的同步服务调用,发起服务调用之后,业务线程阻塞,等待响应,接收到响应之后,业务线程继续执行,对发送的消息进行累加,获取性能KPI数据。

使用Netty之后,所有的网络I/O操作都是异步执行的,即调用Channelwrite方法,并不代表消息真正发送到TCP缓冲区中,如果在调用write方法之后就对发送的字节数做计数,统计结果就不准确。


对消息发送功能进行code review,发现代码调用完writeAndFlush方法之后直接对发送的请求消息字节数进行计数,代码示例如下:


 public void channelRead(ChannelHandlerContextctx, Object msg) {

        int sendBytes =((ByteBuf)msg).readableBytes();

        ctx.writeAndFlush(msg);

        totalSendBytes.getAndAdd(sendBytes);

}

调用writeAndFlush并不代表消息已经发送到网络上,它仅仅是个异步的消息发送操作而已,调用writeAndFlush之后,Netty会执行一系列操作,最终将消息发送到网络上,相关流程如下所示:


微信图片_20220121194320.jpg


图3 writeAndFlush处理流程图


通过对writeAndFlush方法深入分析,我们发现性能统计代码忽略了如下几个耗时:

(1)业务ChannelHandler的执行时间。

(2)被异步封装的WriteTask/WriteAndFlushTaskNioEventLoop任务队列中的排队时间。

(3)ByteBufChannelOutboundBuffer队列中排队时间。

(4)JDK NIO类库将ByteBuffer写入到网络的时间。


由于性能统计遗漏了上述4个关键步骤的执行时间,因此统计出来的发送速率比实际值会更高一些,这将干扰我们的问题定位思路。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,大概有三种登录方式:
9155 0
SAP UI5应用如果遇到数据绑定问题时,应该如何自己定位问题?
SAP UI5应用如果遇到数据绑定问题时,应该如何自己定位问题?
17 0
VC运行库版本不同导致链接.LIB静态库时发生重复定义问题的一个案例分析和总结
Background MSDN中对于在不同的配置下Link的LIB作了说明: C Runtime Library: 开关 对应的库 版本 /MD MSVCRT.
962 0
性能测试如何定位瓶颈?偶发超时?看高手如何快速排查问题
线上系统为何经常出错?数据库为何屡遭黑手?业务调用为何频频失败?连环异常堆栈案,究竟是哪次调用所为?数百台服务器意外雪崩背后又隐藏着什么?是软件的扭曲还是硬件的沦丧?走进科学带你了解 Arthas,一款开源一年多 GitHub Star 2 万,99% 的阿里研发小哥都在用的 Java 终极诊断利器.
963 0
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
19806 0
18 个命令&工具帮你定位 Linux 性能问题
1.TopTop命令是一个性能监控程序,它按一定的顺序显示所有正在运行而且处于活动状态的实时进程,而且会定期更新显示结果。这条命令显示了CPU的使用率、内存使用率、交换内存使用大小、高速缓存使用大小、缓冲区使用大小,进程PID、所使用命令以及其他。
1188 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
18057 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
24831 0
1946
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
OceanBase 入门到实战教程
立即下载
阿里云图数据库GDB,加速开启“图智”未来.ppt
立即下载
实时数仓Hologres技术实战一本通2.0版(下)
立即下载