【读后感】Netty 系列之 Netty 高性能之道 - 相比 Mina 怎样 ?

2021-07-04 00:06

阅读:435

【读后感】Netty 系列之 Netty 高性能之道 - 相比 Mina 怎样 ?

太阳火神的漂亮人生 (http://blog.csdn.net/opengl_es)

本文遵循“署名-非商业用途-保持一致”创作公用协议

转载请保留此句:太阳火神的漂亮人生 -  本博客专注于 敏捷开发及移动和物联设备研究:iOS、Android、Html5、Arduino、pcDuino否则,出自本博客的文章拒绝转载或再转载,谢谢合作。


【读后感】
不知道这是什么节奏,或许人家早就春意盎然了。仅仅是我方才感觉到而已!

研究 Mina 的过程中,偶然发现了 Netty,有人说 Mina 好久不更新了,而 Netty 一直很活跃。
这仅仅能说。
Netty 在快速的完好其中,
至于 Mina。是没有后劲儿了呢,还是已经很完好了,不须要再继续更新,这个到是不得而知,
至少眼下看。还不错,
相比 Netty 的大数据、大并发、高效率。。。

还有什么。请移步下文,自品其详吧!


Netty系列之Netty高性能之道

1. 背景

1.1. 惊人的性能数据

近期一个圈内朋友通过私信告诉我,通过使用Netty4 + Thrift压缩二进制编解码技术。他们实现了10W TPS(1K的复杂POJO对象)的跨节点远程服务调用。相比于传统基于Java序列化+BIO(同步堵塞IO)的通信框架,性能提升了8倍多。

其实。我对这个数据并不感到吃惊,依据我5年多的NIO编程经验,通过选择合适的NIO框架,加上高性能的压缩二进制编解码技术。精心的设计Reactor线程模型,达到上述性能指标是全然有可能的。

以下我们就一起来看下Netty是怎样支持10W TPS的跨节点远程服务调用的。在正式開始解说之前,我们先简介下Netty。

相关厂商内容

Windows Azure在中国正式开启在线直付

领先在国内落地的全球化云服务。深度了解Windows Azure

利用开发測试云实现精益创业、快速迭代

Windows Azure自管理服务实现近乎零停机维护

Windows Azure专区上线,全面了解云服务

相关赞助商

技术分享

Windows Azure专区上线。全面了解云服务精彩呈现

1.2. Netty基础入门

Netty是一个高性能、异步事件驱动的NIO框架,它提供了对TCP、UDP和文件传输的支持,作为一个异步NIO框架,Netty的全部IO操作都是异步非堵塞的,通过Future-Listener机制,用户能够方便的主动获取或者通过通知机制获得IO操作结果。

作为当前最流行的NIO框架,Netty在互联网领域、大数据分布式计算领域、游戏行业、通信行业等获得了广泛的应用,一些业界著名的开源组件也基于Netty的NIO框架构建。

2. Netty高性能之道

2.1. RPC调用的性能模型分析

2.1.1. 传统RPC调用性能差的三宗罪

网络传输方式问题:传统的RPC框架或者基于RMI等方式的远程服务(过程)调用採用了同步堵塞IO,当client的并发压力或者网络时延增大之后,同步堵塞IO会因为频繁的wait导致IO线程常常性的堵塞,因为线程无法高效的工作,IO处理能力自然下降。

以下,我们通过BIO通信模型图看下BIO通信的弊端:

技术分享

图2-1 BIO通信模型图

採用BIO通信模型的服务端。通常由一个独立的Acceptor线程负责监听client的连接,接收到client连接之后为client连接创建一个新的线程处理请求消息,处理完毕之后,返回应答消息给client,线程销毁,这就是典型的一请求一应答模型。

该架构最大的问题就是不具备弹性伸缩能力。当并发訪问量添加后,服务端的线程个数和并发訪问数成线性正比,因为线程是JAVA虚拟机很宝贵的系统资源,当线程数膨胀之后,系统的性能急剧下降,随着并发量的继续添加,可能会发生句柄溢出、线程堆栈溢出等问题。并导致server终于宕机。

序列化方式问题:Java序列化存在例如以下几个典型问题:

1) Java序列化机制是Java内部的一种对象编解码技术。无法跨语言使用;比如对于异构系统之间的对接,Java序列化后的码流须要能够通过其他语言反序列化成原始对象(副本),眼下很难支持。

2) 相比于其他开源的序列化框架。Java序列化后的码流太大,不管是网络传输还是持久化到磁盘,都会导致额外的资源占用。

3) 序列化性能差(CPU资源占用高)。

线程模型问题:因为採用同步堵塞IO,这会导致每一个TCP连接都占用1个线程,因为线程资源是JVM虚拟机很宝贵的资源。当IO读写堵塞导致线程无法及时释放时。会导致系统性能急剧下降,严重的甚至会导致虚拟机无法创建新的线程。

