1. 程式人生 > >Tomcat整體架構及其工作流程

Tomcat整體架構及其工作流程

這兩天看了一些關於tomcat的東西,在此做一個小的總計。

Tomcat架構

Tomcat中最頂層的容器是Server,代表著整個伺服器,從上圖中可以看出,一個Server可以包含至少一個Service,用於具體提供服務。一個Tomcat中只有一個Server,一個Server可以包含多個Service,一個Service只有一個Container,但是可以有多個Connectors,這是因為一個服務可以有多個連線,如同時提供Http和Https連結,也可以提供向相同協議不同埠的連線,如上圖。

Service主要包含兩個部分:Connector和Container。從上圖中可以看出 Tomcat 的心臟就是這兩個元件,他們的作用如下:

  • Connector用於處理連線相關的事情,並提供Socket與Request和Response相關的轉化; 
  • Connector最底層使用的是Socket來進行連線的,Request和Response是按照HTTP協議來封裝的,所以Connector同時需要實現TCP/IP協議和HTTP協議
  • Container用於封裝和管理Servlet,以及具體處理Request請求;

Server標籤設定的埠號為8005,shutdown=”SHUTDOWN” ,表示在8005埠監聽“SHUTDOWN”命令,如果接收到了就會關閉Tomcat。上述的包含關係或者說是父子關係,都可以在tomcat的conf目錄下的server.xml

配置檔案中看出:

Connector

  • Endpoint用來處理底層Socket的網路連線,Processor用於將Endpoint接收到的Socket封裝成Request,Adapter用於將Request交給Container進行具體的處理
  • Endpoint由於是處理底層的Socket網路連線,因此Endpoint是用來實現TCP/IP協議的,而Processor用來實現HTTP協議的,Adapter將請求適配到Servlet容器進行具體的處理
  • Connector在處理HTTP請求時,會使用不同的protocol。不同的Tomcat版本支援的protocol不同,其中最典型的protocol包括BIO、NIO和APR
  • BIO、NIO:在accept佇列中接收連線(當客戶端向伺服器傳送請求時,如果客戶端與OS完成三次握手建立了連線,則OS將該連線放入accept佇列);在連線中獲取請求的資料,生成request;呼叫servlet容器處理請求;返回response為了便於後面的說明,首先明確一下連線與請求的關係:連線是TCP層面的(傳輸層),對應socket;請求是HTTP層面的(應用層),必須依賴於TCP的連線實現;一個TCP連線中可能傳輸多個HTTP請求。
  • BIO:Acceptor接收socket,然後從Worker執行緒池中找出空閒的執行緒處理socket,如果worker執行緒池沒有空閒執行緒,則Acceptor將阻塞
  • NIO(IO多路複用):Acceptor接收socket後,不是直接使用Worker中的執行緒處理請求,而是先將請求傳送給了Poller,而Poller是實現NIO的關鍵。Acceptor向Poller傳送請求通過佇列實現,使用了典型的生產者-消費者模式。在Poller中,維護了一個Selector物件;當Poller從佇列中取出socket後,註冊到該Selector中;然後通過遍歷Selector,找出其中可讀的socket,並使用Worker中的執行緒處理相應請求。但在“讀取socket並交給Worker中的執行緒”的這個過程中,使用非阻塞的NIO實現,這是NIO模式與BIO模式的最主要區別
  • acceptCount:accept佇列的長度;當accept佇列中連線的個數達到acceptCount時,佇列滿,進來的請求一律被拒絕。預設值是100。
  • maxConnections:Tomcat在任意時刻接收和處理的最大連線數,當Tomcat接收的連線數達到maxConnections時,Acceptor執行緒不會讀取accept佇列中的連線;這時accept佇列中的執行緒會一直阻塞著,直到Tomcat接收的連線數小於maxConnections

  • maxThreads:請求處理執行緒的最大數量。預設值是200(Tomcat7和8都是的

Connector的優化:

  1. 指定protocol -- BIO、NIO、NIO2,APR,如果沒有指定protocol,則使用預設值HTTP/1.1,其含義如下:
  2. 優化3個引數:acceptCount、maxConnections、maxThreads
    <Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol" acceptCount="2" maxConnections="10" maxThreads="2"
               connectionTimeout="20000"
               redirectPort="8443" />
  3. 使用執行緒池Executor
    <Executor name="tomcatThreadPool" namePrefix ="catalina-exec-" maxThreads="150" minSpareThreads="4" />
    
    <Connector executor="tomcatThreadPool" port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" acceptCount="1000" />
  • 在Tomcat7中,自動選取使用BIO或APR(如果找到APR需要的本地庫,則使用APR,否則使用BIO);
  • 在Tomcat8中,自動選取使用NIO或APR(如果找到APR需要的本地庫,則使用APR,否則使用NIO)。

Container

Container用於封裝和管理Servlet,以及具體處理Request請求。Container處理請求是使用Pipeline-Valve管道來處理的,Pipeline-Valve是責任鏈模式

  • Engine:引擎,用來管理多個站點,一個Service最多隻能有一個Engine;
  • Host:代表一個站點,也可以叫虛擬主機,通過配置Host就可以新增站點;
  • Context:代表一個應用程式,對應著平時開發的一套程式,或者一個WEB-INF目錄以及下面的web.xml檔案;
  • Wrapper:每一Wrapper封裝著一個Servlet;

tomcat基本工作流程:

Tomcat Server處理一個HTTP請求的過程

  1. 使用者點選網頁內容,請求被髮送到本機埠8080,被在那裡監聽的Coyote HTTP/1.1 Connector獲得。 
  2. Connector把該請求交給它所在的Service的Engine來處理,並等待Engine的迴應。 
  3. Engine獲得請求localhost/test/index.jsp,匹配所有的虛擬主機Host。 
  4. Engine匹配到名為localhost的Host(即使匹配不到也把請求交給該Host處理,因為該Host被定義為該Engine的預設主機),名為localhost的Host獲得請求/test/index.jsp,匹配它所擁有的所有的Context。Host匹配到路徑為/test的Context(如果匹配不到就把該請求交給路徑名為“ ”的Context去處理)。 
  5. path=“/test”的Context獲得請求/index.jsp,在它的mapping table中尋找出對應的Servlet。Context匹配到URL PATTERN為*.jsp的Servlet,對應於JspServlet類。 
  6. 構造HttpServletRequest物件和HttpServletResponse物件,作為引數呼叫JspServlet的doGet()或doPost().執行業務邏輯、資料儲存等程式。 
  7. Context把執行完之後的HttpServletResponse物件返回給Host。 
  8. Host把HttpServletResponse物件返回給Engine。 
  9. Engine把HttpServletResponse物件返回Connector。 
  10. Connector把HttpServletResponse物件返回給客戶Browser。