1. 程式人生 > >Tomcat 架構概述

Tomcat 架構概述

關於 流水線 研究 engine 參考 sim 上下文 com 設計

Tomcat 是一個 Web 應用服務器,它是對 HTTP 和 Servlet 規範的實現,簡單來說它做了這幾件事:處理 HTTP 協議、執行 Servlet 和處理網絡 I/O。這裏以 6.0.53 版本為例(實現了 HTTP/1.1、Servlet2.5),研究其基本結構。

關於源碼版本,我使用的是 tomcat6,因為 7 為了重構有太多的抽象,看著實在費勁,6 代碼雖有冗余但讀起來很直觀,並且低版本也不影響理解 Tomcat 的核心流程。

體系結構

server.xml 中就能夠看出 Tomcat 各組件的層次結構,具體結構圖如下:

技術分享圖片

  • Server:代表整個容器,它可能包含一個或多個 Service 和全局 JNDI 資源;
  • Service:包含一個或多個 Connector,這些連接器與一個 Engine 相關聯;
  • Engine:表示請求處理流水線(pipeline),它接收所有連接器的請求,並將響應交給適當的連接器返回給客戶端;
  • Host:網絡名稱(域名)與 Tomcat 服務器的關聯,默認主機名 localhost,一個 Engine 可包含多個 Host;
  • Connector:處理與客戶端的通信,網絡 I/O;
  • Context:表示一個 Web 應用程序,一個 Host 包含多個上下文。

服務器模型

服務器模型(或 I/O 模型),描述的是 TCP 連接的處理方式,以及 Socket 讀寫時線程的狀態。Java 裏常用的是 BIO 和 NIO,分別對應同步阻塞和同步非阻塞兩種模型,Tomcat 中的 Connector 組件就是對這兩種的封裝實現。

BIO - 阻塞式

Tomcat 實現了一個一連接一線程的簡單服務器模型,內部采用線程池做了優化,設計如下:

技術分享圖片

  • 當 Acceptor 接收到一個 TCP 連接時,線程池分配一個線程進行處理;
  • 線程調用 read() 方法讀取 Socket 輸入流中的字節,此時線程阻塞(Block),直到收到客戶端發送的數據;
  • 收到數據後,進行解碼、業務處理、編碼,最後把響應發送到客戶端,關閉連接。

由此可以看出,合理的分配線程池大小可以一定程度上提高系統的並發能力。

NIO - 非阻塞

BIO 的缺點在於不管當前連接有沒有數據傳輸,它始終阻塞占用線程池內的一個線程,而 NIO 的處理方式是若通道無數據可讀取,此時線程不阻塞直接返回,可用於處理其他連接,提高了線程利用率。那怎麽知道什麽時候處理數據的讀寫呢?當通道可讀或可寫時,內核會通知用戶程序進行處理。

NIO 的編程比較復雜,常用的是 Reactor 模式,它描述了一個利用多路復用 I/O,基於事件驅動的服務器處理模型,(這裏) 基於 Doug Lea 的 Scalable IO in Java 對 Reactor 進行了實現。Tomcat 的設計略有不同,其設計如下:

技術分享圖片

  • Acceptor 以阻塞模式接收 TCP 連接,然後將連接註冊到 Poller 上;
  • Poller 以非阻塞模式處理 SSL 握手和 HTTP 請求頭的讀取;
  • BlockPoller 模擬阻塞處理 HTTP 請求體的讀取和發送響應。

值得註意的是,兩類 Poller 都只是負責事件的通知,I/O 操作都是由線程池中的線程完成。那麽,ServerSocketChannel 為什麽阻塞?為什麽要模擬阻塞處理請求體和 Servlet 響應?相關的討論可參考:

  • Why Tomcat‘s Non-Blocking Connector is using a blocking socket?
  • Getting my head around NIO ‘simulated‘ blocking (trying to)

Servlet API 的實現

Servlet 規範描述了容器如何加載和運行 Servlet,如和將請求映射到用戶配置的 Servlet, 如何處理請求和響應等相關問題。Tomcat 主要實現了以下 API:

  • ServletConfig :Servlet 名字和初始化參數;
  • ServletContext :定義了 Web 應用程序,Servlet 運行的上下文;
  • ServletRequest :封裝客戶端請求;
  • ServletResponse :封裝服務端響應;
  • FilterChain :請求過濾調用鏈;
  • FilterConfig :過濾配置對象;
  • RequestDispatcher :轉發請求,將請求轉發給 JSP 或另一個 Servlet 處理。

其他如 Servlet、Filter、GenericServlet、HttpServlet 接口或類則由用戶程序來實現,更多詳細的介紹請參考規範內容。

小結

Tomcat 架構看著挺簡單但做起來難,難的就是把復雜的問題抽象化、簡單化,體現到代碼上就是如何設計和抽象出類並且優雅的組織在一起,它作為一個流行的中間件,其內部代碼的實現以及優化手段,也是值得我們去研究和模仿的。

Tomcat 架構概述