tomcat優化總結

系統發生了比較嚴重的性能問題,因爲事情緊急只能取消自己的休假計劃,趕到現場調試系統。 

到了之後,首先檢查了Tomcat的配置文件server.xml,原來一直以爲肯定是配置服務器的同學沒有把Tomcat中默認的允許訪問的最大數75給改掉,後來發現不是這個問題,在配置文件中設置Context的地方有一段非常的詭異:有一個Context的路徑是在%Tomcat%/webapps/ROOT中的一個目錄AAA,這樣的話如果當一個用戶訪問URL:http://serverip:port/AAA 時,系統是應該使用ROOT/WEB-INF中類還是應該使用ROOT/AAA/WEB-INF中的類?把服務器中兩個WEB-INF都下載下來,用JAD反編譯其中的部分類,發現並不一致。最後經過分析,得出了TOMCAT在這種Context嵌套在ROOT Context中的情況,TOMCAT會使用ROOT目錄中的WEB-INF。 

然後爲程序加入了數據庫連接池配置,實踐證明了如果不採用TOMCAT的數據庫連接池技術,那麼在併發訪問數達到4000-5000的時候,Tomcat絕對支撐不到1分鐘的。採用TOMCAT的數據庫連接池技術後這時的TOMCAT能維持正常運行30分鐘左右。數據庫連接池配置的方式如下:修改tomcat配置文件server.xml,在context標籤中加上: 
1. 
2. 
4. 
5. 
6. factory 
7. org.apache.commons.dbcp. 
8. BasicDataSourceFactory 
9. 
10. 
11. driverClassName 
12. oracle.jdbc.driver.OracleDriver 
13. 
14. 
15. url 
16. jdbc:oracle:thin:@10.11.6.1:1521:dbname 
17. 
18. 
19. 
20. username 
21. yourname 
22. 
23. 
24. password 
25. yourpasswd 
26. 
27. 
28. maxActive 
29. 1000 
30. 
31. 
32. maxIdle 
33. 20 
34. 
35. maxWait 
36. -1 
37. 
38. 
39. 
maxActive是最大激活連接數,這裏取值爲1000,表示同時最多有1000個數據庫連接。maxIdle是最大的空閒連接數,這裏取值爲20,表示即使沒有數據庫連接時依然可以保持20空閒的連接,而不被清除,隨時處於待命狀態。MaxWait是最大等待秒鐘數,這裏取值-1,表示無限等待,直到超時爲止,也可取值9000,表示9秒後超時。 
修改web.xml文文件,加入 
[待加入的XML片斷,竟然被系統過濾掉了,赫赫,留個站位符] 
將Oracle的JDBC驅動classes12.jar拷貝到Tomcat安裝目錄的common/lib下。建立簡單的測試頁面test2.jsp: 
1. Context initCtx = new InitialContext(); 
2. 
3. Context envCtx = (Context) initCtx.lookup("java:comp/env"); 
4. 
5. ds = (DataSource)envCtx.lookup("jdbc/OracleDB"); 
6. 
7. Connection cn=ds.getConnection(); 

到這裏數據庫連接池配置基本完成了。但是如果半個小時服務器死掉一次的話,還是不能令人接受的。開始詳細檢查tomcat的輸出文件%Tomcat%/logs/catalina.out,在這個文件中記錄的是所有TOMCAT控制檯的輸出,一般在JAVA中的抱錯信息都會在這裏打印出來。自己分析後發現每次TOMCAT死掉之前,都是一堆java.net.SocketException: Too many open files這種錯誤。這個錯誤肯定不是程序的問題。 
可能是因爲每有一個TCP的連接到Linux服務器的80端口,都有一次文件的傳輸過程,Tomcat服務器會打開一個文件(比如圖片文件),傳送給請求的客戶端瀏覽器,所以如果訪問Tomcat的人數過多,會突破linux系統默認的1024個文件上限。 
在/root/.bash_profile文件中加入: 
ulimit -n 4096 
可以在每次系統啓動時候自動執行ulimit命令,把最大文件上傳個數調整到4096個。注意ulimit這個命令是針對於一個開打的終端的,比如你在一個終端上面運行ulimit,但是影響到的只是你這個終端上運行的命令和程序的打開的文件數,其他的終端如果再打開,效果仍然是沒有運行ulimit -n 4096之前的。大家可以實驗一下。 
這樣之後,服務器大概能維持2小時左右的正常運行,使用TOP命令查看Java進程佔用的內存後,發覺一個現象,就是內存使用到256M之後,不會往上增長了(服務器有8G的內存)。上網查了以後,知道了Tomcat默認可以使用的是256M的內存。由於在線人數過多,造成Tomcat默認可以使用的256M的內存不夠使用,所以修改Tomcat的啓動文件catalina.sh,在“echo “Using JAVA_HOME: $JAVA_HOME”” 後加入JAVA_OPTS=’-Xms256m -Xmx1024m’,256m表示初始化的時候給Tomcat初始內存256M,1024m表示Tomcat最大可使用的內存爲1024M。 
修改了這個之後,服務器比原先穩定了許多了,可是又發現在有的時候,進行用戶登錄的時候會報莫名其妙的數據庫連接錯誤。終於在有一次使用ORACLE的客戶端程序GOLDEN連接Oracle時,出現了ORA-00020:maximum number of process(150) exceeded 這樣一個錯誤。這是由於數據庫服務器訪問的連接數過多,會出現ORA-00020:maximum number of process(150) exceeded的錯誤。Oracle 9i中默認的連接數爲150,要修改這個配置文件,需要修改SPFILEORCL.ORA文件中的processes的值。(8.1.5中是init.ora文件,在9i中修改init.ora文件是無效的)這個文件由於是一個二進制的文件,不能直接使用notepad此類的編輯器打開,否則會報錯誤ORA-27101 Shared memory realm does not exist。使用UltraEdit或者EditPlus之類的可以編輯二進制文件的編輯器打開此文件(直接編輯二進制文件),然後在Windows服務中重新啓動Oracle服務器即可。 
現在的狀況非常好,問題正在逐步的好轉之中,不過系統的性能還是非常的差,網頁的訪問速度很糟糕。到安裝Oracle的Win2003服務器上檢查了一下Oracle服務器,發現硬盤的佔用率很高,基本一致是100% 使用的狀況。進入Oracle中進行分析,發現有兩條SQL語句非常佔用系統的資源,是造成瓶頸的兩個SQL。 
於是對於原先使用trim的SQL進行優化 
由於trim命令會造成大量的硬盤讀寫(使用trim後造成索引無效),所以把所有使用trim命令的語句修改爲使用rpad命令。 
例如: 
select sfzh from qjgkXSK where trim(sfzh)=:1 
改爲 
select sfzh from qjgkXSK where sfzh=:rpad(1) 

