Netty In Action中文版 – 第十六章:从EventLoop取消注册和重新注册

释放双眼,带上耳机,听听看~!

Netty In Action中文版 – 第十六章:从EventLoop取消注册和重新注册

Netty In Action中文版 - 第十六章:从EventLoop取消注册和重新注册

本章介绍

  • EventLoop
  • 从EventLoop注册和取消注册
  • 在Netty中使用旧的Socket和Channel

Netty提供了一个简单的方法来连接Socket/Channel,这是在Netty之外创建并转移他们的责任到Netty。这允许你将遗留的集成框架以无缝方式一步一步迁移到Netty;Netty还允许取消注册的通道来停止处理IO,这可以暂停程序处理并释放资源。

这些功能在某些情况或某种程度上可能不是非常有用,但使用这些特性可以解决一些困难的问题。举个例子,有一个非常受欢迎的社交网络,其用户增长非常快,系统程序需要处理每秒几千个交互或消息,如果用户持续增长,系统将会处理每秒数以万计的交互;这很令人兴奋,但随着用户数的增长,系统将消耗大量的内存和CPU而导致性能低下;此时最需要做的就是改进他们,并且不要花太多的钱在硬件设备上。这种情况下,系统必须保持功能正常能处理日益增长的数据量,此时,注册/注销事件循环就派上用场了。

通过允许外部Socket/Channel来注册和注销,Netty能够以这样的方式改进旧系统的缺陷,所有的Netty程序都可以通过一种有效精巧的方式整合到现有系统,本章将重点讲解Netty是如何整合。

16.1 注册和取消注册的Channel和Socket

        前面章节讲过,每个通道需要注册到一个EventLoop来处理IO或事件,这是在引导过程中自动完成。下图显示了他们的关系:

        上图只是显示了他们关系的一部分,通道关闭时,还需要将注册到EventLoop中的Socket/Channel注销以释放资源。

        有时不得不处理java.nio.channels.SocketChannel或其他java.nio.channes.Channel实现,这可能是遗留程序或框架的一些原因所致。我们可以使用Netty来包装预先创建的java.nio.channels.Channel,然后再注册到EventLoop。我们可以使用Netty的所有特性,同时还能重用现有的东西。下面代码显示了此功能:

[java] view plain
copy

  1. //nio
  2. java.nio.channels.SocketChannel mySocket = java.nio.channels.SocketChannel.open();
  3. //netty
  4. SocketChannel ch = 

new NioSocketChannel(mySocket);

  1. EventLoopGroup group = 

new NioEventLoopGroup();

  1. //register channel
  2. ChannelFuture registerFuture = group.register(ch);
  3. //de-register channel
  4. ChannelFuture deregisterFuture = ch.deregister();

Netty也适用于包装OIO,看下面代码:

[java] view plain
copy

  1. //oio
  2. Socket mySocket = 

new Socket(
"www.baidu.com", 
80);

  1. //netty
  2. SocketChannel ch = 

new OioSocketChannel(mySocket);

  1. EventLoopGroup group = 

new OioEventLoopGroup();

  1. //register channel
  2. ChannelFuture registerFuture = group.register(ch);
  3. //de-register channel
  4. ChannelFuture deregisterFuture = ch.deregister();

只有2个重点如下:

  1. 使用Netty包装已创建的Socket或Channel必须使用与之对应的实现,如Socket是OIO,则使用Netty的OioSocketChannel;SocketChannel是NIO,则使用NioSocketChannel。
  2. EventLoop.register(…)和Channel.deregister(…)都是非阻塞异步的,也就是说它们可能不会理解执行完成,可能稍后完成。它们返回ChannelFuture,我们在需要进一步操作或确认完成操作时可以添加一个ChannelFutureLister或在ChannelFuture上同步等待至完成;选择哪一种方式看实际需求,一般建议使用ChannelFutureLister,应避免阻塞。

16.2 挂起IO处理

在一些情况下可能需要停止一个指定通道的处理操作,比如程序耗尽内存、崩溃、失去一些消息,此时,我们可以停止处理事件的通道来清理系统资源,以保持程序稳定继续处理后续消息。若这样做,最好的方式就是从EventLoop取消注册的通道,这可以有效阻止通道再处理任何事件。若需要被取消的通道再次处理事件,则只需要将该通道重新注册到EventLooop即可。看下图:

