前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >netty(1): IO线程模型的变迁

netty(1): IO线程模型的变迁

作者头像
yiduwangkai
发布2019-09-17 15:52:28
4750
发布2019-09-17 15:52:28
举报
文章被收录于专栏:大数据进阶大数据进阶

jdk 1.4之前所有的socket通信都采用同步阻塞模式(bio),这种一请求一应答的通信模型简化了上层应用的开发,但是在可靠性和性能方面存在巨大的弊端,下图是bio通信模型图

通常由一个独立的Acceptor线程负责监听客户端的连接,接收到客户端连接之后为客户端连接创建一个新的线程处理请求消息,处理完成之后,返回应答消息给客户端,线程销毁。该架构最大的问题是不具备弹性伸缩能力,当并发访问量增加后,服务端的线程个数和并发访问数成线性正比,当线程数剧增后,会引起一系列连锁反应,直至系统崩溃。

代码语言:javascript
复制
//同步阻塞式,单线程处理
public class IOServerSingleThread {
    private static final Logger LOGGER = LoggerFactory.getLogger(IOServer.class);
    public static void main(String[] args) {
        LOGGER.info("nihao");
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket();
            serverSocket.bind(new InetSocketAddress(1234));
            serverSocket.setSoTimeout(0);
        } catch (IOException ex) {
            LOGGER.error("Listen failed", ex);
            return;
        }
        InputStream inputstream = null;
        try{
            while(true) {
                Socket socket = serverSocket.accept();
                inputstream = socket.getInputStream();
                LOGGER.info("Received message {}", IOUtils.toString(inputstream));
                IOUtils.closeQuietly(inputstream);
            }
        } catch(IOException ex) {
            IOUtils.closeQuietly(inputstream);
            LOGGER.error("Read message failed", ex);
        }
    }
}

//同步阻塞多线程处理
public class IOServerMultiThread {
  private static final Logger LOGGER = LoggerFactory.getLogger(IOServerMultiThread.class);
  public static void main(String[] args) {
  ServerSocket serverSocket = null;
    try {
      serverSocket = new ServerSocket();
      serverSocket.bind(new InetSocketAddress(2345));
      serverSocket.setSoTimeout(0);
    } catch (IOException ex) {
      LOGGER.error("Listen failed", ex);
      return;
    }
    try{
      while(true) {
        Socket socket = serverSocket.accept();
        new Thread( () -> {
          try{
            InputStream inputstream = socket.getInputStream();
            LOGGER.info("Received message {}", IOUtils.toString(inputstream));
            IOUtils.closeQuietly(inputstream);
          } catch (IOException ex) {
            LOGGER.error("Read message failed", ex);
          }
        }).start();
      }
    } catch(IOException ex) {
      LOGGER.error("Accept connection failed", ex);
    }
  }
}

由于线程数会随着客户端请求的增加而增加,由此我们进行分析优化,递进出如下的模型:伪异步模型

服务端接收到客户端连接之后,不创建独立的线程,而是将socket连接封装成Task,将Task放入线程池的任务队列中执行,这样可以有效控制线程的规模,防止线程膨胀导致系统的崩溃,还能有效重复利用线程

代码语言:javascript
复制
//伪异步模型
public class IOServerThreadPool {
  private static final Logger LOGGER = LoggerFactory.getLogger(IOServerThreadPool.class);
  public static void main(String[] args) {
    ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
    ServerSocket serverSocket = null;
    try {
      serverSocket = new ServerSocket();
      serverSocket.bind(new InetSocketAddress(2345));
    } catch (IOException ex) {
      LOGGER.error("Listen failed", ex);
      return;
    }
    try{
      while(true) {
        Socket socket = serverSocket.accept();
        executorService.submit(() -> {
          try{
            InputStream inputstream = socket.getInputStream();
            LOGGER.info("Received message {}", IOUtils.toString(new InputStreamReader(inputstream)));
          } catch (IOException ex) {
            LOGGER.error("Read message failed", ex);
          }
        });
      }
    } catch(IOException ex) {
      try {
        serverSocket.close();
      } catch (IOException e) {
      }
      LOGGER.error("Accept connection failed", ex);
    }
  }
}

下面我们来说说actor模型,reactor模型,proactor模型

actor模型是建立在用户态的一种并发模型,实体间的调用,通过消息进行通讯,消息的发送和接收是完全异步的,消息的发送方会将消息发送到一个FIFO队列,消息的接收方会从这个FIFO队列中取出消息,因为是FIFO队列,消息必然有先来后到,先到的消息会被先处理,后到的消息阻塞,每一个任务由以下三个属性:tag:用以区别于系统中的其它任务

target:通信到达的地址

communication:包含在target上的Actor处理任务时可获取的信息

actor的具体模型会在后面的一遍中详细讲解

reactor模型

reactor,即反应堆。reactor的一般工作工作过程是首先在Reactor中注册事件,并在注册时指定某个已定义的回调函数,当客户端发送请求时,在reactor中会触发刚才注册的事件,并调用对应的处理函数。

这是一个reactor模型的简略图,比较通俗化的图形如下

reactor模型中包含三种角色,分别是reactor,acceptor,handler

reactor: 负责派发IO事件给对应的角色处理,为了监听IO事件,select必须实现在reactor中

acceptor: 负责接受client的连线,然后给client绑定一个handler并注册IO事件到reactor上监听

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
弹性伸缩
弹性伸缩(Auto Scaling,AS)为您提供高效管理计算资源的策略。您可设定时间周期性地执行管理策略或创建实时监控策略,来管理 CVM 实例数量,并完成对实例的环境部署,保证业务平稳顺利运行。在需求高峰时,弹性伸缩自动增加 CVM 实例数量,以保证性能不受影响;当需求较低时,则会减少 CVM 实例数量以降低成本。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档