2.1.2. 高性能的三个主题

1) 传输:用什么样的通道将数据发送给对方。BIO、NIO或者AIO,IO模型在很大程度上决定了框架的性能。

2) 协议:採用什么样的通信协议,HTTP或者内部私有协议。协议的选择不同。性能模型也不同。

相比于公有协议,内部私有协议的性能通常能够被设计的更优。

3) 线程:数据报怎样读取?读取之后的编解码在哪个线程进行,编解码后的消息怎样派发,Reactor线程模型的不同。对性能的影响也很大。

技术分享

图2-2 RPC调用性能三要素

2.2. Netty高性能之道

2.2.1. 异步非堵塞通信

在IO编程过程中。当须要同一时候处理多个client接入请求时。能够利用多线程或者IO多路复用技术进行处理。

IO多路复用技术通过把多个IO的堵塞复用到同一个select的堵塞上,从而使得系统在单线程的情况下能够同一时候处理多个client请求。与传统的多线程/多进程模型比。I/O多路复用的最大优势是系统开销小。系统不须要创建新的额外进程或者线程,也不须要维护这些进程和线程的执行,减少了系统的维护工作量,节省了系统资源。

JDK1.4提供了对非堵塞IO(NIO)的支持,JDK1.5_update10版本号使用epoll替代了传统的select/poll,极大的提升了NIO通信的性能。

JDK NIO通信模型例如以下所看到的:

技术分享

图2-3 NIO的多路复用模型图

与Socket类和ServerSocket类相相应。NIO也提供了SocketChannel和ServerSocketChannel两种不同的套接字通道实现。这两种新增的通道都支持堵塞和非堵塞两种模式。堵塞模式使用很easy。可是性能和可靠性都不好。非堵塞模式正好相反。

开发者一般能够依据自己的须要来选择合适的模式,一般来说。低负载、低并发的应用程序能够选择同步堵塞IO以减少编程复杂度。可是对于高负载、高并发的网络应用,须要使用NIO的非堵塞模式进行开发。

Netty架构依照Reactor模式设计和实现。它的服务端通信序列图例如以下:

技术分享

图2-3 NIO服务端通信序列图

client通信序列图例如以下:

技术分享

图2-4 NIOclient通信序列图

Netty的IO线程NioEventLoop因为聚合了多路复用器Selector。能够同一时候并发处理成百上千个clientChannel,因为读写操作都是非堵塞的,这就能够充分提升IO线程的执行效率。避免因为频繁IO堵塞导致的线程挂起。

另外,因为Netty採用了异步通信模式,一个IO线程能够并发处理N个client连接和读写操作。这从根本上攻克了传统同步堵塞IO一连接一线程模型。架构的性能、弹性伸缩能力和可靠性都得到了极大的提升。

2.2.2. 零拷贝

许多用户都听说过Netty具有“零拷贝”功能,可是具体体如今哪里又说不清楚,本小节就具体对Netty的“零拷贝”功能进行解说。

Netty的“零拷贝”主要体如今例如以下三个方面:

1) Netty的接收和发送ByteBuffer採用DIRECT BUFFERS,使用堆外直接内存进行Socket读写,不须要进行字节缓冲区的二次拷贝。

假设使用传统的堆内存(HEAP BUFFERS)进行Socket读写。JVM会将堆内存Buffer拷贝一份到直接内存中。然后才写入Socket中。相比于堆外直接内存。消息在发送过程中多了一次缓冲区的内存拷贝。

2) Netty提供了组合Buffer对象,能够聚合多个ByteBuffer对象。用户能够像操作一个Buffer那样方便的对组合Buffer进行操作,避免了传统通过内存拷贝的方式将几个小Buffer合并成一个大的Buffer。

3) Netty的文件传输採用了transferTo方法。它能够直接将文件缓冲区的数据发送到目标Channel,避免了传统通过循环write方式导致的内存拷贝问题。

以下,我们对上述三种“零拷贝”进行说明,先看Netty 接收Buffer的创建:

技术分享

图2-5 异步消息读取“零拷贝”

每循环读取一次消息,就通过ByteBufAllocator的ioBuffer方法获取ByteBuf对象,以下继续看它的接口定义:

技术分享

图2-6 ByteBufAllocator 通过ioBuffer分配堆外内存

当进行Socket IO读写的时候。为了避免从堆内存拷贝一份副本到直接内存,Netty的ByteBuf分配器直接创建非堆内存避免缓冲区的二次拷贝,通过“零拷贝”来提升读写性能。

以下我们继续看另外一种“零拷贝”的实现CompositeByteBuf,它对外将多个ByteBuf封装成一个ByteBuf,对外提供统一封装后的ByteBuf接口。它的类定义例如以下:

技术分享

图2-7 CompositeByteBuf类继承关系

通过继承关系我们能够看出CompositeByteBuf实际就是个ByteBuf的包装器。它将多个ByteBuf组合成一个集合,然后对外提供统一的ByteBuf接口,相关定义例如以下:

