新一代网络IO框架性能吊打传统框架
最近看了一下最新第21期(2022年7月)的Techempower的网络框架性能排名,实在有些惊讶。很多老牌的框架都名落孙山,后起之秀纷纷排到了前面。
首先第一名居然是用V语言写的pico.v框架。要知道V语言是2019年才正式发布的新型编程语言。另外微软公司的框架ASPCore居然也取得了第三名的成绩。采用Java语言的国产AIO框架smart-socket排在了第四位。Golang的高性能网络IO框架gnet排在第9位。事实上,前十多位框架的差距都非常小。而很多非常著名的传统以高性能著称的网络框架或工具,比如Netty,Nginx等的排名都非常靠后。Netty排名64,Nginx排名109,分别只能达到排名第一的框架性能的57.2%和28.8%。总体看来目前的网络IO框架卷得非常严重,前浪有被拍死的危险。
Netty的技术负债和解决办法
不过Netty正在加快开发其5.0版本,不知道是不是因为其他的IO框架的严重竞争。实施上Netty的首席开发Norman Maurer在2019年的一次演讲中就说过,Netty需要开发新的5.X版本。有大量的技术债务(tech debt)需要处理。他指出主要有以下几点:
- 一些API是很多年以前开发的,设计的不够用户友好
- 需要添加并使用Java8的一些新特性
- 如果不对API进行大调整,很难改善性能
- 删除过时的代码
减少Handler中方法的数量
目前Netty采用的是ChannelPipline的模式,ChannelPipline中会加入多个顺序处理的ChannelHandler。通常一个ChannelPipline包含有4-12个ChannelHandler来处理不同的事件。我们知道对于JVM有一个方法内联深度的定义-XX:MaxInlineLevel=n,这个深度的默认值是9。较多的ChannelHandler不但增加了程序stack的深度,而且往往会降低使用方法内联的可能性。这都会对其运行效率和性能有影响。
我们知道在channelHandler的接口中有很多抽象的方法,这些方法只有在channelpipline的某个事件被触发的时候,并且需要handler进行处理才需要调用和执行。因此在Netty5.0中会加入@Skip这个标记,用于忽略某个接口。只有当这个接口被重写时才会被调用。这样就减少了handler中需要被调用的方法数,增加了内联的可能性,提高了性能。下面是一个简单的Skip标签的实现。
根据相关的测试,一个拥有5个handler的pipeline,在采用了@Skip标签后的吞吐量可以提高3倍,如下图所示:
我们是否应该转到新的框架
虽然很多网络IO框架的性能的确已经非常强大,但是并没有达到碾压传统框架的程度。最多也就是在相同硬件配置下,达到两倍到三倍的性能优势。那么为了这样的性能优势而舍弃成熟框架的投资回报可能并不一定能弥补修改的成本。而且目前在Java技术栈的很多著名开源系统的通信框架都是采用的Netty,而反向代理服务器和负载均衡器往往都是用的Nginx。我们看到包括Redis,Cassandra和Elasticsearch等著名的开源程序的底层通讯都是建立在Netty的基础上的。在可以预见的未来,传统的框架还是会占据主导地位。
不过新框架的发展势头非常强劲,也许一些新的开源项目或者企业项目会开始尝试使用。最终那个技术路线会成为5到10年后的主流,还是很难预测的。还是让我们保持开放的心态,对新技术保持热情。同时也关注成熟技术的发展。