對於表結構的建議:表結構中如果長度小於200的字段,建議使用char類型,而不是Varchar類型。 

然後發現在生成一個唯一序列號的時候,程序中有一個鎖表的操作,造成一個最大的瓶頸。原先的做法是先是鎖住一個表,然後取得最大值,最後把最大值加一,寫入數據庫中。 
1. ps = conn.prepareStatement("LOCK TABLE "+Global.xsk+" IN EXCLUSIVE MODE"); 
2. ps.executeUpdate(); 
3. ps = conn.prepareStatement("select max(SNO) from "+Global.xsk+" where SNO is not null"); 
4. rs = ps.executeQuery(); 
5. rs.next(); 
6. if (rs.getString(1)!=null) 
7. { 
8. temp = Global.formatString(""+(Integer.parseInt(rs.getString(1))+1),"0",6); 
9. } 
10. else 
11. { 
12. temp = "000001"; 
13. } 

改進後的做法是加入一個ORACLE的自增1的sequence(Oracle和MySQL、DB2等不同,它沒有主鍵auto-increasement這種功能) 
1. ps = conn.prepareStatement("select seq_qjgksno.nextval from dual"); 
2. rs = ps.executeQuery(); 
3. rs.next(); 
4. temp = Global.formatString("" + (Integer.parseInt(rs.getString(1))), "0", 6); 


做完這些時候,感到系統的問題都解決了,不過後來的情況還是幾個小時會死機一次,這次是報一個Java虛擬機的錯誤,估計是因爲一開始別人裝的是1.5beta版的關係。 
總結一下這次的優化的經驗: 
1.要抓住事物的主要矛盾。其實一開始針對WEB服務器中的很多優化都是次要矛盾,當解決了最後的2個SQL語句的問題後,前面的很多問題都不會出現的,比如那個Linux 1024個默認打開文件數的問題,最後發現如果系統數據庫訪問的速度足夠快,根本不會有那麼多打開的文件數的,往往是大家用系統時很慢,所以造成了不斷用F5刷新,把Tomcat活活搞死。 
2.在這種很重要的場合下改動程序或者配置一定要謹慎謹慎再謹慎。我在修改Oracle的配置文件的時候,一開始沒有備份,以後那是一個文本文件,我就是直接開打修改一個數字而已。但是雖然用notepad打開的時候顯示出來的是文本,但是這個文件在被notepad打開時一些二進制的東西被破壞了,造成了Oracle服務器啓動不起來,那時候自己都要被嚇死了,還好有個同學的機器上也有Oracle9i,而且都是按照默認配置的,直接打電話叫他把那個文件通過MSN發了過來。如果沒有類似的文件,或者服務器裝的比較怪異,那麼就慘了,千古罪人的。後來我基本每做一個操作,都不圖快,而是隨時備份,做的比較穩健了。 
3.在改那個程序的時候不斷的有考生打電話來諮詢服務器的問題,那個時候壓力非常大,一定要頂住壓力,如果感覺吃不消了,不妨先休息下,然後效率可能會更加高。 
4.事前一定要做好測試工作。 
最後附上一些Linux中可能會在檢測性能時候用到的命令:A.察看某個進程打開的文件數:先用ps -aux找到pid,然後運行lsof -p %pid% wc -l 
B.察看80端口的連接數netstat -natgrep -i “80″wc -l

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