實現高性能 Tomcat
2015-08-05 23:03:58 by陸晨
引子:這篇文章主要淺析一下Tomcat底層對IO處理的可選擇性以及深入一些對操作系統相關調用的介紹,主要包括send和sendfile系統調用。
Tomcat常用的三種IO模式
提起高性能JAVA IO大家一定會想到NIO,AIO等等,然而我們的Tomcat是java寫的一個優秀的開源的web服務,它與NIO有什么關系呢?我們的tomcat應用是不是早就跑在nio之上了呢?
答案是Tomcat是支持NIO的,到Tomcat7為止,默認的Tomcat包里面的配置并沒有開啟NIO連接器。下面我先簡單介紹一下Tomcat的三種IO策略:BIO,NIO,APR。
BIO:大家是否記得我們初學網絡編程的時候,我們寫的第一個服務器程序……,BIO是Tomcat默認開啟的IO模式,性能灰常底下,沒有經過任何的優化處理。
NIO:利用JAVA的非阻塞IO技術,開啟這個模式非常簡單,只需要把tomcat子目錄conf下面的server.xml修改一下即可,找到下面,將protocol改為org.apache.coyote.http11.Http11NioProtocol即可。
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
上面是默認的配置,我們改成下面這個樣子:
<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol" connectionTimeout="20000" redirectPort="8443" />
這樣重啟你的tomcat就好,有沒有被easy到?
APR:這種模式使用起來最優門檻,除非要將上面的配置改成下面這樣:
還需要下載APR模式需要的庫,因為這種模式是基于JNI的,即JAVA調用本地庫的方式來進行IO。
Tomcat對靜態資源的處理
大家都知道,Tomcat為我們提供了一個專門用來處理靜態資源的Servler,它叫DefaultServlet,看看這個Servlet的源代碼,其中對資源處理方法的實現里面有下面這樣一段:
if (ostream != null) { if (!checkSendfile(request, response, cacheEntry, contentLength, null)) copy(cacheEntry, renderResult, ostream); } else { copy(cacheEntry, renderResult, writer); }
作者的意思是這里判斷如果沒有滿足使用sendfile條件的情況下我們就直接將靜態資源數據讀取,寫入response的輸出流,那么如果滿足使用sendfile條件,這里是不做處理的,這里會把資源文件的大小即名稱放在request的屬性集合里面帶給底層,讓底層來處理。
Tomcat定義了三種類型的Endpoint,他們分別是BIO,NIO及APR三種模式下底層網絡處理的具體實現,比如 NioEndpoint里面調用了FileChannel的transferTo方法,transferTo會利用操作系統的sendfile系統調用來將磁盤文件輸出到網絡。同樣AprEndpoint最為哦APR方式的實現會調用Native來實現IO。
send和sendfile
Tomcat中的NIO模式和APR模式對靜態文件處理的高效根源在于地從對不同的系統調用,和普通的文件傳輸不同的是NIO和APR方式都使用的操作系統的sendfile系統調用來對文件進行IO,而普通的方式是使用了read和write系統調用。name這兩種類型有什么不同呢,這是本文的關鍵點:
文件讀取以發送至網絡流程圖
先看看上面這張圖,使用read和write方式的時候,將文件輸出到網絡的流程是這樣的:
1,read操作先將線程從用戶態切換到內核態,將文件從磁盤讀到內核緩沖器。
2,read將文件從內核緩沖區讀到用戶地址空間,同時線程從內核態切換到用戶態。
3,read返回。
4,對文件進行處理
5,write將線程從用戶態切換到內核態,將文件寫到操作系統內核網絡部分的緩沖區。
6,write將線程切換到用戶態并返回。
上面的的過程涉及到四次操作系統內核態與用戶態的切換,代價是昂貴的。由于事實上我們并不需要對靜態文件進行處理這個步驟,為什么要繞一個圈子呢從內核copy到用戶態又copy到內核態呢,因此sendfile來了。
我們再來看看sendfile的處理流程:
1,將文件讀到操作系統的內核緩沖區。
2,將文件copy到操作系統跟網絡相關的內核緩沖區。
上面不會涉及到內核態到用戶態以及用戶態到內核態的切換,sendfile是linux2+version提供的系統調用,而且在 linux2.4+version版本之后提供能zero-copy特性,上面這些說明了sendfile為我們的程序提高了問靜態文件處理的能力和性能。