技术分享

图2-8 CompositeByteBuf类定义

加入ByteBuf,不须要做内存拷贝,相关代码例如以下:

技术分享

图2-9 新增ByteBuf的“零拷贝”

最后,我们看下文件传输的“零拷贝”:

技术分享

图2-10 文件传输“零拷贝”

Netty文件传输DefaultFileRegion通过transferTo方法将文件发送到目标Channel中,以下重点看FileChannel的transferTo方法,它的API DOC说明例如以下:

技术分享

图2-11 文件传输 “零拷贝”

对于许多操作系统它直接将文件缓冲区的内容发送到目标Channel中,而不须要通过拷贝的方式。这是一种更加高效的传输方式,它实现了文件传输的“零拷贝”。

2.2.3. 内存池

随着JVM虚拟机和JIT即时编译技术的发展,对象的分配和回收是个很轻量级的工作。

可是对于缓冲区Buffer,情况却稍有不同。特别是对于堆外直接内存的分配和回收。是一件耗时的操作。为了尽量重用缓冲区,Netty提供了基于内存池的缓冲区重用机制。以下我们一起看下Netty ByteBuf的实现:

技术分享

图2-12 内存池ByteBuf

Netty提供了多种内存管理策略。通过在启动辅助类中配置相关參数,能够实现差异化的定制。

以下通过性能測试,我们看下基于内存池循环利用的ByteBuf和普通ByteBuf的性能差异。

用例一,使用内存池分配器创建直接内存缓冲区:

技术分享

图2-13 基于内存池的非堆内存缓冲区測试用例

用例二,使用非堆内存分配器创建的直接内存缓冲区:

技术分享

图2-14 基于非内存池创建的非堆内存缓冲区測试用例

各执行300万次,性能对照结果例如以下所看到的:

技术分享

图2-15 内存池和非内存池缓冲区写入性能对照

性能測试表明。採用内存池的ByteBuf相比于朝生夕灭的ByteBuf,性能高23倍左右(性能数据与使用场景强相关)。

以下我们一起简单分析下Netty内存池的内存分配:

技术分享

图2-16 AbstractByteBufAllocator的缓冲区分配

继续看newDirectBuffer方法,我们发现它是一个抽象方法,由AbstractByteBufAllocator的子类负责具体实现。代码例如以下:

技术分享

图2-17 newDirectBuffer的不同实现

代码跳转到PooledByteBufAllocator的newDirectBuffer方法,从Cache中获取内存区域PoolArena,调用它的allocate方法进行内存分配:

技术分享

图2-18 PooledByteBufAllocator的内存分配

PoolArena的allocate方法例如以下:

技术分享

图2-18 PoolArena的缓冲区分配

我们重点分析newByteBuf的实现。它相同是个抽象方法,由子类DirectArena和HeapArena来实现不同类型的缓冲区分配,因为測试用例使用的是堆外内存。

技术分享

图2-19 PoolArena的newByteBuf抽象方法

因此重点分析DirectArena的实现:假设没有开启使用sun的unsafe,则

技术分享

图2-20 DirectArena的newByteBuf方法实现

执行PooledDirectByteBuf的newInstance方法。代码例如以下:

技术分享

图2-21 PooledDirectByteBuf的newInstance方法实现

通过RECYCLER的get方法循环使用ByteBuf对象,假设是非内存池实现,则直接创建一个新的ByteBuf对象。从缓冲池中获取ByteBuf之后,调用AbstractReferenceCountedByteBuf的setRefCnt方法设置引用计数器,用于对象的引用计数和内存回收(相似JVM垃圾回收机制)。

2.2.4. 高效的Reactor线程模型

常常使用的Reactor线程模型有三种,分别例如以下:

1) Reactor单线程模型。

2) Reactor多线程模型。

3) 主从Reactor多线程模型

Reactor单线程模型,指的是全部的IO操作都在同一个NIO线程上面完毕,NIO线程的职责例如以下:

1) 作为NIO服务端。接收client的TCP连接;

2) 作为NIOclient,向服务端发起TCP连接;

3) 读取通信对端的请求或者应答消息。

4) 向通信对端发送消息请求或者应答消息。

Reactor单线程模型示意图例如以下所看到的:

技术分享

图2-22 Reactor单线程模型

因为Reactor模式使用的是异步非堵塞IO,全部的IO操作都不会导致堵塞,理论上一个线程能够独立处理全部IO相关的操作。从架构层面看,一个NIO线程确实能够完毕其承担的职责。比如,通过Acceptor接收client的TCP连接请求消息。链路建立成功之后,通过Dispatch将相应的ByteBuffer派发到指定的Handler上进行消息解码。用户Handler能够通过NIO线程将消息发送给client。

对于一些小容量应用场景,能够使用单线程模型。

