从时延毛刺问题定位到 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个关键步骤的执行时间,因此统计出来的发送速率比实际值会更高一些,这将干扰我们的问题定位思路。

相关实践学习
通过日志服务实现云资源OSS的安全审计
本实验介绍如何通过日志服务实现云资源OSS的安全审计。
相关文章
|
Rust Dubbo 网络协议
通过 HTTP/2 协议案例学习 Java & Netty 性能调优:工具、技巧与方法论
通过 HTTP/2 协议案例学习 Java & Netty 性能调优:工具、技巧与方法论
12914 78
|
消息中间件 机器学习/深度学习 大数据
阿里技术官发布的Netty速成笔记,堪称“性能猛兽”,真的很强悍
现如今互联网大厂,一面最喜欢考察的就是基础知识,比如本课程要讲解的计算机基础,因为写代码不可避免要跟机器、网络、CPU、磁盘、内存,成天打交道。
222 0
|
消息中间件 编解码 网络协议
Netty 的三层架构设计
《读尽源码》
453 0
|
存储 编解码 移动开发
04、Netty学习笔记—(黏包半包及协议设计解析)(二)
04、Netty学习笔记—(黏包半包及协议设计解析)(二)
04、Netty学习笔记—(黏包半包及协议设计解析)(二)
|
移动开发 网络协议 算法
04、Netty学习笔记—(黏包半包及协议设计解析)(一)
04、Netty学习笔记—(黏包半包及协议设计解析)(一)
04、Netty学习笔记—(黏包半包及协议设计解析)(一)
|
缓存 监控 Java
为什么说Netty是性能之王,因为它用了 Reactor 模型啊
程,更多是与平台及编程语言相关。 例如 C 语言使用线程和进程都可以(例如 N
为什么说Netty是性能之王,因为它用了 Reactor 模型啊
|
消息中间件 数据采集 运维
从时延毛刺问题定位到 Netty 的性能统计设计(下)
从时延毛刺问题定位到 Netty 的性能统计设计(下)
539 0
从时延毛刺问题定位到 Netty 的性能统计设计(下)
netty系列之:性能为王!创建多路复用http2服务器
netty系列之:性能为王!创建多路复用http2服务器
|
网络协议 Java 物联网
基于Netty的百万级推送服务设计要点
1. 背景 1.1. 话题来源 最近很多从事移动互联网和物联网开发的同学给我发邮件或者微博私信我,咨询推送服务相关的问题。
1822 0
|
安全 算法 Java
Netty SSL性能调优
TLS算法组合 在TLS中,5类算法组合在一起,称为一个CipherSuite: 认证算法 加密算法 消息认证码算法 简称MAC 密钥交换算法 密钥衍生算法 比较常见的算法组合是 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA 和  TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 都是ECDHE 做密钥交换,使用RSA做认证,SHA256做PRF算法。
3072 0