BT

你的观点很重要! 快来参与InfoQ调研吧!

Netty系列之Netty高性能之道

| 作者 李林锋 关注 54 他的粉丝 发布于 2014年5月30日. 估计阅读时间: 25 分钟 | ArchSummit社交架构图谱:Facebook、Snapchat、Tumblr等背后的核心技术

1. 背景

1.1. 惊人的性能数据

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

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

下面我们就一起来看下Netty是如何支持10W TPS的跨节点远程服务调用的,在正式开始讲解之前,我们先简单介绍下Netty。

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,当客户端的并发压力或者网络时延增大之后,同步阻塞IO会由于频繁的wait导致IO线程经常性的阻塞,由于线程无法高效的工作,IO处理能力自然下降。

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

图2-1 BIO通信模型图

采用BIO通信模型的服务端,通常由一个独立的Acceptor线程负责监听客户端的连接,接收到客户端连接之后为客户端连接创建一个新的线程处理请求消息,处理完成之后,返回应答消息给客户端,线程销毁,这就是典型的一请求一应答模型。该架构最大的问题就是不具备弹性伸缩能力,当并发访问量增加后,服务端的线程个数和并发访问数成线性正比,由于线程是JAVA虚拟机非常宝贵的系统资源,当线程数膨胀之后,系统的性能急剧下降,随着并发量的继续增加,可能会发生句柄溢出、线程堆栈溢出等问题,并导致服务器最终宕机。

序列化方式问题: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编程过程中,当需要同时处理多个客户端接入请求时,可以利用多线程或者IO多路复用技术进行处理。IO多路复用技术通过把多个IO的阻塞复用到同一个select的阻塞上,从而使得系统在单线程的情况下可以同时处理多个客户端请求。与传统的多线程/多进程模型比,I/O多路复用的最大优势是系统开销小,系统不需要创建新的额外进程或者线程,也不需要维护这些进程和线程的运行,降低了系统的维护工作量,节省了系统资源。

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

JDK NIO通信模型如下所示:

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

与Socket类和ServerSocket类相对应,NIO也提供了SocketChannel和ServerSocketChannel两种不同的套接字通道实现。这两种新增的通道都支持阻塞和非阻塞两种模式。阻塞模式使用非常简单,但是性能和可靠性都不好,非阻塞模式正好相反。开发人员一般可以根据自己的需要来选择合适的模式,一般来说,低负载、低并发的应用程序可以选择同步阻塞IO以降低编程复杂度。但是对于高负载、高并发的网络应用,需要使用NIO的非阻塞模式进行开发。

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

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

客户端通信序列图如下:

图2-4 NIO客户端通信序列图

Netty的IO线程NioEventLoop由于聚合了多路复用器Selector,可以同时并发处理成百上千个客户端Channel,由于读写操作都是非阻塞的,这就可以充分提升IO线程的运行效率,避免由于频繁IO阻塞导致的线程挂起。另外,由于Netty采用了异步通信模式,一个IO线程可以并发处理N个客户端连接和读写操作,这从根本上解决了传统同步阻塞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服务端,接收客户端的TCP连接;

2) 作为NIO客户端,向服务端发起TCP连接;

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

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

Reactor单线程模型示意图如下所示:

图2-22 Reactor单线程模型

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

对于一些小容量应用场景,可以使用单线程模型。但是对于高负载、大并发的应用却不合适,主要原因如下:

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

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

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

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

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

图2-23 Reactor多线程模型

Reactor多线程模型的特点:

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

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

3) 1个NIO线程可以同时处理N条链路,但是1个链路只对应1个NIO线程,防止发生并发操作问题。

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

主从Reactor线程模型的特点是:服务端用于接收客户端连接的不再是个1个单独的NIO线程,而是一个独立的NIO线程池。Acceptor接收到客户端TCP连接请求处理完成后(可能包含接入认证等),将新创建的SocketChannel注册到IO线程池(sub reactor线程池)的某个IO线程上,由它负责SocketChannel的读写和编解码工作。Acceptor线程池仅仅只用于客户端的登陆、握手和安全认证,一旦链路建立成功,就将链路注册到后端subReactor线程池的IO线程上,由IO线程负责后续的IO操作。

它的线程模型如下图所示:

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

利用主从NIO线程模型,可以解决1个服务端监听线程无法有效处理所有客户端连接的性能不足问题。因此,在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)关注我们,并与我们的编辑和其他读者朋友交流。

评价本文

专业度
风格

您好,朋友!

您需要 注册一个InfoQ账号 或者 才能进行评论。在您完成注册后还需要进行一些设置。