可是对于高负载、大并发的应用却不合适。主要原因例如以下:

1) 一个NIO线程同一时候处理成百上千的链路,性能上无法支撑,即便NIO线程的CPU负荷达到100%,也无法满足海量消息的编码、解码、读取和发送;

2) 当NIO线程负载过重之后,处理速度将变慢,这会导致大量client连接超时,超时之后往往会进行重发。这更加重了NIO线程的负载。终于会导致大量消息积压和处理超时,NIO线程会成为系统的性能瓶颈;

3) 可靠性问题:一旦NIO线程意外跑飞,或者进入死循环。会导致整个系统通信模块不可用,不能接收和处理外部消息,造成节点故障。

为了解决这些问题,演进出了Reactor多线程模型。以下我们一起学习下Reactor多线程模型。

Rector多线程模型与单线程模型最大的差别就是有一组NIO线程处理IO操作,它的原理图例如以下:

技术分享

图2-23 Reactor多线程模型

Reactor多线程模型的特点:

1) 有专门一个NIO线程-Acceptor线程用于监听服务端,接收client的TCP连接请求。

2) 网络IO操作-读、写等由一个NIO线程池负责,线程池能够採用标准的JDK线程池实现。它包括一个任务队列和N个可用的线程,由这些NIO线程负责消息的读取、解码、编码和发送;

3) 1个NIO线程能够同一时候处理N条链路。可是1个链路仅仅相应1个NIO线程,防止发生并发操作问题。

在绝大多数场景下,Reactor多线程模型都能够满足性能需求。可是,在极特殊应用场景中,一个NIO线程负责监听和处理全部的client连接可能会存在性能问题。比如百万client并发连接。或者服务端须要对client的握手消息进行安全认证,认证本身很损耗性能。在这类场景下,单独一个Acceptor线程可能会存在性能不足问题,为了解决性能问题,产生了第三种Reactor线程模型-主从Reactor多线程模型。

主从Reactor线程模型的特点是:服务端用于接收client连接的不再是个1个单独的NIO线程。而是一个独立的NIO线程池。

Acceptor接收到clientTCP连接请求处理完毕后(可能包括接入认证等)。将新创建的SocketChannel注冊到IO线程池(sub reactor线程池)的某个IO线程上,由它负责SocketChannel的读写和编解码工作。

Acceptor线程池仅仅仅仅用于client的登陆、握手和安全认证。一旦链路建立成功,就将链路注冊到后端subReactor线程池的IO线程上,由IO线程负责兴许的IO操作。

它的线程模型例如以下图所看到的:

技术分享

图2-24 Reactor主从多线程模型

利用主从NIO线程模型,能够解决1个服务端监听线程无法有效处理全部client连接的性能不足问题。因此。在Netty的官方demo中,推荐使用该线程模型。

其实,Netty的线程模型并非固定不变,通过在启动辅助类中创建不同的EventLoopGroup实例并通过适当的參数配置,就能够支持上述三种Reactor线程模型。

正是因为Netty 对Reactor线程模型的支持提供了灵活的定制能力,所以能够满足不同业务场景的性能诉求。

2.2.5. 无锁化的串行设计理念

在大多数场景下,并行多线程处理能够提升系统的并发性能。可是。假设对于共享资源的并发訪问处理不当。会带来严重的锁竞争,这终于会导致性能的下降。为了尽可能的避免锁竞争带来的性能损耗,能够通过串行化设计,即消息的处理尽可能在同一个线程内完毕。期间不进行线程切换,这样就避免了多线程竞争和同步锁。

为了尽可能提升性能,Netty採用了串行无锁化设计,在IO线程内部进行串行操作。避免多线程竞争导致的性能下降。表面上看,串行化设计似乎CPU利用率不高。并发程度不够。可是。通过调整NIO线程池的线程參数,能够同一时候启动多个串行化的线程并行执行。这样的局部无锁化的串行线程设计相比一个队列-多个工作线程模型性能更优。

Netty的串行化设计工作原理图例如以下:

技术分享

图2-25 Netty串行化工作原理图

Netty的NioEventLoop读取到消息之后,直接调用ChannelPipeline的fireChannelRead(Object msg),仅仅要用户不主动切换线程,一直会由NioEventLoop调用到用户的Handler,期间不进行线程切换。这样的串行化处理方式避免了多线程操作导致的锁的竞争。从性能角度看是最优的。

2.2.6. 高效的并发编程

Netty的高效并发编程主要体如今例如以下几点:

1) volatile的大量、正确使用;

2) CAS和原子类的广泛使用;

3) 线程安全容器的使用;

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

假设大家想了解Netty高效并发编程的细节。能够阅读之前我在微博分享的《多线程并发编程在 Netty 中的应用分析》。在这篇文章中对Netty的多线程技巧和应用进行了具体的介绍和分析。

2.2.7. 高性能的序列化框架

影响序列化性能的关键因素总结例如以下:

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

