tomcat 執行緒模式

來源:互聯網
上載者:User

最近看到了內網ATA上的一篇斷網故障時Mtop觸發tomcat高並發情境下的BUG排查和修複(已被apache採納),引起了我的好奇,感覺原作者對應底層十分瞭解,寫的很複雜。原來對於tomcat的執行緒模式不怎麼清楚,但是它又是我們日常最常用的伺服器,於是我對它的執行緒模式進行了補習。 一. tomcat支援的請求處理方式

Tomcat支援三種接收請求的處理方式:BIO、NIO、APR

BIO模式:阻塞式I/O操作,表示Tomcat使用的是傳統Java I/O操作(即Java.io包及其子包)。Tomcat7以下版本預設情況下是以bio模式啟動並執行,由於每個請求都要建立一個線程來處理,線程開銷較大,不能處理高並發的情境,在三種模式中效能也最低。啟動tomcat看到如下日誌,表示使用的是BIO模式:

NIO模式:是java SE 1.4及後續版本提供的一種新的I/O操作方式(即java.nio包及其子包)。是一個基於緩衝區、並能提供非阻塞I/O操作的Java API,它擁有比傳統I/O操作(bio)更好的並發運行效能。在tomcat 8之前要讓Tomcat以nio模式來運行比較簡單,只需要在Tomcat安裝目錄/conf/server.xml檔案中將如下配置:

<Connector port="8080" protocol="HTTP/1.1"connectionTimeout="20000"redirectPort="8443" />

修改成

<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"connectionTimeout="20000"redirectPort="8443" />

Tomcat8以上版本,預設使用的就是NIO模式,不需要額外修改
apr模式:簡單理解,就是從作業系統層級解決非同步IO問題,大幅度的提高伺服器的處理和響應效能, 也是Tomcat運行高並發應用的首選模式。
啟用這種模式稍微麻煩一些,需要安裝一些依賴庫,下面以在CentOS7 mini版環境下Tomcat-8.0.35為例,介紹安裝步聚:

APR 1.2+ development headers (libapr1-dev package)OpenSSL 0.9.7+ development headers (libssl-dev package)JNI headers from Java compatible JDK 1.4+GNU development environment (gcc, make)
二. tomcat的NioEndpoint

我們先來簡單回顧下目前一般的NIO伺服器端的大致實現,借鑒infoq上的一篇文章Netty系列之Netty執行緒模式中的一張圖

一個或多個Acceptor線程,每個線程都有自己的Selector,Acceptor只負責accept新的串連,一旦串連建立之後就將串連註冊到其他Worker線程中。
多個Worker線程,有時候也叫IO線程,就是專門負責IO讀寫的。一種實現方式就是像Netty一樣,每個Worker線程都有自己的Selector,可以負責多個串連的IO讀寫事件,每個串連歸屬於某個線程。另一種方式實現方式就是有專門的線程負責IO事件監聽,這些線程有自己的Selector,一旦監聽到有IO讀寫事件,並不是像第一種實現方式那樣(自己去執行IO操作),而是將IO操作封裝成一個Runnable交給Worker線程池來執行,這種情況每個串連可能會被多個線程同時操作,相比第一種並發性提高了,但是也可能引來多線程問題,在處理上要更加謹慎些。tomcat的NIO模型就是第二種。

這就要詳細瞭解下tomcat的NioEndpoint實現了。先來借鑒看下 斷網故障時Mtop觸發tomcat高並發情境下的BUG排查和修複(已被apache採納) 中的一張圖

這張圖勾畫出了NioEndpoint的大致執行流程圖,worker線程並沒有體現出來,它是作為一個線程池不斷的執行IO讀寫事件即SocketProcessor(一個Runnable),即這裡的Poller僅僅監聽Socket的IO事件,然後封裝成一個個的SocketProcessor交給worker線程池來處理。下面我們來詳細的介紹下NioEndpoint中的Acceptor、Poller、SocketProcessor。
它們處理用戶端串連的主要流程如圖所示:

圖中Acceptor及Worker分別是以線程池形式存在,Poller是一個單線程。注意,與BIO的實現一樣,預設狀態下,在server.xml中沒有配置<Executor>,則以Worker線程池運行,如果配置了<Executor>,則以基於java concurrent 系列的java.util.concurrent.ThreadPoolExecutor線程池運行。

Acceptor
接收socket線程,這裡雖然是基於NIO的connector,但是在接收socket方面還是傳統的serverSocket.accept()方式,獲得SocketChannel對象,然後封裝在一個tomcat的實作類別org.apache.tomcat.util.net.NioChannel對象中。然後將NioChannel對象封裝在一個PollerEvent對象中,並將PollerEvent對象壓入events queue裡。這裡是個典型的生產者-消費者模式,Acceptor與Poller線程之間通過queue通訊,Acceptor是events queue的生產者,Poller是events queue的消費者。

