Netty搬运工 EventLoop与Bootstrap

Posted nullPoint水

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Netty搬运工 EventLoop与Bootstrap相关的知识,希望对你有一定的参考价值。

EventLoop

         Netty4中,所有的IO操作和事件都由已经分配给了EventLoopThread处理。EventLoop线程主要需要处理IO事件、定时任务和一般任务。Netty提供可一个参数ioRatio用于调整单线程对于IO处理事件和任务处理事件的分配比率。这样尽管一个EventLoop会关联多个Channel,这些Channel在单个线程下并不会出现并发问题,同时对于异步任务的处理也一样,Netty这样设计即免去了并发问题的烦恼,有减少了多线程上下文切换带来的性能损耗,同时基于EventLoopGroup实现的有限的线程数能够充分利用CPU处理能力。

         NettyEventLoop扩展了ScheduledExecutorService,所以它提供了JDK实现可用的所有方法,包括schedule()scheduleAtFixedRate()方法。以下为EventLoop的继承关系类图

Netty线程模型的性能优越取决于对于当前执行的Thread的身份的确定。如果当前调用线程正式支撑EventLoop的线程,那么所提交的代码块将被直接执行。否则EventLoop将它放入到内部队列中,以便稍后执行。当EventLoop下次处理事件时将会处理队列中的任务。每个EventLoop都有他自己的任务队列,独立于任何其他的EventLoop

EventLoop与线程的分配

异步传输

         异步传输实现只使用了少量的EventLoop以及和他们相关联的Thread,而且在当前的线程模型中,他们可能会被多个Channel共享。

         EventLoopGroup负责为每个新创建的Channel分配一个EventLoop。使用顺序循环的方式进行分配以获取一个均衡的分布,相同的EventLoop可能会被分配给多个Channel。一旦一个Channel被分配给一个EventLoop,它的整个生命周期都将使用这个EventLoop

Netty搬运工(3) EventLoop与Bootstrap

阻塞传输

         阻塞传输每一个Channel都将被分配给一个EventLoop以及它的Thread。这样每个ChannelIO事件都将只会被一个Thread处理。

Netty搬运工(3) EventLoop与Bootstrap

总结:Netty基于单线程设计的EventLoop能够同时处理成千上万的客户端连接的IO事件,缺点是单线程不能够处理时间过长的任务,这样会阻塞使得IO事件的处理被阻塞,严重的时候回造成IO事件堆积,服务不能够高效响应客户端请求。所谓时间过长的任务通常是占用CPU资源比较长的任务,也即CPU密集型,对于业务应用也可能是业务代码的耗时。

Bootstrap

         之前简单说明了一下ChannelChannelPipelineChannelHandlerEventLoop之后。在使用netty编程时需要Bootstrap来将这些部分组合到一起来工作。

先看一下Bootstrap使用的例子:

EventLoopGroup group = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group).channel(NiosocketChannel.class)
        .option(ChannelOption.
TCP_NODELAY,true)
        .handler(
new ChannelInitializer<SocketChannel>() {
           
@Override
           
protected void initChannel(SocketChannel socketChannel) throws Exception {

            }
        })
;

如果对设计模式有所了解的话,应该可以看出这是Builder模式。

 

引导客户端和无连接协议

         Bootstrap类被用于客户端或者使用了无连接协议的程序中。以下是一些常用方法:

名称

描述

Bootstrap group()

设置处理Channel所有事件的EventLoopGroup

Bootstrap channel()

Bootstrap channelFactory()

channel()方法指定了Channel的实现类。如果该实现类没有提供默认的构造函数,可以通过channelFactory()方法指定工厂类,它会被bind()方法调用

SocketAddress  localAddress()

<T> Bootstrap option()

设置ChannelOption,将被应用到每个新创建的ChannelChannelConfig。这个方法在Channel已经被创建后再调用将不会有效果。

<T>Bootstrap attr()

指定新创建的Channel的属性值。这个方法在Channel已经被创建后再调用将不会有效果。

Bootstrap handler()

设置将被添加到ChannelPipeline以接收事件通知的ChannelHandler

Bootstrap clone()

创建当前Bootstrap的克隆。

Bootstrap remoteAddress()

ChannelFuture connect()

ChannelFuture bind()

绑定Channel并返回一个ChannelFuture,其将会在连接操作完成后收到通知

示例:

EventLoopGroup group = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group).channel(NioSocketChannel.class)
        .handler(
new ChannelInitializer<SocketChannel>() {
           
@Override
           
protected void initChannel(SocketChannel socketChannel) throws Exception {

            }
        })
;
ChannelFuture future = bootstrap.connect(new InetAddress("localhost",80));
future.addListener(new ChannelFutureListener() {
   
@Override
   
public void operationComplete(ChannelFuture channelFuture) throws Exception {
       
if (channelFuture.isSuccess()){}
    }
})
;

需要注意的是:对于NIOOIO来说都有相关的EventLoopGroupChannel实现,不能混用不同前缀的组件。NioEventLoopGroup必须和Nio开头的Channel使用。

对于无连接的协议与基于TCP协议的连接,区别就在于是需要调用bind()方法而不需要调用connect()方法。

引导服务端

         ServerBootstrap类被用于服务端程序中,以下是常用方法。

名称

描述

ServerBootstrap group()

设置ServerBootstrap要用的EventLoopGroup。这个EventLoopGroup将用于ServerChannel和被接受的子ChannelIO处理

ServerBootstrap channel()

设置将要被实例化的ServerChannel

ServerBootstrap channelFactory()

如果不能通过默认的构造函数创建Channel,那么可以提供ChannelFactory

SocketAddress  localAddress()

<T> ServerBootstrap option()

指定要应用到新创建的ServerChannelChannelConfigChannelOption。这些选项将通过bind()方法设置到Channel。在bind()方法被调用之后,设置或者改变ChannelOption都不会有效果。

<T> ServerBootstrap childOption()

指定当子Channel被接受时,应用到子ChannelChannelConfigChannelOption

<T> ServerBootstrap attr()

指定ServerChannel的属性。这些选项将通过bind()方法设置到Channel。在bind()方法被调用之后,设置或者改变ChannelOption都不会有效果。。

<T> ServerBootstrap childAttr()

将属性设置给已经被接受的子Channel。接下来的调用将不会有效果

ServerBootstrap handler()

设置将被添加到ServerChannelChannelPipeline中的ChannelHandler

ServerBootstrap childHandler()

设置将被添加到已被接受的子ChannelChannelPipeline中的ChannelHandlerhandler()childHandler()的区别:前者添加的ChannelHandler由接受子ChannelServerChannel处理,而childHandler()添加的ChannelHandler由已被接受的子Channel处理。

ServerBootstrap clone()

创建当前ServerBootstrap的克隆。

ChannelFuture bind()

绑定ServerChannel并返回一个ChannelFuture,其将会在连接操作完成后收到通知

         ServerChannel的实现负责创建子Channel,这些子Channel代表已被接受的连接。

Channel引导客户端

         通过将已被接受的子ChannelEventLoop传递给Bootstrapgroup()方法来共享该EventLoop。因为分配给EventLoop的所有Channel都使用同一个线程,所以这避免了创建额外的线程以及上下文切换。

         尽可能的重用EventLoop,以减少创建线程带来的开销。

ChannelOption

         在每个Channel创建时都手动配置它的属性太过繁琐。使用option()方法将ChannelOption应用到Bootstrap,所做的配置将被自动应用到Bootstrap所创建的所有的Channel


以上是关于Netty搬运工 EventLoop与Bootstrap的主要内容,如果未能解决你的问题,请参考以下文章

Netty精粹之基于EventLoop机制的高效线程模型

牛了Netty之EventLoop线程

Netty源码EventLoop

Netty入门——组件(EventLoop)

从Netty EventLoop实现上可以学到什么

Netty学习系列-EventLoop