2) 序列化&反序列化的性能(CPU资源占用);

3) 是否支持跨语言(异构系统的对接和开发语言切换)。

Netty默认提供了对Google Protobuf的支持,通过扩展Netty的编解码接口。用户能够实现其他的高性能序列化框架,比如Thrift的压缩二进制编解码框架。

以下我们一起看下不同序列化&反序列化框架序列化后的字节数组对照:

技术分享

图2-26 各序列化框架序列化码流大小对照

从上图能够看出,Protobuf序列化后的码流仅仅有Java序列化的1/4左右。正是因为Java原生序列化性能表现太差,才催生出了各种高性能的开源序列化技术和框架(性能差仅仅是其中的一个原因,还有跨语言、IDL定义等其他因素)。

2.2.8. 灵活的TCP參数配置能力

合理设置TCP參数在某些场景下对于性能的提升能够起到显著的效果,比如SO_RCVBUF和SO_SNDBUF。假设设置不当。对性能的影响是很大的。以下我们总结下对性能影响比較大的几个配置项:

1) SO_RCVBUF和SO_SNDBUF:通常建议值为128K或者256K;

2) SO_TCPNODELAY:NAGLE算法通过将缓冲区内的小封包自己主动相连,组成较大的封包,阻止大量小封包的发送堵塞网络,从而提高网络应用效率。

可是对于时延敏感的应用场景须要关闭该优化算法;

3) 软中断:假设Linux内核版本号支持RPS(2.6.35以上版本号),开启RPS后能够实现软中断,提升网络吞吐量。RPS依据数据包的源地址,目的地址以及目的和源端口,计算出一个hash值。然后依据这个hash值来选择软中断执行的cpu。从上层来看。也就是说将每一个连接和cpu绑定,并通过这个hash值,来均衡软中断在多个cpu上。提升网络并行处理性能。

Netty在启动辅助类中能够灵活的配置TCP參数。满足不同的用户场景。相关配置接口定义例如以下:

技术分享

图2-27 Netty的TCP參数配置定义

2.3. 总结

通过对Netty的架构和性能模型进行分析。我们发现Netty架构的高性能是被精心设计和实现的,得益于高质量的架构和代码,Netty支持10W TPS的跨节点服务调用并非件十分困难的事情。

3. 作者简介

李林锋。2007年毕业于东北大学,2008年进入华为公司从事高性能通信软件的设计和开发工作,有6年NIO设计和开发经验,精通Netty、Mina等NIO框架。Netty中国社区创始人。《Netty权威指南》作者。

联系方式:新浪微博 Nettying 微信:Nettying


感谢张龙对本文的审校,郭蕾对本文的策划。

给InfoQ中文站投稿或者參与内容翻译工作,请邮件至editors@cn.infoq.com。也欢迎大家通过新浪微博(@InfoQ)或者腾讯微博(@InfoQ)关注我们。并与我们的编辑和其他读者朋友交流。

免费赠送QCon/ArchSummit门票、热门图书,InfoQ联合亚马逊推出“注冊信息即送AWS服务25美元折扣券”活动。
  • 领域
  • 架构 & 设计
  • 语言 & 开发
  • 专栏
  • Netty
  • 性能调优
  • Performance

相关内容

告诉我们您的想法

社区评论Watch Thread
採用内存池的ByteBuf相比于朝生夕灭的ByteBuf,性能高23倍左右 by Zhang Yuan Posted 2014年5月30日 10:43
Re: 採用内存池的ByteBuf相比于朝生夕灭的ByteBuf,性能高23倍左右 by 林锋 李 Posted 2014年5月31日 03:34
Re: 採用内存池的ByteBuf相比于朝生夕灭的ByteBuf。性能高23倍左右 by Jesse Q Posted 2014年7月4日 10:37
Re: 採用内存池的ByteBuf相比于朝生夕灭的ByteBuf,性能高23倍左右 by 林锋 李 Posted 2014年7月4日 10:59
Good by 孙 奇辉 Posted 2014年5月31日 02:31
Re: Good by 林锋 李 Posted 2014年5月31日 03:35
 by yan yan Posted 2014年6月2日 11:21
Re: 赞 by 林锋 李 Posted 2014年6月3日 02:18
支持,须要深入了解netty by 刘 鹏 Posted 2014年6月3日 10:30
Re: 支持。须要深入了解netty by 林锋 李 Posted 2014年6月3日 02:14
node.js by he rn Posted 2014年6月3日 05:18
Re: node.js by 林锋 李 Posted 2014年6月4日 11:36
Re: node.js by zhang frank Posted 2014年6月5日 04:11
Re: node.js by 林锋 李 Posted 2014年6月5日 09:57
Ding by qingyi xu Posted 2014年6月5日 01:27
Re: Ding by 林锋 李 Posted 2014年6月5日 10:47
Good by 穆 晓林 Posted 2014年6月5日 07:28
Re: Good by 林锋 李 Posted 2014年6月5日 10:09
Re: Good by 林锋 李 Posted 2014年6月5日 10:09
Re: Good by 林锋 李 Posted 2014年6月5日 10:09
Re: Good by 林锋 李 Posted 2014年6月5日 10:09
Re: Good by 林锋 李 Posted 2014年6月5日 10:09
不好意思。刚才点击回复没有反应。我连续点了多次,没想到居然反复发了5份,杯具啊。

 by 林锋 李 Posted2014年6月5日 10:41