获得来自InfoQ的更多体验。

告诉我们您的想法

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我
社区评论

采用内存池的ByteBuf相比于朝生夕灭的ByteBuf,性能高23倍左右 by Zhang Yuan

之所以会这样,是因为ByteBUffer可能是从Native Memory分配出来的。
所以分配和回收效率要远低于在Java Heap上的对象

Good by 孙 奇辉

顶,请继续多写!

Re: 采用内存池的ByteBuf相比于朝生夕灭的ByteBuf,性能高23倍左右 by 林锋 李

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

尽管基于堆内存分配的ByteBuffer性能已经很高,但是大块缓冲区的开辟和回收依然非常损耗性能,
如果为每条消息都创建一个ByteBuffer,用完就立即回收,这不是一个好的策略,所以Netty开发和提供了ByteBuffer 内存池。

Re: Good by 林锋 李

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

by yan yan

顶。继续期待后续的文章。

支持,需要深入了解netty by 刘 鹏

支持,正准备升级netty从3到4.x

Re: 支持,需要深入了解netty by 林锋 李

从Netty 3升级到4还是有一些小麻烦,接口层面变更的有点多,无法前向兼容。架构也重构了下,增加了一些功能,修改了一些接口设计。升级中如果遇到什么疑难问题,也可以发邮件给我讨论下,我打算将来有空写一篇详细点的升级指南。

Re: 赞 by 林锋 李

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

node.js by he rn

能否分析一下node.js是否也能做到这些?

Re: node.js by 林锋 李

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

Ding by qingyi xu

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

Re: Ding by 林锋 李

可以这样说,有 "惊" 也有 "喜" ,相信你升级的时候就会有深切体会了。

Re: node.js by zhang frank

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

Good by 穆 晓林

1) SO_RCVBUF和SO_SNDBUF:通常建议值为128K或者256K;
为什么要设置这么大的缓冲区呢,保持1000tcp链接是否可以认为(256k+128K)*1000的内存

Re: node.js by 林锋 李

嗯,IO线程模型差不多,不过Netty的IO线程模型可以由用户定制,支持多种模式。Netty也做了很多底层的优化,例如优化了Selector的选择键列表,它有一些性能开关。不过过分追求性能也是把双刃剑,例如Netty直接利用了一些JDK提供商相关的特性,如sun的Unsafe。

Re: Good by 林锋 李

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

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

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

Re: Good by 林锋 李

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

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

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

Re: Good by 林锋 李

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

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

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

Re: Good by 林锋 李

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

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

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

Re: Good by 林锋 李

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

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

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

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

如题,也没有滤重功能......

求推荐 by qingyi xu

博主有没有Netty4或者最新的5的学习书籍?Netty迁移中需要注意的,也包括Netty新版本的新特性介绍的

Re: 求推荐 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主从多线程模型”不太理解 by 徐 小虾

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

做为客户端 使用socket短链接有必要使用NIO吗? by kai shen

我刚接触网络编程不久,之前只知道MINA。想问一下jetty更主流些吗? 还有我们系统接收socket报文后还要通过 socket 请求另外一个系统,然后根据请求结果返回给客户端请求的处理结果。采用的都是短链接,我们即做服务端又做客户端,服务端我们用mina 客户端就用的jdk 的类。请问客户端有必要也用Nio吗?有什么好处吗?对于短链接来讲

Re: 对于“Reactor主从多线程模型”不太理解 by 林锋 李

你的问题非常好,看来你对NIO编程还是比较熟悉的。

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

这种模型的ServerSocketChannel只有一个,挂载在Acceptor线程上。

该模型通常用于海量的客户端接入和推送系统中。

Re: 做为客户端 使用socket短链接有必要使用NIO吗? by 林锋 李

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

无论服务端还是客户端,都需要操作IO,如果对方处理速度比较慢,经常超时,而你的超时时间又无法设置太短,就会导致你的客户端通信线程经常挂住,可靠性比较差。因此建议你使用NIO。

Re: 采用内存池的ByteBuf相比于朝生夕灭的ByteBuf,性能高23倍左右 by Jesse Q

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

Re: 采用内存池的ByteBuf相比于朝生夕灭的ByteBuf,性能高23倍左右 by 林锋 李

这篇文章写得非常清楚,建议你可以参考下:blog.csdn.net/xieyuooo/article/details/7547435

Re: 采用内存池的ByteBuf相比于朝生夕灭的ByteBuf,性能高23倍左右 by 左 裕初

这篇文章讲的是JavaNio范畴的ByteBuffer的GC?

