• 4-网络架构和Netty系列-网络线程模型与核心概念


    网络模型*

    Netty 是典型的 Reactor 模型结构,关于 Reactor 的详尽阐释,可参考 POSA2 ,这里不做概念性的解释。而应用 Java NIO 构建 Reactor 模式,Doug Lea在 “Scalable IO in Java” 中给了很好的阐述。这里截取其 PPT 中经典的图例说明 Reactor 模式的典型实现:

    Reactor 线程模型

    Reactor 是反应堆的意思,Reactor 模型是指通过一个或多个输入同时传递给服务处理器的服务请求的事件驱动处理模式。

    服务端程序处理传入多路请求,并将它们同步分派给请求对应的处理线程,Reactor 模式也叫 Dispatcher 模式,即 I/O 多了复用统一监听事件,收到事件后分发(Dispatch 给某进程),是编写高性能网络服务器的必备技术之一。

    Reactor 模型中有 2 个关键组成:

    • Reactor,Reactor 在一个单独的线程中运行,负责监听和分发事件,分发给适当的处理程序来对 IO 事件做出反应。它就像公司的电话接线员,它接听来自客户的电话并将线路转移到适当的联系人。
    • Handlers,处理程序执行 I/O 事件要完成的实际事件,类似于客户想要与之交谈的公司中的实际官员。Reactor 通过调度适当的处理程序来响应 I/O 事件,处理程序执行非阻塞操作。

    在这里插入图片描述

    单 Reactor 单线程模型。

    Reactor 线程是个多面手,负责多路分离套接字,Accept 新连接,并分派请求到处理器链中。该模型 适用于处理器链中业务处理组件能快速完成的场景。不过,这种单线程模型不能充分利用多核资源,所以实际使用的不多。

    单 Reactor 多线程(线程池)模型

    主从 Rreactor 多线程模型

    特别说明的是:虽然 Netty 的线程模型基于主从 Reactor 多线程,借用了 MainReactor 和 SubReactor 的结构。但是实际实现上 SubReactor 和 Worker 线程在同一个线程池中:

    EventLoopGroup bossGroup = newNioEventLoopGroup();

    EventLoopGroup workerGroup = newNioEventLoopGroup();

    ServerBootstrap server= newServerBootstrap();

    server.group(bossGroup, workerGroup)

    .channel(NioServerSocketChannel. class)

    上面代码中的 bossGroup 和 workerGroup 是 Bootstrap 构造方法中传入的两个对象,这两个 group 均是线程池:

    • bossGroup 线程池则只是在 Bind 某个端口后,获得其中一个线程作为 MainReactor,专门处理端口的 Accept 事件,每个端口对应一个 Boss 线程。
    • workerGroup 线程池会被各个 SubReactor 和 Worker 线程充分利用。

    异步处理

    异步的概念和同步相对。当一个异步过程调用发出后,调用者不能立刻得到结果。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。

    Netty 中的 I/O 操作是异步的,包括 Bind、Write、Connect 等操作会简单的返回一个 ChannelFuture。

    调用者并不能立刻获得结果,而是通过 Future-Listener 机制,用户可以方便的主动获取或者通过通知机制获得 IO 操作结果。

    当 Future 对象刚刚创建时,处于非完成状态,调用者可以通过返回的 ChannelFuture 来获取操作执行的状态,注册监听函数来执行完成后的操作。

    常见有如下操作:

    • 通过 isDone 方法来判断当前操作是否完成。
    • 通过 isSuccess 方法来判断已完成的当前操作是否成功。
    • 通过 getCause 方法来获取已完成的当前操作失败的原因。
    • 通过 isCancelled 方法来判断已完成的当前操作是否被取消。
    • 通过 addListener 方法来注册监听器,当操作已完成(isDone 方法返回完成),将会通知指定的监听器;如果 Future 对象已完成,则理解通知指定的监听器。

    例如下面的代码中绑定端口是异步操作,当绑定操作处理完,将会调用相应的监听器处理逻辑。

    serverBootstrap.bind(port).addListener(future -> {
      if(future.isSuccess()) {
      System.out. println( newDate() + ": 端口["+ port + "]绑定成功!");
      } else{
      System.err. println( "端口["+ port + "]绑定失败!");
      }
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    相比传统阻塞 I/O,执行 I/O 操作后线程会被阻塞住, 直到操作完成;异步处理的好处是不会造成线程阻塞,线程在 I/O 操作期间可以执行别的程序,在高并发情形下会更稳定和更高的吞吐量。

    Netty 中的核心概念

    Channel
    管道,其是对 Socket 的封装,其包含了一组 API,大大简化了直接与 Socket 进行操作的
    复杂性。
    EventLoopGroup
    EventLoopGroup 是一个 EventLoop 池,包含很多的 EventLoop。
    Netty 为每个 Channel 分配了一个 EventLoop,用于处理用户连接请求、对用户请求的处 理等所有事件。EventLoop 本身只是一个线程驱动,在其生命周期内只会绑定一个线程,让 该线程处理一个 Channel 的所有 IO 事件。
    一个 Channel 一旦与一个 EventLoop 相绑定,那么在 Channel 的整个生命周期内是不能 改变的。一个 EventLoop 可以与多个 Channel 绑定。即 Channel 与 EventLoop 的关系是 n:1, 而 EventLoop 与线程的关系是 1:1。
    ServerBootStrap
    用于配置整个 Netty 代码,将各个组件关联起来。服务端使用的是 ServerBootStrap,而
    客户端使用的是则 BootStrap。
    ChannelHandler 与 ChannelPipeline
    ChannelHandler 是对 Channel 中数据的处理器,这些处理器可以是系统本身定义好的编 解码器,也可以是用户自定义的。这些处理器会被统一添加到一个 ChannelPipeline 的对象中, 然后按照添加的顺序对 Channel 中的数据进行依次处理。
    ChannelFuture
    Netty 中所有的 I/O 操作都是异步的,即操作不会立即得到返回结果,所以 Netty 中定义 了一个 ChannelFuture 对象作为这个异步操作的“代言人”,表示异步操作本身。如果想获取 到该异步操作的返回值,可以通过该异步操作对象的 addListener()方法为该异步操作添加监听器,为其注册回调:当结果出来后马上调用执行。
    Netty 的异步编程模型都是建立在 Future 与回调概念之上的。

  • 相关阅读:
    Java和JavaScript区别与联系
    Windows11重置提示找不到恢复环境怎么解决?
    【小程序项目开发-- 京东商城】uni-app之分类导航区域
    iOS开发基础102-后台保活方案
    SAP UI5 ManagedObject 的 Event 讲解
    IDEA中如何使用debug调试项目 一步一步详细教程
    springboot医疗管理系统毕业设计源码015221
    设计一个基于 GraphQL 的 Node.js 工单系统
    液位检测仪在线监测系统解决方案
    WZOI-354找子串
  • 原文地址:https://blog.csdn.net/xianghanscce/article/details/125631921