求推荐 by qingyi xu Posted 2014年6月9日 04:16
Re: 求推荐 by 林锋 李 Posted 2014年6月11日 09:21
对于“Reactor主从多线程模型”不太理解 by 徐 小虾 Posted 2014年6月20日 06:23
Re: 对于“Reactor主从多线程模型”不太理解 by 林锋 李 Posted 2014年6月27日 11:47
做为client 使用socket短链接有必要使用NIO吗? by kai shen Posted 2014年6月26日 12:22
Re: 做为client 使用socket短链接有必要使用NIO吗? by 林锋 李 Posted 2014年6月27日 11:50

採用内存池的ByteBuf相比于朝生夕灭的ByteBuf,性能高23倍左右2014年5月30日 10:43 by Zhang Yuan

之所以会这样,是因为ByteBUffer可能是从Native Memory分配出来的。


所以分配和回收效率要远低于在Java Heap上的对象

  • 回复
  • 回到顶部

Good2014年5月31日 02:31 by 孙 奇辉

顶,请继续多写!

  • 回复
  • 回到顶部

Re: 採用内存池的ByteBuf相比于朝生夕灭的ByteBuf。性能高23倍左右2014年5月31日 03:34 by 林锋 李

是的。

所以ByteBuffer的最优使用方法是:
1)网络IO读写,直接与Socket打交道的使用直接内存;
2)其他的用途的ByteBuffer。建议直接使用ByteBuffer。



虽然基于堆内存分配的ByteBuffer性能已经很高。可是大块缓冲区的开辟和回收依旧很损耗性能,
假设为每条消息都创建一个ByteBuffer。用完就马上回收,这不是一个好的策略,所以Netty开发和提供了ByteBuffer 内存池。

  • 回复
  • 回到顶部

Re: Good2014年5月31日 03:35 by 林锋 李

谢谢鼓舞。大家对实战型的干货还是很渴求的。后面我会继续分享一些Netty的干货!

  • 回复
  • 回到顶部

2014年6月2日 11:21 by yan yan

顶。继续期待兴许的文章。

  • 回复
  • 回到顶部

支持。须要深入了解netty2014年6月3日 10:30 by 刘 鹏

支持。正准备升级netty从3到4.x
  • 回复
  • 回到顶部

Re: 支持,须要深入了解netty2014年6月3日 02:14 by 林锋 李

从Netty 3升级到4还是有一些小麻烦,接口层面变更的有点多,无法前向兼容。架构也重构了下。添加了一些功能,改动了一些接口设计。

升级中假设遇到什么疑难问题,也能够发邮件给我讨论下,我打算将来有空写一篇具体点的升级指南。

  • 回复
  • 回到顶部

Re: 赞2014年6月3日 02:18 by 林锋 李

多谢。这些都是从实践中提炼出来的,所以对于自己的框架设计也有指导意义。

  • 回复
  • 回到顶部

node.js2014年6月3日 05:18 by he rn

能否分析一下node.js是否也能做到这些?
  • 回复
  • 回到顶部

Re: node.js2014年6月4日 11:36 by 林锋 李

这个能够由精通node.js的朋友们结合具体的性能数据和业务场景分析下。

  • 回复
  • 回到顶部

Ding2014年6月5日 01:27 by qingyi xu

近期在做的一个远程RPC框架也是使用的 Netty 作为底层通信框架,当前使用Netty3性能已经很不错了,不知道升级Netty4后还有多大的惊喜!
  • 回复
  • 回到顶部

Re: Ding2014年6月5日 10:47 by 林锋 李

能够这样说,有 "惊" 也有 "喜" ,相信你升级的时候就会有深切体会了。
  • 回复
  • 回到顶部

Re: node.js2014年6月5日 04:11 by zhang frank

NodeJS採用的是“Reactor多线程模型”,即一个Acceptor线程负责接收请求。全部的IO操作由系统IO线程池完毕。而且Node针对不同平台的IO策略进行了优化,在windows下是用IOCP,而*nix下採用的是自己定义的IO线程池。

  • 回复
  • 回到顶部

Good2014年6月5日 07:28 by 穆 晓林

1) SO_RCVBUF和SO_SNDBUF:通常建议值为128K或者256K;
为什么要设置这么大的缓冲区呢,保持1000tcp链接能否够觉得(256k+128K)*1000的内存
  • 回复
  • 回到顶部