Netty在这一块是一样的嘛?

Re: 采用内存池的ByteBuf相比于朝生夕灭的ByteBuf,性能高23倍左右 by 左 裕初

我觉得这个说得清楚一点

github.com/netty/netty/wiki/Reference-counted-o...

Netty使用的是引用计数的方法,一个对象unreachable了jvm自然就会回收 它

关注netty几个月了,看到这篇文章解惑了 by 陈 建

请问线程模型的图是用哪个工具画的?平时不怎么画,3个主要的工具都太庞大。

netty5小版本切换引发的问题 by jacky 别理科夫

发现一个问题,使用netty的example项目中的http-upload组件,我从浏览器端进行文件上传常规form表单提交,文件都能正常传到服务器端,但是之后5.0.0.Alpha1这个版本是没有正常返回到浏览器端,netty-5.0.0.Alpha2这个版本能正常返回服务器端信息发到浏览器端。对比了下两边HttpUploadServerHandler的实现,除了一些方法调用改变名称外感觉没啥特别的区别,想问问李林峰大神看看有没有时间帮忙给予解答,谢谢!

netty5小版本切换引发的问题 by jacky 别理科夫

发现一个问题,使用netty的example项目中的http-upload组件,我从浏览器端进行文件上传常规form表单提交,文件都能正常传到服务器端,但是之后5.0.0.Alpha1这个版本是没有正常返回到浏览器端,netty-5.0.0.Alpha2这个版本能正常返回服务器端信息发到浏览器端。对比了下两边HttpUploadServerHandler的实现,除了一些方法调用改变名称外感觉没啥特别的区别,想问问李林峰大神看看有没有时间帮忙给予解答,谢谢!

netty5小版本切换引发的问题 by jacky 别理科夫

发现一个问题,使用netty的example项目中的http-upload组件,我从浏览器端进行文件上传常规form表单提交,文件都能正常传到服务器端,但是之后5.0.0.Alpha1这个版本是没有正常返回到浏览器端,netty-5.0.0.Alpha2这个版本能正常返回服务器端信息发到浏览器端。对比了下两边HttpUploadServerHandler的实现,除了一些方法调用改变名称外感觉没啥特别的区别,想问问李林峰大神看看有没有时间帮忙给予解答,谢谢!

netty5小版本切换引发的问题 by jacky 别理科夫

发现一个问题,使用netty的example项目中的http-upload组件,我从浏览器端进行文件上传常规form表单提交,文件都能正常传到服务器端,但是之后5.0.0.Alpha1这个版本是没有正常返回到浏览器端,netty-5.0.0.Alpha2这个版本能正常返回服务器端信息发到浏览器端。对比了下两边HttpUploadServerHandler的实现,除了一些方法调用改变名称外感觉没啥特别的区别,想问问李林峰大神看看有没有时间帮忙给予解答,谢谢!

netty5小版本切换引发的问题 by jacky 别理科夫

发现一个问题,使用netty的example项目中的http-upload组件,我从浏览器端进行文件上传常规form表单提交,文件都能正常传到服务器端,但是之后5.0.0.Alpha1这个版本是没有正常返回到浏览器端,netty-5.0.0.Alpha2这个版本能正常返回服务器端信息发到浏览器端。对比了下两边HttpUploadServerHandler的实现,除了一些方法调用改变名称外感觉没啥特别的区别,想问问李林峰大神看看有没有时间帮忙给予解答,谢谢!

建立连接后,第一次发送消息比较慢 by 田 艾特

建立连接后,客户端向服务器发送消息,我在解码的地方打印日志,发现4-5s之后才能收到客户端请求。第二次发送请求速度就很快了,没有这种现象了

建立连接后,第一次发送消息比较慢 by 田 艾特

建立连接后,客户端向服务器发送消息,我在解码的地方打印日志,发现4-5s之后才能收到客户端请求。第二次发送请求速度就很快了,没有这种现象了

建立连接后,第一次发送消息比较慢 by 田 艾特

建立连接后,客户端向服务器发送消息,我在解码的地方打印日志,发现4-5s之后才能收到客户端请求。第二次发送请求速度就很快了,没有这种现象了

建立连接后,第一次发送消息比较慢 by 田 艾特

建立连接后,客户端向服务器发送消息,我在解码的地方打印日志,发现4-5s之后才能收到客户端请求。第二次发送请求速度就很快了,没有这种现象了

建立连接后,第一次发送消息比较慢 by 田 艾特

