tomcat7併發和線程數

最近一直在解決線上一個問題,表現是:

Tomcat每到凌晨會有一個高峯,峯值的併發達到了3000以上,最後的結果是Tomcat線程池滿了,日誌看很多請求超過了1s。

服務器性能很好,Tomcat版本是7.0.54,配置如下:

複製代碼
 <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
        maxThreads="3000" minSpareThreads="800"/>

    <Connector executor="tomcatThreadPool" port="8084" protocol="org.apache.coyote.http11.Http11AprProtocol"
               connectionTimeout="60000"
               keepAliveTimeout="30000"
               maxKeepAliveRequests="8000"
               maxHttpHeaderSize="8192"
               URIEncoding="UTF-8"
               enableLookups="false"
               acceptCount="1000"
               disableUploadTimeout="true"
               redirectPort="8443" />
複製代碼

事後thread dump看其實真正處於RUNNABLE狀態的線程很少,絕大部分線程都處於TIMED_WAITING狀態:

於是大夥都開始糾結爲什麼線程會漲到3000,而且發現即使峯值過了線程數並不會降下來。

我們首先想到的是:

後端應用的處理瞬間比較慢,“堵住了”導致前端線程數漲了起來。

但是優化一個版本上線後發現雖然漲的情況有所好轉,但是最終線程池還是會達到3000這個最大值。

==================================分割線=========================================

以上是大背景,中間的過程省略,直接跟各位說下目前我得到的結論:

1、首先是爲什麼線程不釋放的問題?

簡單說下我驗證的Tomcat(7.0.54)線程池大概的工作機制

  • Tomcat啓動時如果沒有請求過來,那麼線程數(都是指線程池的)爲0;
  • 一旦有請求,Tomcat會初始化minSapreThreads設置的線程數;
  • Tomcat不會主動對線程池進行收縮,除非確定沒有任何請求的時候,Tomcat纔會將線程池收縮到minSpareThreads設置的大小;
  • Tomcat6之前的版本有一個maxSpareThreads參數,但是在7中已經移除了,所以只要前面哪怕只有一個請求,Tomcat也不會釋放多於空閒的線程。

至於Tomcat爲什麼移除maxSpareThreads這個參數,我想也是出於性能的考慮,不停的收縮線程池性能肯定不高,而多餘的線程處於等待狀態的好處是一有新請求過來立刻可以處理。

  • 而且大量的Tomcat線程處於等待狀態不會消耗CPU,但是會消耗一些JVM存儲。

 

補充:上面標紅的一句有點問題,進一步驗證發現只有使用Keep-Alive(客戶端和服務端都支持)時纔是這種表現,如果客戶端沒有使用Keep-Alive那麼線程會隨着TCP連接的釋放而回收。

Tomcat中Keep-Alive相關的參數:

maxKeepAliveRequests:

The maximum number of HTTP requests which can be pipelined until the connection is closed by the server. Setting this attribute to 1 will disable HTTP/1.0 keep-alive, as well as HTTP/1.1 keep-alive and pipelining. Setting this to -1 will allow an unlimited amount of pipelined or keep-alive HTTP requests. If not specified, this attribute is set to 100.

keepAliveTimeout:

The number of milliseconds this Connector will wait for another HTTP request before closing the connection. The default value is to use the value that has been set for the connectionTimeout attribute. Use a value of -1 to indicate no (i.e. infinite) timeout. 

 

2、爲什麼線程池會滿?

這是我現在糾結的核心。到底是不是應用的性能慢導致的,我現在的結論是有關係,但關鍵是併發。

  • Tomcat的線程池的線程數跟你的瞬間併發有關係,比如maxThreads設置爲1000,當瞬間併發達到1000那麼Tomcat就會起1000個線程來處理,這時候跟你應用的快慢關係不大。

那麼是不是併發多少Tomcat就會起多少個線程呢?這裏還跟Tomcat的這幾個參數設置有關係,看官方的解釋是最靠譜的:

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.

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 BIO the default is the value of maxThreads unless an Executor is used in which case the default will be the value of maxThreads from the executor. For NIO the default is 10000. For APR/native, the default is 8192.

……

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.

minSpareThreads:

The minimum number of threads always kept running. If not specified, the default of 10 is used.

我簡單理解就是:

maxThreads:Tomcat線程池最多能起的線程數;

maxConnections:Tomcat最多能併發處理的請求(連接);

acceptCount:Tomcat維護最大的對列數;

minSpareThreads:Tomcat初始化的線程池大小或者說Tomcat線程池最少會有這麼多線程。

比較容易弄混的是maxThreads和maxConnections這兩個參數:

maxThreads是指Tomcat線程池做多能起的線程數,而maxConnections則是Tomcat一瞬間做多能夠處理的併發連接數。比如maxThreads=1000,maxConnections=800,假設某一瞬間的併發時1000,那麼最終Tomcat的線程數將會是800,即同時處理800個請求,剩餘200進入隊列“排隊”,如果acceptCount=100,那麼有100個請求會被拒掉。
注意:根據前面所說,只是併發那一瞬間Tomcat會起800個線程處理請求,但是穩定後,某一瞬間可能只有很少的線程處於RUNNABLE狀態,大部分線程是TIMED_WAITING,如果你的應用處理時間夠快的話。所以真正決定Tomcat最大可能達到的線程數是maxConnections這個參數和併發數,當併發數超過這個參數則請求會排隊,這時響應的快慢就看你的程序性能了。

轉載自: http://www.cnblogs.com/magialmoon/p/concurrent-and-tomcat-threads.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章