Re: node.js2014年6月5日 09:57 by 林锋 李

嗯。IO线程模型几乎相同。只是Netty的IO线程模型能够由用户定制,支持多种模式。Netty也做了许多底层的优化。比如优化了Selector的选择键列表,它有一些性能开关。

只是过分追求性能也是把双刃剑,比如Netty直接利用了一些JDK提供商相关的特性。如sun的Unsafe。

  • 回复
  • 回到顶部

Re: Good2014年6月5日 10:09 by 林锋 李

这样设置的原因是为了有效的提升性能,具体的原因不解释了,你能够去了解下相关知识。
关于内存的问题,有两种解决的方法:
1) 依据实际的组网计算内存。JDK的内存上限未必一定要设置成4G或者8G;
2) 内存缓冲区能够使用内存池,消费完放回池子,不是每条链路都一直占用这么多内存。



实际上你说的问题不存在,原因例如以下:
1. 假设是长连接,1000个TCP,意味着1000个节点的集群组网。国内除了阿里等互联网巨头。谁有这么大的集群组网?
2. 假设是短连接。处理完毕链路就会关闭,资源释放,buffer是不会被某条链路长期持有的;
3. 集群情况下,消息是分发到多个节点上的。
4. 内存池的应用。

实际上,你改小,依照这个公式,那我 10W个链路,100W个链路。内存还是不够,你改小也没用。

不够就加内存呗。假设server内存不足。那就说明支持不了这么多链路。

  • 回复
  • 回到顶部

Re: Good2014年6月5日 10:09 by 林锋 李

这样设置的原因是为了有效的提升性能。具体的原因不解释了。你能够去了解下相关知识。
关于内存的问题,有两种解决的方法:
1) 依据实际的组网计算内存。JDK的内存上限未必一定要设置成4G或者8G;
2) 内存缓冲区能够使用内存池,消费完放回池子。不是每条链路都一直占用这么多内存。

实际上你说的问题不存在。原因例如以下:
1. 假设是长连接。1000个TCP,意味着1000个节点的集群组网,国内除了阿里等互联网巨头。谁有这么大的集群组网?
2. 假设是短连接,处理完毕链路就会关闭,资源释放,buffer是不会被某条链路长期持有的。
3. 集群情况下,消息是分发到多个节点上的。
4. 内存池的应用。

实际上,你改小,依照这个公式,那我 10W个链路,100W个链路。内存还是不够,你改小也没用。不够就加内存呗,假设server内存不足,那就说明支持不了这么多链路。
  • 回复
  • 回到顶部

Re: Good2014年6月5日 10:09 by 林锋 李

这样设置的原因是为了有效的提升性能,具体的原因不解释了,你能够去了解下相关知识。
关于内存的问题,有两种解决的方法:
1) 依据实际的组网计算内存,JDK的内存上限未必一定要设置成4G或者8G。
2) 内存缓冲区能够使用内存池,消费完放回池子,不是每条链路都一直占用这么多内存。

实际上你说的问题不存在,原因例如以下:
1. 假设是长连接,1000个TCP。意味着1000个节点的集群组网,国内除了阿里等互联网巨头,谁有这么大的集群组网?
2. 假设是短连接。处理完毕链路就会关闭,资源释放。buffer是不会被某条链路长期持有的;
3. 集群情况下,消息是分发到多个节点上的;
4. 内存池的应用。

实际上,你改小,依照这个公式,那我 10W个链路,100W个链路,内存还是不够,你改小也没用。不够就加内存呗。假设server内存不足,那就说明支持不了这么多链路。
  • 回复
  • 回到顶部

Re: Good2014年6月5日 10:09 by 林锋 李

这样设置的原因是为了有效的提升性能。具体的原因不解释了。你能够去了解下相关知识。
关于内存的问题。有两种解决的方法:
1) 依据实际的组网计算内存,JDK的内存上限未必一定要设置成4G或者8G;
2) 内存缓冲区能够使用内存池,消费完放回池子,不是每条链路都一直占用这么多内存。

实际上你说的问题不存在,原因例如以下:
1. 假设是长连接,1000个TCP,意味着1000个节点的集群组网。国内除了阿里等互联网巨头,谁有这么大的集群组网?
2. 假设是短连接,处理完毕链路就会关闭,资源释放,buffer是不会被某条链路长期持有的。
3. 集群情况下,消息是分发到多个节点上的;
4. 内存池的应用。



实际上,你改小。依照这个公式。那我 10W个链路,100W个链路,内存还是不够,你改小也没用。

不够就加内存呗,假设server内存不足,那就说明支持不了这么多链路。

  • 回复
  • 回到顶部

Re: Good2014年6月5日 10:09 by 林锋 李

