现在的位置: 首页 > 综合 > 正文

谈谈jetty8 的io模型

2013年12月12日 ⁄ 综合 ⁄ 共 2224字 ⁄ 字号 评论关闭

几个重要的概念

  • Connector: jetty网络接口的封装,用于监听网络连接
  • SelectorManager:底层selector封装,管理网络事件,主要是向底层selector注册感兴趣的网络事件,并从selector中轮询出准备好的事件
  • EndPoint:socket的封装,用于底层网络的读写,一旦网络读写准备好,会调用相应的connection的handle方法
  • Connection:请求的抽象,比如解析请求的http协议,并调用servlet 容器,依赖EndPoint

见图

几个重要的线程

1) Acceptor线程

  • task:org.eclipse.jetty.server.AbstractConnector.Acceptor
  • 数量设定:setAcceptors(Math.max(1,(Runtime.getRuntime().availableProcessors()+3)/4));见SelectChannelConnector构造函数
  • 触发时机:见SelectChannelConnector(AbstractConnector).doStart()
  • 执行线程:QueuedThreadPool中的线程
  • 执行逻辑
    • 轮询SelectChannelConnector.accept(int acceptorID)
    • 以阻塞的方式获取连接请求
    • 一旦获得连接,调用ConnectorSelectorManager.register(SocketChannel channel)
      • 向SelectorManager$SelectSet 内部的_changes队列中添加该事件(有新的连接)
      • 唤醒selector

2)Selector 线程

  • task:匿名内部类(new Runnable(){......})
  • 数量设定:在jetty.xml中配置
  • 触发时机:见SelectChannelConnector$ConnectorSelectorManager(SelectorManager).doStart()
  • 执行线程:QueuedThreadPool中的线程
  • 执行逻辑
    • 轮询SelectorManager$SelectSet.doSelect()
    • 从_changes队列获取感兴趣的事件
      • 如果是EndPoint类型(读写事件)
        • 如果已在selector中注册过,则更新selection key, 否则向selector注册
      • 如果是ChannelAndAttachment类型
        • 如果关联的SocketChannel已连接,则向selector注册读事件
        • 否则注册连接事件
      • 如果是SocketChannel类型(连接事件)
        • 则向selector注册读事件//key = channel.register(selector,SelectionKey.OP_READ,null);
        • 实例化SelectChannelEndPoint //createEndPoint(channel,key);
        • 调用SelectChannelEndPoint.schedule()
          • 调用SelectChannelConnector$ConnectorSelectorManager.dispatch(Runnable task)将请求扔给QueuedThreadPool(存放在内部jobs队列)
      • 如果是ChangeTask类型
        • 直接执行
      • 如果是Runnable
        • 直接丢给QueuedThreadPool
    • 运行selector.select获取准备好的SelectionKey,遍历SelectionKey
      • 如果key无效则去更新
      • 如果有事件发生则调用SelectChannelEndPoint.schedule()
    • 调用selector.selectedKeys().clear()

3)Worker线程

  • task:匿名内部类(new Runnable(){......})
  • 数量设定:在jetty.xml中配置
  • 触发时机:QueuedThreadPool.startThread
  • 执行线程:QueuedThreadPool中的线程
  • 执行逻辑:
    • 轮询从jobs队列取job(通常是SelectChannelEndPoint的匿名内部类(new Runnable(){......}))
    • 然后执行job.run(通常是SelectChannelEndPoint.handle())
      • 调用SelectChannelConnector$SelectChannelHttpConnection(AsyncHttpConnection).handle()
        • HttpParser.parseAvailable()(不断调用parseNext读取请求的内容)处理请求
        • flush内容
        • 如果过程中存在写阻塞,会调用SelectChannelEndPoint.scheduleWrite()或者直接调用updateKey()往_changes队列中添加写事件

线程关系见图

小结(请求处理流程)

  • Acceptor线程负责监听连接,一但有连接过来,写入changes队列
  • Selector轮询changes队列,将队列中的感兴趣事件往selector中注册,并从selector中查出准备好的网络事件,一旦有准备好的网络事件,通过调用endpoint.schedule()将task丢入线程池的jobs队列
  • Work线程会从jobs队列取出任务,然后执行
  • 上面的3组线程全来自QueuedThreadPool中的线程

 

抱歉!评论已关闭.