天天看點

談談jetty8 的io模型

幾個重要的概念

  • Connector: jetty網絡接口的封裝,用于監聽網絡連接配接
  • SelectorManager:底層selector封裝,管理網絡事件,主要是向底層selector注冊感興趣的網絡事件,并從selector中輪詢出準備好的事件
  • EndPoint:socket的封裝,用于底層網絡的讀寫,一旦網絡讀寫準備好,會調用相應的connection的handle方法
  • Connection:請求的抽象,比如解析請求的http協定,并調用servlet 容器,依賴EndPoint

見圖

談談jetty8 的io模型

幾個重要的線程

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隊列中添加寫事件

線程關系見圖

談談jetty8 的io模型

小結(請求處理流程)

  • Acceptor線程負責監聽連接配接,一但有連接配接過來,寫入changes隊列
  • Selector輪詢changes隊列,将隊列中的感興趣事件往selector中注冊,并從selector中查出準備好的網絡事件,一旦有準備好的網絡事件,通過調用endpoint.schedule()将task丢入線程池的jobs隊列
  • Work線程會從jobs隊列取出任務,然後執行
  • 上面的3組線程全來自QueuedThreadPool中的線程

繼續閱讀