这样设置的原因是为了有效的提升性能。具体的原因不解释了,你能够去了解下相关知识。
关于内存的问题。有两种解决的方法:
1) 依据实际的组网计算内存,JDK的内存上限未必一定要设置成4G或者8G;
2) 内存缓冲区能够使用内存池,消费完放回池子。不是每条链路都一直占用这么多内存。



实际上你说的问题不存在,原因例如以下:
1. 假设是长连接,1000个TCP,意味着1000个节点的集群组网,国内除了阿里等互联网巨头,谁有这么大的集群组网?
2. 假设是短连接,处理完毕链路就会关闭,资源释放,buffer是不会被某条链路长期持有的;
3. 集群情况下,消息是分发到多个节点上的。
4. 内存池的应用。

实际上,你改小。依照这个公式。那我 10W个链路,100W个链路,内存还是不够,你改小也没用。不够就加内存呗。假设server内存不足,那就说明支持不了这么多链路。

  • 回复
  • 回到顶部

不好意思,刚才点击回复没有反应。我连续点了多次,没想到居然反复发了5份,杯具啊。

2014年6月5日 10:41 by 林锋 李

如题,也没有滤重功能......
  • 回复
  • 回到顶部

求推荐2014年6月9日 04:16 by qingyi xu

博主有没有Netty4或者最新的5的学习书籍?Netty迁移中须要注意的。也包括Netty新版本号的新特性介绍的
  • 回复
  • 回到顶部

Re: 求推荐2014年6月11日 09:21 by 林锋 李

网上有一些Netty 3到 Netty4的 API差异对照,感兴趣你能够看下。
实际上,Netty 3升级到 4后架构进行了重构和优化。假设你想升级到4。还是须要认真学习下 Netty 4。
眼下,系统介绍 Netty 4和 Netty5的书籍不多。眼下市场上有两本。



1. Netty in Action: 英文版的。亚马逊能够买到。大概500元左右;
2. Netty权威指南,6月份刚出版,在互动、亚马逊、当当、京东等能够预定。预计6月中下旬能发货。



还有最后一个途径就是阅读源代码。这个须要具备三个条件:1. 有一定的NIO编程经验。2. 实际应用过Netty;3. 喜欢钻研源代码。

  • 回复
  • 回到顶部

对于“Reactor主从多线程模型”不太理解2014年6月20日 06:23 by 徐 小虾

在上面的“Reactor主从多线程模型”中有几个线程池?会生成一个ServerSocketChannel还是多个ServerSocketChannel呢?
  • 回复
  • 回到顶部

做为client 使用socket短链接有必要使用NIO吗?2014年6月26日 12:22 by kai shen

我刚接触网络编程不久,之前仅仅知道MINA。想问一下jetty更主流些吗? 还有我们系统接收socket报文后还要通过 socket 请求另外一个系统,然后依据请求结果返回给client请求的处理结果。

採用的都是短链接,我们即做服务端又做client,服务端我们用mina client就用的jdk 的类。请问client有必要也用Nio吗?有什么优点吗?对于短链接来讲

  • 回复
  • 回到顶部

Re: 对于“Reactor主从多线程模型”不太理解2014年6月27日 11:47 by 林锋 李

你的问题很好,看来你对NIO编程还是比較熟悉的。

主从多线程模型中有1个线程池。仅仅有一个Acceptor线程用于SocketChannel接入。然后将其投递到本线程组其他的可用线程中处理兴许的接入认证、黑白名单校验、加解密、编解码等操作,因为这些操作须要一定的时间,因为由独立的线程负责,否则Acceptor线程无法及时处理其他的接入。

这样的模型的ServerSocketChannel仅仅有一个。挂载在Acceptor线程上。



该模型通常常使用于海量的client接入和推送系统中。

  • 回复
  • 回到顶部

Re: 做为client 使用socket短链接有必要使用NIO吗?2014年6月27日 11:50 by 林锋 李

Jetty是轻量级的HTTP协议栈和Web容器,比較流行。

不管服务端还是client,都须要操作IO,假设对方处理速度比較慢,常常超时,而你的超时时间又无法设置太短。就会导致你的client通信线程常常挂住,可靠性比較差。因此建议你使用NIO。
  • 回复
  • 回到顶部

Re: 採用内存池的ByteBuf相比于朝生夕灭的ByteBuf。性能高23倍左右2014年7月4日 10:37 by Jesse Q

菜鸟一枚,请教一个问题:在堆外分配的内存是由full gc 来释放的?,那么假设堆的内存比較充足的时候长时间不触发full gc。是不是堆外的内存就被占用着,是不是意味着堆外的机器内存将会耗光?
  • 回复
  • 回到顶部

Re: 採用内存池的ByteBuf相比于朝生夕灭的ByteBuf,性能高23倍左右2014年7月4日 10:59 by 林锋 李

这篇文章写得很清楚。建议你能够參考下:blog.csdn.net/xieyuooo/article/details/7547435
  • 回复
  • 回到顶部




评论


亲,登录后才可以留言!