简介
Netty为什么这么优良,它在JDK自身的NIO根底上又做了什么改良呢?它的架构和工作流程如何呢?请走进明天的netty系列文章之:netty架构概述。
netty架构图
netty的次要作用就是提供一个简略的NIO框架能够和下层的各种协定相结合,最终实现高性能的服务器。上面是netty官网提供的架构图:
从上图能够看到netty的外围次要分成三局部,别离是可扩大的event model、对立的API、和弱小的Byte Buffer。这三个个性是netty的制胜法宝。
上面会从这几个方面对netty的个性进行具体阐明,务必让读者理解到netty的优良之处。
丰盛的Buffer数据机构
首先从最底层的Buffer数据结构开始,netty提供了一个io.netty.buffer的包,该包外面定义了各种类型的ByteBuf和其衍生的类型。
netty Buffer的根底是ByteBuf类,这是一个抽象类,其余的Buffer类基本上都是由该类衍生而得的,这个类也定义了netty整体Buffer的基调。
netty重写ByteBuf其目标是让最底层的ByteBuf比JDK自带的更快更适宜扩大。具体而言,netty的ByteBuf要比JDK中的ByteBuffer要快,同时,扩大也更加容易,大家能够依据须要Buf进行自定义。另外netty有一些内置的复合缓冲区类型,所以能够实现通明的零拷贝。对于动静缓冲区类型来说,能够和StringBuffer一样按需扩大,十分好用。
零拷贝
什么是零拷贝呢?零拷贝的意思是在须要拷贝的时候不做拷贝。咱们晓得数据在应用底层协定进行传输的过程中是会被封装成为一个个的包进行传输。当传输的数据过大,一个包放不下的时候,还须要对数据进行拆分,目标方在接管到数据之后,须要对收到的数据进行组装,个别状况下这个组装的操作是对数据的拷贝,将拆分过后的对象拷贝到一个长的数据空间中。
比方上面的例子所示,将底层的TCP包组合称为顶层的HTTP包,然而并没有进行拷贝:
具体怎么拷贝呢?在上一篇文章中,咱们晓得netty提供了一个工具类办法Unpooled,这个工具类中有很多wrapped结尾的办法,咱们举几个例子:
public static ByteBuf wrappedBuffer(byte[]... arrays) { return wrappedBuffer(arrays.length, arrays); }public static ByteBuf wrappedBuffer(ByteBuf... buffers) { return wrappedBuffer(buffers.length, buffers); }public static ByteBuf wrappedBuffer(ByteBuffer... buffers) { return wrappedBuffer(buffers.length, buffers); }
下面三个办法别离是封装byte数组、封装ByteBuf和封装ByteBuffer,这些办法都是零拷贝。大家能够在理论的我的项目中依据理论状况,自行选用。
对立的API
一般来说,在传统的JDK的IO API中,依据传输类型或者协定的不同,应用的API也是不同的。咱们须要对不同的传输方式开发不同的应用程序,不能做到对立。这样的后果就是无奈平滑的迁徙,并且在程序扩大的时候须要进行额定的解决。
什么是传输方式呢?这里是指以什么样的形式来实现IO,比方传统的阻塞型IO,咱们能够称之为OIO,java的new IO能够称之为NIO,异步IO能够称之为AIO等等。
并且JDK中的传统IO和NIO是割裂的,如果在最开始你应用的是传统IO,那么当你的客户数目增长到肯定的水平筹备切换到NIO的时候,就会发现切换起来异样简单,因为他们是割裂的。
为了解决这个问题,netty提供了一个对立的类Channel来提供对立的API。
先看下Channel中定义的办法:
从上图咱们能够看到应用Channel能够判断channel以后的状态,能够对其进行参数配置,能够对其进行I/O操作,还有和channel相干的ChannelPipeline用来解决channel关联的IO申请和事件。
应用Channel就能够对NIO的TCP/IP,OIO的TCP/IP,OIO的UDP/IP和本地传输都能提供很好的反对。
传输方式的切换,只须要进行很小的老本替换。
当然,如果你对现有的实现都不称心的话,还能够对外围API进行自定义扩大。
事件驱动
netty是一个事件驱动的框架,事件驱动框架的根底就是事件模型,Netty专门为IO定义了一个十分无效的事件模型。能够在不毁坏现有代码的状况下实现本人的事件类型。netty中自定义的事件类型通过严格的类型层次结构跟其余事件类型辨别开来,所以可扩展性很强。
netty中的事件驱动是由ChannelEvent、ChannelHandler和ChannelPipeline独特作用的后果。其中ChannelEvent示意产生的事件,ChannelHandler定义了如何对事件进行解决,而ChannelPipeline相似一个拦截器,能够让用户自行对定义好的ChannelHandler进行管制,从而达到管制事件处理的后果。
咱们看一个简略的自定义Handler:
public class MyHandler extends SimpleChannelInboundHandler<Object> { @Override public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception { // 对音讯进行解决 ByteBuf in = (ByteBuf) msg; try { log.info("收到音讯:{}",in.toString(io.netty.util.CharsetUtil.US_ASCII)); }finally { ReferenceCountUtil.release(msg); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { //异样解决 cause.printStackTrace(); ctx.close(); }}
下面的例子中,咱们定义了如何对接管到的音讯和异样进行解决。在后续的文章中咱们会具体对ChannelEvent、ChannelHandler和ChannelPipeline之间的交互应用进行介绍。
其余优良的个性
除了下面提到的三大外围个性之外,netty还有其余几个长处,不便程序员的开发工作。
比方对SSL / TLS的反对,对HTTP协定的实现,对WebSockets 实现和Google Protocol Buffers的实现等等,表明netty在各个方面多个场景都有很强的利用能力。
总结
netty是由三个外围组件形成:缓冲区、通道和事件模型,通过了解这三个外围组件是如何互相工作的,那么再去了解建设在netty之上的高级性能就不难了。
本文的例子能够参考:learn-netty4
本文已收录于 http://www.flydean.com/03-netty-architecture/
最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!
欢送关注我的公众号:「程序那些事」,懂技术,更懂你!