高并发编程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大部分生态组件中都广泛使用到了。

猜你喜欢

转载自www.cnblogs.com/geektcp/p/10016954.html