天天看點

tomcat架構分析(connector BIO 實作)

出處:http://gearever.iteye.com  

在 tomcat架構分析(概覽) 中已經介紹過,connector元件是service容器中的一部分。它主要是接收,解析http請求,然後調用本service下的相關servlet。由于tomcat從架構上采用的是一個分層結構,是以根據解析過的http請求,定位到相應的servlet也是一個相對比較複雜的過程。 

tomcat架構分析(connector BIO 實作)

整個connector實作了從接收socket到調用servlet的全部過程。先來看一下connector的功能邏輯; 

  • 接收socket
  • 從socket擷取資料包,并解析成HttpServletRequest對象
  • 從engine容器開始走調用流程,經過各層valve,最後調用servlet完成業務邏輯
  • 傳回response,關閉socket

可以看出,整個connector元件是tomcat運作主幹,之前介紹的各個子產品都是tomcat啟動時,靜态建立好的,通過connector将這些子產品串了起來。 

通常在實際運作中,特别是對于一些網際網路應用而言,網絡吞吐一直是整個服務的瓶頸所在,是以,connector的運作效率在一定程度上影響了tomcat的整體性能。相對來說,tomcat在處理靜态頁面方面一直有一些瓶頸,是以通常的服務架構都是前端類似nginx的web伺服器,後端挂上tomcat作為應用伺服器(當然還有些其他原因,例如負載均衡等)。Tomcat在connector的優化上做了一些特殊的處理,這些都是可選的,通過部署,配置友善完成,例如APR(Apache Portable Runtime),BIO,NIO等。 

目前connector支援的協定是HTTP和AJP。AJP是Apache與其他伺服器之間的通信協定。通常在叢集環境中,例如前端web伺服器和後端應用伺服器或servlet容器,使用AJP會比HTTP有更好的性能,這裡引述apache官網上的一段話“ If integration with the native webserver is needed for any reason, an AJP connector will provide faster performance than proxied HTTP. AJP clustering is the most efficient from the Tomcat perspective. It is otherwise functionally equivalent to HTTP clustering.” 

本篇主要是針對HTTP協定的connector進行闡述。先來看一下connector的配置,在server.xml裡; 

Xml代碼  

tomcat架構分析(connector BIO 實作)
  1. <Connector port="80" URIEncoding="UTF-8" protocol="HTTP/1.1"   
  2.                connectionTimeout="20000"   
  3.                redirectPort="7443" />  

熟悉的80端口不必說了。“protocol”這裡是指這個connector支援的協定。針對HTTP協定而言,這個屬性可以配置的值有: 

  • HTTP/1.1
  • org.apache.coyote.http11.Http11Protocol –BIO實作
  • org.apache.coyote.http11.Http11NioProtocol –NIO實作
  • 定制的接口

配置“HTTP/1.1”和“org.apache.coyote.http11.Http11Protocol”的效果是一樣的,是以connector的HTTP協定實作預設是支援BIO的。無論是BIO還是NIO都是實作一個org.apache.coyote.ProtocolHandler接口,是以如果需要定制化,也必須實作這個接口。 

本篇就來看看預設狀态下HTTP connector的架構及其消息流。 

tomcat架構分析(connector BIO 實作)

可以看見connector中三大塊 

  • Http11Protocol
  • Mapper
  • CoyoteAdapter

Http11Protocol  

類全路徑org.apache.coyote.http11.Http11Protocol,這是支援http的BIO實作。 Http11Protocol包含了JIoEndpoint對象及Http11ConnectionHandler對象。 

Http11ConnectionHandler對象維護了一個Http11Processor對象池,Http11Processor對象會調用CoyoteAdapter完成http request的解析和分派。 

JIoEndpoint維護了兩個線程池,Acceptor及Worker。Acceptor是接收socket,然後從Worker線程池中找出空閑的線程處理socket,如果worker線程池沒有空閑線程,則Acceptor将阻塞。Worker是典型的線程池實作。Worker線程拿到socket後,就從Http11Processor對象池中擷取Http11Processor對象,進一步處理。除了這個比較基礎的Worker線程池,也可以通過基于java concurrent 系列的java.util.concurrent.ThreadPoolExecutor線程池實作,不過需要在server.xml中配置相應的節點,即在connector同級别配置<Executor>,配置完後,使用ThreadPoolExecutor與Worker在實作上沒有什麼大的差別,就不贅述了。 

Xml代碼  

tomcat架構分析(connector BIO 實作)
  1. <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"   
  2.         maxThreads="150" minSpareThreads="4"/>  

圖中的箭頭代表了消息流。 

Mapper  

類全路徑org.apache.tomcat.util.http.mapper.Mapper,此對象維護了一個從Host到Wrapper的各級容器的快照。它主要是為了,當http request被解析後,能夠将http request綁定到相應的servlet進行業務處理。前面的文章中已經說明,在加載各層容器時,會将它們注冊到JMX中。 

tomcat架構分析(connector BIO 實作)

是以當connector元件啟動的時候,會從JMX中查詢出各層容器,然後再建立這個Mapper對象中的快照。 

CoyoteAdapter  

全路徑org.apache.catalina.connector.CoyoteAdapter,此對象負責将http request解析成HttpServletRequest對象,之後綁定相應的容器,然後從engine開始逐層調用valve直至該servlet。在session管理中,已經說明,根據request中的jsessionid綁定伺服器端的相應session。這個jsessionid按照優先級或是從request url中擷取,或是從cookie中擷取,然後再session池中找到相應比對的session對象,然後将其封裝到HttpServletRequest對象。所有這些都是在CoyoteAdapter中完成的。看一下将request解析為HttpServletRequest對象後,開始調用servlet的代碼; 

Java代碼  

tomcat架構分析(connector BIO 實作)
  1. connector.getContainer().getPipeline().getFirst().invoke(request, response);  

connector的容器就是StandardEngine,代碼的可讀性很強,擷取StandardEngine的pipeline,然後從第一個valve開始調用邏輯,相應的過程請參照tomcat架構分析(valve機制)。