談談jetty8 的io模型

幾個重要的概念


  • 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中的線程



 






發佈了200 篇原創文章 · 獲贊 7 · 訪問量 106萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章