vlambda博客
学习文章列表

想统计Netty的一轮事件循环的耗时,该怎么做?


本篇文章大概1300字,阅读时间大约5分钟


前面几篇文章,将Netty的线程图像进行了抽象,并且从细节处着手,分析了它们的源码实现,本篇文章做个收尾。不妨带着两个问题阅读:

1、想统计Netty的一轮事件循环的耗时,应该怎么做?

2、@UnstableApi注解在Netty里的作用?

想统计Netty的一轮事件循环的耗时,该怎么做?

前面几篇文章:





NioEventLoop的整个处理异步任务的过程和设计思想进行了拆解,其实还漏了一个方法,下面重点分析一下。


回忆Netty的线程封装,重复印象,如下是NioEventLoop的继承图:

想统计Netty的一轮事件循环的耗时,该怎么做?

NioEventLoop的父类SingleThreadEventLoop里其实还有一个队列叫tailTasks,如下黄线处,它也被初始化为了一个MPSCQ:

想统计Netty的一轮事件循环的耗时,该怎么做?


tailTasks,单看它的名字就能猜出来,这是一个负责收尾任务的MPSCQ。下面看它在哪里被使用了,在SingleThreadEventLoop发现如下代码:

想统计Netty的一轮事件循环的耗时,该怎么做?


即方法executeAfterEventLoopIteration(task)。看方法名也能知道,这个方法的执行是在EventLoop的run循环一次之后被调用。这个方法本身没什么特别的,就是收尾的MPSCQ的任务聚合——用户将自定义的异步任务封装为task,调用它就可以将task添加到tailTasks,那么该队列到底何时会被执行呢?回忆NioEventLoop的runAllTasks方法:

想统计Netty的一轮事件循环的耗时,该怎么做?

两个红框处都调用了同一个方法:afterRunningAllTasks(),这个方法最终会执行tailTasks,去执行里面的收尾任务,执行时机有两个:


1、EventLoop事件循环的一轮runAllTasks结束,即for循环退出需要做一次善后处理


2、如直接从MPSCQ取出的task为null,那么也表明本轮runAllTasks结束,也要调用它做善后。


以上,其实调用时机可以归纳为一个,即EventLoop事件循环的一轮runAllTasks结束后,执行收尾任务。


简单看下这个afterRunningAllTasks()的内部实现:

想统计Netty的一轮事件循环的耗时,该怎么做?

内部调用到类io.netty.util.concurrent.SingleThreadEventExecutor的runAllTasksFrom方法:

想统计Netty的一轮事件循环的耗时,该怎么做?

以上,可以清晰的看到,runAllTasksFrom的工作就是取出tailTasks里的任务,并将其全部执行完,类似runAllTasks,它仍然是一个反复取出队列里的任务执行的逻辑。


综上,NioEventLoop可通过executeAfterEventLoopIteration(task)方法,向tailTasks队列添加收尾的异步任务,比如一些需要在一轮事件循环后执行的任务,就像标题说的,用户想统计执行一次事件循环花了多长时间就可以调用此方法将自己实现的统计业务封装为task在提交给NioEventLoop线程,当NIO线程执行完一次事件循环,就会自动执行这个task。


举个例子,如下是我之前写的一个RPC框架的服务器代码片段:

想统计Netty的一轮事件循环的耗时,该怎么做?

我在一个自定义的入站处理器里,通过channelRead0的参数——ctx,也就是前面总结流水线图像时,说到的双向链表的节点对象,拿到当前Channel绑定的eventloop,然后将其向上转换为SingleThreadEventLoop,在去调用它的executeAfterEventLoopIteration方法,异步的添加一个收尾的任务,这个收尾任务会在当前Channel绑定的NIO线程,一轮事件循环后才被执行,任务内容是简单记录被执行的次数,后续即可通过观察日志来确定一轮事件循环的时间间隔。PS. 其实使用普通int即可,因为全程是NIO线程执行。


启动服务器和客户端后,期间两者会有一个欢迎消息的来回,接着是心跳包,如下打印:

想统计Netty的一轮事件循环的耗时,该怎么做?

日志细节就不放了,这样就能通过日志的打印间隔,估算一些业务处理的耗时,这个耗时比单纯在channelRead这种方法里写要更准确一些,因为它能统计上NIO线程轮询I/O事件,处理I/O事件,以及其它业务逻辑的时间。可以辅助全面评估整个服务器架构设计的性能盲点。


不过需要注意的是,Netty将executeAfterEventLoopIteration方法标记了@UnstableApi:

想统计Netty的一轮事件循环的耗时,该怎么做?


@UnstableApi是Netty自己定义的注解,意思是表明某个API不是稳定的,可能在后续版本里删除,如果线上业务有依赖这样的方法,那么在升级Netty版本时,需要注意这一点。


END


点亮在看,你最好看

~

阅读原文,获得更多精彩内容