建立连接后,客户端向服务器发送消息,我在解码的地方打印日志,发现4-5s之后才能收到客户端请求。第二次发送请求速度就很快了,没有这种现象了

建立连接后,第一次发送消息比较慢 by 田 艾特

建立连接后,客户端向服务器发送消息,我在解码的地方打印日志,发现4-5s之后才能收到客户端请求。第二次发送请求速度就很快了,没有这种现象了

建立连接后,第一次发送消息比较慢 by 田 艾特

建立连接后,客户端向服务器发送消息,我在解码的地方打印日志,发现4-5s之后才能收到客户端请求。第二次发送请求速度就很快了,没有这种现象了

建立连接后,第一次发送消息比较慢 by 田 艾特

建立连接后,客户端向服务器发送消息,我在解码的地方打印日志,发现4-5s之后才能收到客户端请求。第二次发送请求速度就很快了,没有这种现象了

Re: 对于“Reactor主从多线程模型”不太理解 by 王 王

会不会存在Acceptor线程挂掉的情况?

Re: 建立连接后,第一次发送消息比较慢 by 李 夏

是不是域名解析比较慢啊,可以telnet然后用traceroute等工具看下

Re: Good by 李 夏

楼主。我想问下,CompositeByteBuf并不像api说明的那样, CompositeByteBuf compositeBuf = Unpooled.compositeBuffer();
compositeBuf.addComponents(Unpooled.copiedBuffer("ab".getBytes()), Unpooled.copiedBuffer("ab".getBytes()));
System.err.println("readables: " + compositeBuf.readableBytes());
如此简单的测试,可读字节数目竟然为0,这让人无法理解。

夜行侠老师的netty源码分析视频 by liu yaolin

可以直接观看大象在线分享,夜行侠老师的netty源码分析视频
1、netty源码剖析简介
2、Netty服务器的构建
3、Netty客户端的构建
4、Netty客户端短连接实现接服务器收响应数据
5、Netty线程模型
6、Netty ServerBootstrap启动的详细过程类图分析
7、NioEventLoop如何开启和处理channel的Accept事件
8、NioEventLoop接收客户端请求过程
9、NioEventLoop接收channel read事件剖析
10、读半包处理分析
11、如何write数据
12、异步多线程同时write数据处理分析
13、write数据时细节分析,并发问题处理
14、写半包处理详细过程分析
15、NioEventLoop源码详细剖析
16、netty内存管理整个流程分析
17、Netty内存管理 PoolChunk设计思路
18、Netty内存管理中位移与或操作
19、Netty内存管理PoolSubpage剖析
20、Netty内存管理PoolArena,PoolChunkList剖析
21、Netty在读写过程中,内存池PooledByteBufAllocator分配内存详细过程剖析
22、Netty Tcp参数,修改Linux配置提高并发讲解
23、Netty与spring整合
24、Netty完成一套类似SpringMVC RPC架构
27:Netty客户端长连接Netty服务器时分析如何异步获取响应数据
28:Netty客户端长连接实战
29:Netty客户端长连接获取服务器响应数据
30:Netty客户端问题解决与设计优化
31:NettyHttp服务器实现
32:NettyHttp客户端实现
33:NettyHttps服务器实现
34:Netty源码分析总结下期预告
www.itjoin.org/course/detail/58096d240cf2f99b7e...

Re: 对于“Reactor主从多线程模型”不太理解 by Rocky Peng

那可以这样理解么:

reactor多线程模型和主从reactor多线程模型都只有一个线程池。

在多线程模型中,acceptor线程会负责socket的接入,以及一些认证的计算工作(这个工作有没有其实是根据业务觉得的),然后那个线程池负责其他所有的io读写。

在主从多线程模型下,acceptor线程只会负责socket的接入,而把多线程模型下做的其他工作也交给线程池完成?

可以像上面这样理解么?

Netty物联网高并发系统第一季 by 刘 耀林

Netty物联网高并发系统第一季
www.itjoin.org/course/detail/5945adcc0cf2dfcdd9...

第1集netty物联网介绍
第2集netty服务器编写
第3集netty客户端与服务器通信
第4集编码解码
第5集netty服务器架构上
第6集netty服务器架构下
第7集netty客户端架构
第8集netty客户端长连接架构

Netty物联网高并发系统第二季
第9集netty服务器管理链路
第10集mybatis整合
第11集物联网信息交换
第12集网络异常情况处理
第13集netty服务端框架优化
第14集netty客户端加上动态代理
第15集在高并发情况下netty内部处理机制
第16集分析netty源码启动过程
第17集课程总结与下期预告

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

51 讨论

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT