从NIO到netty(13)Netty的架构设计和开发中的几个注意点

56 篇文章 2 订阅

之前把netty启动时的几大模块都分析完了,下面就Netty的架构设计做一个总结

1、一个EventLoopGroup当中会包含一个或多个EventLoop。
2、一个EventLoop在它的整个生命周期当中都只会与唯一一个Thread进行绑定。
3、所有由EventLoop所处理的各种I/O事件都将在它所关联的那个Thread上进行处理。
4、一个Channel在它的整个生命周期中只会注册在一个EventLoop上。
5、一个EventLoop在运行过程中,会被分配给一个或多个Channel。
6、同一个Channel提交的任务执行顺序和提交顺序是一样的(先进去的先出来,任务队列)

重要结论:在netty的实现当中一定是线程安全的,基于此我们可以存储存储一个channel的引用,并且在需要向远程端点发送数据时,通过这个引用来调用Channel相应的方法;即便当时有很多线程在使用它也不会出现多线程问题,而且消息一定会按照顺序发送出去。

重要结论:我们在业务开发中,不要将长时间执行的耗时任务放入到EventLoop的执行队列中,因为它将会一直阻塞该线程所对应的所有Channel上的其他执行任务,如果我们需要进行阻塞调用或是耗时的操作(实际开发中很常见),那么我们就需要使用一个专门的EventExecutor(业务线程池)。
通常会有2种实现方式: 
1、在ChannelHandler的回调方法中,使用自己定义的业务线程池,这样就可以实现异步调用。 

protected void channelRead0(ChannelHandlerContext ctx, String s) {
    new Thread(()->{
        for (int i =0;i<100000;i++){
            Thread.sleep(10000L);
        }
    }).start();
    
    ctx.writeAndFlush("收到请求");
}

2、借助于netty提供的向ChannelPipeLine添加ChannelHandler时调用的addLast方法来传递EventExecutor。 
说明:默认情况下(调用addLast(handler)),ChannelHandler中的回调方法都是由I/O线程所执行,如果调用了ChannelPipeline addLast(EventExecutorGroup group, ChannelHandler… handlers);方法,那么ChannelHandler中的回调方法就是由参数中的group线程组来执行。

ChannelPipeline addLast(EventExecutorGroup group, ChannelHandler... handlers);

----------------------------------------

下面说几个知识点

1.ChannelFutureListener的operationcomplete方法是由I/O线程执行的,因此要注意的是不要再这里执行耗时操作,否则需要需要通过另外的线程或线程池来执行。 

2.ChannelPromise

ChannelPromise继承了Promise 接口,而Promise是可以写的(writable),什么是可以写的,之前的Future都是get,isSuccess之类的方法,在ChannelPromise里边可以看到setSuccess(Void result)【setSuccess只能写一次,下一次写报错】之类的写方法。ChannelPromise字面意思是承诺的意思,不管是成功还是失败会承诺给你一个结果。

3.netty有两种发送请求的方法,一种是是获取到channel,调用channel的writeAndFlush方法,另一种是直接在ChannelHandlerContext调用writeAndFlush,这两种方法有一定区别

对于前一种方式来说,消息会从ChannelPipeline的末尾开始流动,对于后一种方式来说,消息将从ChannelPipleline中的下一个ChannelG、Handler开始流动。

用一张图来描述

è¿éåå¾çæè¿° 

@Override
protected void channelRead0(ChannelHandlerContext ctx, String s) {
   ctx.channel().writeAndFlush("收到请求");
    ctx.writeAndFlush("收到请求");
}

所以我们可以得出这样的结论:

1、ChannelHandlerContext与ChannelHandler之间的关联绑定关系永远是不会绑定的,因此缓存是没问题的

2、相比于与Channel同名的方法来说,ChannelHandlerContext方法将会产生更短的事件流,所以我们应该经可能利用这个特性来提升性能。

4.在netty中Nio和OIO是通用一套变成模型的,如果我们想在netty程序中使用传统I/O模型,那么只需要将

serverBootstrap = serverBootstrap.group(bossgroup,worker).channel(NioServerSocketChannel.class);中的

NioServerSocketChannel改成OioServerSocketChannel就可以了。

为什么netty可以把底层完全不同的两种编程模型抽象成一种变成模型呢?

在Nio中调用完毕后直接返回

而Oio中可以用下面的伪代码来说明

While(true)

try{

 ….OIO synchronized

   Break;

   }

catch(SocketTimeoutExcepion e){

    continue

}

è¿éåå¾çæè¿°用一张图来表示在netty框架下nio和oio是怎么抽象成同一种模型的

5.一段代码如何既是客户端又是服务器端,比如

è¿éåå¾çæè¿°

 

连接客户端的channel和连接服务器端的channel共用一个eventLoop

 

public void channelActive(ChannelHandlerContext ctx){

    Bootstrap bootstrap =….

   Bootstrap.channel(NioSocketChannel.class).handler(

   ……

 

    Bootstrap.group(ctx.channel().eventLoop());

Bootstrap.connect()

)

}

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值