Poller
Poller線程中維護了一個Selector對象,NIO就是基於Selector來完成邏輯的。在connector中並不止一個Selector,在socket的讀寫資料時,為了控制timeout也有一個Selector,在後面的BlockSelector中介紹。可以先把Poller線程中維護的這個Selector標為主Selector。 Poller是NIO實現的主要線程。首先作為events queue的消費者,從queue中取出PollerEvent對象,然後將此對象中的channel以OP_READ事件註冊到主Selector中,然後主Selector執行select操作,遍曆出可以讀資料的socket,並從Worker線程池中拿到可用的Worker線程,然後將socket傳遞給Worker。整個過程是典型的NIO實現。

Worker
Worker線程拿到Poller傳過來的socket後,將socket封裝在SocketProcessor對象中。然後從Http11ConnectionHandler中取出Http11NioProcessor對象,從Http11NioProcessor中調用CoyoteAdapter的邏輯,跟BIO實現一樣。在Worker線程中,會完成從socket中讀取http request,解析成HttpServletRequest對象,指派到相應的servlet並完成邏輯,然後將response通過socket發回client。在從socket中讀資料和往socket中寫資料的過程,並沒有像典型的非阻塞的NIO的那樣,註冊OP_READ或OP_WRITE事件到主Selector,而是直接通過socket完成讀寫,這時是阻塞完成的,但是在timeout控制上,使用了NIO的Selector機制,但是這個Selector並不是Poller線程維護的主Selector,而是BlockPoller線程中維護的Selector,稱之為輔Selector。 三. tomcat8的並發參數控制

本篇的tomcat版本是tomcat8.5。可以到這裡看下tomcat8.5的配置參數

acceptCount
文檔描述為:
The maximum queue length for incoming connection requests when all possible request processing threads are in use. Any requests received when the queue is full will be refused. The default value is 100.
這個參數就立馬牽涉出一塊大內容:TCP三向交握的詳細過程,這個之後再詳細探討。這裡可以簡單理解為:串連在被ServerSocketChannel accept之前就暫存在這個隊列中,acceptCount就是這個隊列的最大長度。ServerSocketChannel accept就是從這個隊列中不斷取出已經建立串連的的請求。所以當ServerSocketChannel accept取出不及時就有可能造成該隊列積壓,一旦滿了串連就被拒絕了

acceptorThreadCount
文檔如下描述
The number of threads to be used to accept connections. Increase this value on a multi CPU machine, although you would never really need more than 2. Also, with a lot of non keep alive connections, you might want to increase this value as well. Default value is 1.
Acceptor線程只負責從上述隊列中取出已經建立串連的請求。在啟動的時候使用一個ServerSocketChannel監聽一個串連連接埠如8080,可以有多個Acceptor線程並發不斷調用上述ServerSocketChannel的accept方法來擷取新的串連。參數acceptorThreadCount其實使用的Acceptor線程的個數。

maxConnections
文檔描述如下
The maximum number of connections that the server will accept and process at any given time. When this number has been reached, the server will accept, but not process, one further connection. This additional connection be blocked until the number of connections being processed falls below maxConnections at which point the server will start accepting and processing new connections again. Note that once the limit has been reached, the operating system may still accept connections based on the acceptCount setting. The default value varies by connector type. For NIO and NIO2 the default is 10000. For APR/native, the default is 8192.
Note that for APR/native on Windows, the configured value will be reduced to the highest multiple of 1024 that is less than or equal to maxConnections. This is done for performance reasons. If set to a value of -1, the maxConnections feature is disabled and connections are not counted.
這裡就是tomcat對於串連數的一個控制,即最大串連數限制。一旦發現當前串連數已經超過了一定的數量(NIO預設是10000),上述的Acceptor線程就被阻塞了,即不再執行ServerSocketChannel的accept方法從隊列中擷取已經建立的串連。但是它並不阻止新的串連的建立,新的串連的建立過程不是Acceptor控制的,Acceptor僅僅是從隊列中擷取建立立的串連。所以當串連數已經超過maxConnections後,仍然是可以建立新的串連的,存放在上述acceptCount大小的隊列中,這個隊列裡面的串連沒有被Acceptor擷取,就處於串連建立了但是不被處理的狀態。當串連數低於maxConnections之後,Acceptor線程就不再阻塞,繼續調用ServerSocketChannel的accept方法從acceptCount大小的隊列中繼續擷取新的串連,之後就開始處理這些新的串連的IO事件了。

maxThreads
文檔描述如下
The maximum number of request processing threads to be created by this Connector, which therefore determines the maximum number of simultaneous requests that can be handled. If not specified, this attribute is set to 200. If an executor is associated with this connector, this attribute is ignored as the connector will execute tasks using the executor rather than an internal thread pool.
這個簡單理解就算是上述worker的線程數。他們專門用於處理IO事件,預設是200。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.