netty指南及进阶
Netty是一个高性能的,提供异步的、事件驱动,非堵塞的IO(NIO)框架,用以快速开发高性能、高可靠性的网络服务器和客户端dsf。用于建立TCP等底层的连接,基于Netty可以建立高性能的Http服务器。
堵塞与非堵塞原理
传统硬件的堵塞如下,从内存中读取数据,然后写到磁盘,而CPU一直等到磁盘写完成,磁盘的写操作是慢的,这段时间CPU被堵塞不能发挥效率。
图一、
使用非堵塞的DMA如下图:CPU只是发出写操作这样的指令,做一些初始化工作,DMA具体执行,从内存中读取数据,然后写到磁盘,当完成写后发出一个中断事件给CPU。这段时间CPU是空闲的,可以做别的事情。这个原理称为Zero.copy零拷贝。
图二、
Netty底层基于上述Java NIO的零拷贝原理实现:
图三、
比较:
- Tomcat是一个Web服务器,它是采取一个请求一个线程,当有1000客户端时,会耗费很多内存。通常一个线程将花费 256kb到1mb的stack空间。
- Node.js是一个线程服务于所有请求,在错误处理上有限制
- Netty是一个线程服务于很多请求,如下图,当从Java NIO获得一个Selector事件,将激活通道Channel。
通常一个netty程序,包含一个客户端和服务端,客户端发送请求道服务端,服务端通过UpStream接受数据,然后激活服务端逻辑和handler(一般继承类ChannelInboundHandler),而服务器向外写数据,也就是响应是通过DownStream实现的。每个通道channel包含一个upstream和一个downstream还有一个handler。这些内容都是通过channelPipeline封装起来的。数据在管道里流动,每个socket对应一个channelpipeline。
图四、netty工作原理
图五、Netty 在事件处理上,是通过ChannelPipeline来控制事件流,通过调用注册其上的一系列ChannelHandler来处理事件,这也是典型的拦截 器模式。
netty核心功能
· netty具有丰富的缓存实现,netty有自建的buffer API--byteBuf,特性:
1、允许自定义的缓冲类型
2、 复合缓冲类型中内置的透明的零拷贝实现(图一)
3、动态缓冲类型,类似于stringBuffer
4、响应效果比byteBuffer更快
接下来注意说一下其优点的实际应用。
透明的零拷贝:举一个网络应用到极致的例子,目前需要减少内存拷贝的次数。这里有一组复合缓冲区可以组合成一个完整的消息。网络提供了一个复合缓冲,可以从现有的任意数的缓冲区创建一个新的缓冲而没有内存拷贝。比如一个请求头request,包含header和body两部分。如果使用jdk中的byteBuffer,你必须要创建一个新的大缓冲区来拷贝这两部分数据到这个新缓冲区。
//复合类型与组件类型不兼容
ByteBuffer[] by = new ByteBuffer[]{header,body};
ByteBuf不会有警告,因为他是完全可扩展并有一个内置的复合缓冲区
//复合类型与组件类型是兼容的
ByteBuf message = Unpooled.wrappedBuffer(header,body);
由于复合类型仍是byteBuf,访问其对象很容易,并且方法方法的行为就像访问一个单独的缓冲区,
自动容量扩充:许多协议定义可变长度的消息,这意味着没有办法确定消息的长度,直到你构建消息。一种新的动态缓冲区被创建。在内部,实际缓冲区是被懒创建,从而避免潜在的内存空间浪费
ByteBuf bb = Unpooled.buffer(2);如果字符长度超过定义的长度会自动扩容。