看下面代码:

[java] view plain
copy

  1. EventLoopGroup group = 

new NioEventLoopGroup();

  1. Bootstrap bootstrap = 

new Bootstrap();

  1. bootstrap.group(group).channel(NioSocketChannel.

class)

  1.         .handler(

new SimpleChannelInboundHandler<ByteBuf>() {

  1.             

@Override

  1.             

protected 
void channelRead0(ChannelHandlerContext ctx,

  1.                     ByteBuf msg) 

throws Exception {

  1.                 

//remove this ChannelHandler and de-register

  1.                 ctx.pipeline().remove(

this);

  1.                 ctx.deregister();
  2.             }
  3.         });
  4. ChannelFuture future = bootstrap.connect(
  5.         

new InetSocketAddress(
"www.baidu.com", 
80)).sync();

  1. //….
  2. Channel channel = future.channel();
  3. //re-register channel and add ChannelFutureLister
  4. group.register(channel).addListener(

new ChannelFutureListener() {

  1.     

@Override

  1.     

public 
void operationComplete(ChannelFuture future) 
throws Exception {

  1.         

if(future.isSuccess()){

  1.             System.out.println(

"Channel registered");

  1.         }

else{

  1.             System.out.println(

"register channel on EventLoop fail");

  1.             future.cause().printStackTrace();
  2.         }
  3.     }
  4. });

16.3 迁移通道到另一个事件循环

另一个取消注册和注册一个Channel的用例是将一个活跃的Channel移到另一个EventLoop,有下面一些原因可能导致需要这么做:

  • 当前EventLoop太忙碌,需要将Channel移到一个不是很忙碌的EventLoop;
  • 终止EventLoop释放资源同时保持活跃Channel可以继续使用;
  • 迁移Channel到一个执行级别较低的非关键业务的EventLoop中。

下图显示迁移Channel到另一个EventLoop:

看下面代码:

[java] view plain
copy

  1. EventLoopGroup group = 

new NioEventLoopGroup();
1.
final EventLoopGroup group2 = 
new NioEventLoopGroup();

  1. Bootstrap b = 

new Bootstrap();

  1. b.group(group).channel(NioSocketChannel.

class)

  1.         .handler(

new SimpleChannelInboundHandler<ByteBuf>() {

  1.             

@Override

  1.             

protected 
void channelRead0(ChannelHandlerContext ctx,

  1.                     ByteBuf msg) 

throws Exception {

  1.                 

// remove this channel handler and de-register

  1.                 ctx.pipeline().remove(

this);

  1.                 ChannelFuture f = ctx.deregister();
  2.                 

// add ChannelFutureListener

  1.                 f.addListener(

new ChannelFutureListener() {

  1.                     

@Override

  1.                     

public 
void operationComplete(ChannelFuture future)

  1.                             

throws Exception {

  1.                         

// migrate this handler register to group2

  1.                         group2.register(future.channel());
  2.                     }
  3.                 });
  4.             }
  5.         });
  6. ChannelFuture future = b.connect(

"www.baidu.com", 
80);

  1. future.addListener(

new ChannelFutureListener() {

  1.     

@Override

  1.     

public 
void operationComplete(ChannelFuture future)

  1.             

throws Exception {

  1.         

if (future.isSuccess()) {

  1.             System.out.println(

"connection established");

  1.         } 

else {

  1.             System.out.println(

"connection attempt failed");

  1.             future.cause().printStackTrace();
  2.         }
  3.     }
  4. });

16.4 Summary

至此,netty in action中文版系列博文已完成了,一次不经意的baidu,发现在51cto上都出现本系列博客的pdf文件了,下载下来一看发现和本系列内容一模一样,呵呵 ,看来netty中文资料的需求还是有一些的。

原文地址http://www.bieryun.com/2205.html

给TA打赏
共{{data.count}}人
人已打赏
安全技术

bootstrap栅格系统自定义列

2021-12-21 16:36:11

安全技术

从零搭建自己的SpringBoot后台框架(二十三)

2022-1-12 12:36:11

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索