前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Netty高性能之道

Netty高性能之道

作者头像
Liusy
发布2020-09-01 14:49:35
6600
发布2020-09-01 14:49:35
举报
文章被收录于专栏:Liusy01Liusy01

【导读】传统RPC性能差的原因有三个,一是网络传输方式是同步阻塞的,二是Java原生序列化性能差,无法跨语言使用,序列化之后体积大等,三是线程模型会占用大量系统资源。所以今天来看以下Netty的高性能是如何建立的?

IO通信的三原则:

1、传输:用什么样的通道发送数据,I/O模型在很大程度上决定了通信的性能。

2、协议:协议的选择不同,性能也不同。相比于公有协议,内部私有协议的性能通常往往更佳。

3、线程:数据报如何读取,编解码在哪个线程执行,Reactor线程模型的不同,性能也不同。

Netty高性能之道:

一、异步非阻塞通信

I/O多路复用技术通过把多个I/O的阻塞复用到同一个select的阻塞上,从而使得系统在单线程的情况下可以同时处理多个客户端请求,与传统的BIO相比,多路复用的最大优势就是系统开销小,无需创建额外的线程。

NIO有阻塞和非阻塞模式,一般来说,低负载,低并发可以选择阻塞模式降低复杂度,高负载、高并发需选择非阻塞模式来撑起系统的性能。

二、高效的Reactor线程模型

常用的Reactor线程模式有三种,分别是:

1、Reactor单线程模型

2、Reactor多线程模型

3、主从Reactor多线程模型

(1)Reactor单线程模型

代码语言:javascript
复制
NioEventLoopGroup group = new NioEventLoopGroup(1);ServerBootstrap server = new ServerBootstrap();server.group(group);

所有的IO操作都在同一个NIO线程上完成,NIO线程职责是接收或发起TCP连接,读取或发送消息。

由于Reactor模式采用的是异步非阻塞IO,所有的IO操作都不会导致阻塞,理论上一个线程就可以独立处理所有IO相关的操作。

此模式不适用于高并发、高负载的场景,原因如下:

1、一个NIO线程同时处理成百上千的链路,性能上无法支撑

2、当负载过重时,处理速度将会变慢,会导致大量客户端连接超时,超时之后往往会进行重发,最终导致大量消息积压和处理超时。

3、可靠性问题,如果NIO线程进入了死循环,会导致不可用。

为了解决上述问题,就有了Reactor多线程模型

(2)Reactor多线程模型

代码语言:javascript
复制
NioEventLoopGroup acceptor = new NioEventLoopGroup(1);NioEventLoopGroup worker = new NioEventLoopGroup();ServerBootstrap server = new ServerBootstrap();server.group(acceptor,worker);

其于单线程模型最大的区别就是有一个Acceptor线程单独处理连接请求,有一组NIO线程负责I/O读写。

在绝大多数场景下,多线程模型可以满足性能需求,但是在高并发的情况下一个NIO线程处理连接请求可能会导致性能问题,为了解决此问题,产生了主从Reactor线程模型。

(3)主从Reactor线程模型

代码语言:javascript
复制
NioEventLoopGroup boss = new NioEventLoopGroup();NioEventLoopGroup worker = new NioEventLoopGroup();ServerBootstrap server = new ServerBootstrap();server.group(boss,worker);

服务端用于接收连接请求的不再是一个单独的NIO线程,而是一个独立的线程池。可解决一个服务端无法有效处理所有连接请求的问题。推荐使用该模型。

三、无锁的串行化设计

并行多线程处理可以提升系统的并发能力,但是,如果处理不当,会有锁竞争的问题。为了解决此问题,Netty通过串行化设计,也就是消息的处理在同一个线程内完成,不进行上下文切换,避免了多线程竞争和同步锁。也就是ChannelPipeline的设计。

Netty的NioEventLoop在读取到消息之后,直接调用ChannelPipeline的fireChannelRead方法,就会一直按照责任链模式执行下去,期间不进行线程切换。

四、高效的并发编程

主要体现在如下几点:

1、Volatile的大量、正确使用

2、CAS和原子类的广泛使用

3、线程安全容器的使用

4、通过读写锁提升并发性能。

五、高性能的序列化框架

影响序列化性能的关键因素如下:

1、序列化之后码流的大小(网络带宽的占用)

2、序列化与反序列化的性能(CPU资源的占用)

3、是否支持跨语言

Netty提供了对Google ProtoBuf、Thrift等优秀序列化框架的支持,之后篇章讲解用法。

六、零拷贝

何为零拷贝?数据都存储在JVM内存里面,如果需要进行数据传输,需要将JVM里面的数据拷贝一份到内核空间中,而NIO提供了在堆外内存存放数据的功能,可以直接进行传输,不需要进行拷贝。

Netty的零拷贝主要体现在三个方面:

(1)Netty的接受和发送都使用DirectBuffers,使用堆内直接内存进行socket读写,不需要进行字节缓冲区的二次拷贝。

(2)CompositeByteBuf,对外将多个ByteBuf封装成一个ByteBuf,对外提供统一的ByteBuf接口。是一个组合Buffer对象,避免了通过内存拷贝的方式将几个小Buffer合并成一个大Buffer。

(3)文件传输,Netty的文件传输类DefaultFileRegion通过transferTo方法将文件发送到目标Channel中。避免了传统通过循环write方式导致的内存拷贝问题。

七、内存池

JVM提供了对内存的分配和回收,但是堆内内存的分配和回收都是比较耗时的操作,为了重用缓冲区,Netty提供了基于内存池的缓冲区重用机制。

通过内存池分配器创建直接内存缓冲区:

代码语言:javascript
复制
PooledByteBufAllocator.DEFAULT.directBuffer(1024);

八、灵活的TCP参数配置

合理的TCP参数在特定场景对于性能的提升可以有显著的效果,例如:

(1)SO_RCVBUF和SO_SNDBUF:通常建议设置为128kb或者256kb

(2)SO_TCPNODELAY:NAGLE算法通过将缓冲区内的小封包自动相连,阻止大量小封包的发送阻塞网络,从而提升网络应用效率,但对于时效强的场景应关闭此算法。

上述就是Netty高性能的基础,来自《Netty权威指南 第2版》一书。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-07-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Liusy01 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
文件存储
文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档