• 高并发编程thirft源码解析之Selector


    Selector作用

    关于套接字编程,有一套经典的IO模型需要提前介绍一下:.

    同步IO模型:

    阻塞式IO模型

    非阻塞式IO模型

    IO复用模型   使用selector

    信号驱动式IO模型

    异步IO模型

    使用aio_read

    thrift里面用到IO模型就是IO复用模型,《Unix网络编程》一书中说它是同步IO模型,selector用法是阻塞的。

    实际上selector模型中的套接字可以通过如下方式设定位非阻塞方式。

    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
    serverSocketChannel.configureBlocking(false);

    Selector就是一个事件选择器。是个操作系统内核实现的套接字连接选择器。

    早期的linux系统是用poll模式,新的模式是epoll。

    目前用C开发套接字编程仍然可以使用这两种方式。

    而用JDK开发套接字编程时,linux JDK默认使用epoll作为selector的事件触发机制。

    Thrift是如何使用Selector

    thirft里面使用了两个Selector,一个是监听socket连接是否进来

    另外一个是监听socketChanell是否可读或者可写。

    第一处TThreadedSelectorServer.AcceptThread

    /**
         * Select and process IO events appropriately: If there are connections to
         * be accepted, accept them.
         */
        private void select() {
          try {
            // wait for connect events.
            acceptSelector.select();
    
            // process the io events we received
            Iterator<SelectionKey> selectedKeys = acceptSelector.selectedKeys().iterator();
            while (!stopped_ && selectedKeys.hasNext()) {
              SelectionKey key = selectedKeys.next();
              selectedKeys.remove();
    
              // skip if not valid
              if (!key.isValid()) {
                continue;
              }
    
              if (key.isAcceptable()) {
                handleAccept();
              } else {
                LOGGER.warn("Unexpected state in select! " + key.interestOps());
              }
            }
          } catch (IOException e) {
            LOGGER.warn("Got an IOException while selecting!", e);
          }
        }

    这个selector主要用来接受客户端发过来的tcp连接请求,每当进来一个连接,就用handleaccept方法分配到一个线程里面去处理,

    将对应socketchannel加入BlockingQueue进行缓冲。然后在消费线程run里面慢慢消费处理。

    第二处:TThreadedSelectorServer.SelectorThread

    /**
         * Select and process IO events appropriately: If there are existing
         * connections with data waiting to be read, read it, buffering until a
         * whole frame has been read. If there are any pending responses, buffer
         * them until their target client is available, and then send the data.
         */
        private void select() {
          try {
            // wait for io events.
            selector.select();
    
            // process the io events we received
            Iterator<SelectionKey> selectedKeys = selector.selectedKeys().iterator();
            while (!stopped_ && selectedKeys.hasNext()) {
              SelectionKey key = selectedKeys.next();
              selectedKeys.remove();
    
              // skip if not valid
              if (!key.isValid()) {
                cleanupSelectionKey(key);
                continue;
              }
    
              if (key.isReadable()) {
                // deal with reads
                handleRead(key);
              } else if (key.isWritable()) {
                // deal with writes
                handleWrite(key);
              } else {
                LOGGER.warn("Unexpected state in select! " + key.interestOps());
              }
            }
          } catch (IOException e) {
            LOGGER.warn("Got an IOException while selecting!", e);
          }
        }

    第二处selector是用来监听已经进来的连接是否可读可写的,并进行对应处理。

    thirft高性能的原因

    thrift之所以能在高并发时维持高性能,我认为主要是因为:

    1、使用了同步非阻塞IO

    2、使用了多线程和队列来处理套接字并发连接

    3、支持数据压缩,节省带宽

    4、代码封装得比较成熟,比如一些channel抽象还有processor的封装等。

    5、易用性。支持跨语言,使用简单方便

    目前thrift在hadoop大部分生态组件中都广泛使用到了。

  • 相关阅读:
    inotify事件监控
    NFS网络文件共享服务
    Rsync数据同步服务
    SSH连接原理及ssh-key讲解
    C语言I博客作业04
    C语言l博客作业03
    C语言I博客作业02
    定义一个计算字符串高度的方法
    字典转模型
    UIScrollView和UIPageControl
  • 原文地址:https://www.cnblogs.com/geektcp/p/10016954.html
Copyright © 2020-2023  润新知