By Benny.luo@Sun.com, 6/19/07 |
![]() |
SUN中國軟件技術中心 羅浩/Benny Luo
簡介:
JDK 5.0, 代號老虎,在以往的Java傳統上加入了許多新的設計,給Java語言帶來了一些較大的變化,比如泛型,元數據,可變個數參數,靜態導入類,新線程架構,自動裝箱/拆箱等等新的以往沒有的新特性。同時,在調試程序和解決性能各種問題方面,JDK5.0同樣加入了多個分析工具來讓開發者更加方便地調試他們自己的程序,它們包括了命令行調試工具,圖形界面調試工具等等.
每一個請求的響應時間大概去到8-9秒時間,這個是客戶所不能接受的。
和應用的開發人員交流后,發現這些有問題的程序,都是和論壇系統中Socket調用有關,當用戶打開一個頁面是,頁面中的用戶信息需要同過Socket的方式調用相冊那邊的數據,這個操作存在bug,經過用戶的重新同步更新程序,問題解決。
JDK5.0包括的調試工具:
我們在這里對JDK5.0的調試工具做大致的概念性的介紹,然后希望通過介紹我自己在實際工作中使用這些工具解決問題的實例來讓大家對這些工具有更深入的了解。
JDK5.0里面加入了jstack, jconsole, jinfo, jmap, jdb, jstat, jps, 下面對這些工具做簡單介紹:
- jstack -- 如果java程序崩潰生成core文件,jstack工具可以用來獲得core文件的java stack和native stack的信息,從而可以輕松地知道java程序是如何崩潰和在程序何處發生問題。另外,jstack工具還可以附屬到正在運行的java程序中,看到當時運行的java程序的java stack和native stack的信息, 如果現在運行的java程序呈現hung的狀態,jstack是非常有用的。目前只有在Solaris和Linux的JDK版本里面才有。
- jconsole – jconsole是基于Java Management Extensions (JMX)的實時圖形化監測工具,這個工具利用了內建到JVM里面的JMX指令來提供實時的性能和資源的監控,包括了Java程序的內存使用,Heap size, 線程的狀態,類的分配狀態和空間使用等等。
- jinfo – jinfo可以從core文件里面知道崩潰的Java應用程序的配置信息,目前只有在Solaris和Linux的JDK版本里面才有。
- jmap – jmap 可以從core文件或進程中獲得內存的具體匹配情況,包括Heap size, Perm size等等,目前只有在Solaris和Linux的JDK版本里面才有。< /li>
- jdb – jdb 用來對core文件和正在運行的Java進程進行實時地調試,里面包含了豐富的命令幫助您進行調試,它的功能和Sun studio里面所帶的dbx非常相似,但 jdb是專門用來針對Java應用程序的。
- jstat – jstat利用了JVM內建的指令對Java應用程序的資源和性能進行實時的命令行的監控,包括了對Heap size和垃圾回收狀況的監控等等。
- jps – jps是用來查看JVM里面所有進程的具體狀態, 包括進程ID,進程啟動的路徑等等。
另外,還有些其他附帶的工具在這里沒有列出,比如Heap Analysis Tool, kill -3 方法等等,這些在JDK5.0之前就有,同樣也是非常有用的性能調優工具,大家可以參照相應的文檔資料來學習,在文章后面也會推薦一些相應的文檔給大家作為參考。
好,說了這么多,讓我們來看看JDK5.0自帶的這些工具在現實工作能給我們帶來什么幫助,下面是我和ISV一起共同工作的實際例子,在這里把它們簡單闡述出來,希望對大家有所幫助。
jconsole和jstack使用實例:
在做過的項目中,曾經有幾個是使用jstack和jconsole來解決問題的。在下面的例子中,由于部分代碼涉及到公司名字,我使用了xxx來代替。
1. 其中的一個是Web2.0的客戶,由于目前Sun Microsystem公司推出的Niagara服務器系列非常適合網絡方面的多線程應用,并且已經在業界非常出名,所以他們決定使用T2000服務器來測試一下如果應用到他們自己的應用是否能夠獲得出眾的性能。
整個應用的架構如下:Apache 2.0.59 + Resin EE 2.1.17 + Jdk 1.5.0.07 + Oracle 9
運行的操作系統:Solaris 10 Update 3 (11/06), EIS patches包.
測試工具:Apache benchmark tool.
在客戶的測試環境中,我們分別做了Apache, Resin, Solaris的相應調整,其中包括了Apache使用Prefork模式,并且調整了httpd.conf文件里面相應的ServerLimit, ListenBacklog,Maxclient等等值,Resin服務器調整Jvm heap size, 并行回收new generation和old generation, 最大線程數,oracle連接數等等參數,Solaris操作系統做了網絡和系統的相應調整,最終把整套系統搬進了生產環境,一切順利進行,但當進入其中的一個論壇系統時卻發現系統響應時間非常緩慢,用Apache Benchmark Tool加少量壓力得到結果如下,由于是在生產環境下所以不敢使用大的壓力:
This is ApacheBench, Version 2.0.41-dev <$Revision: 1.121.2.12 $> apache-2.0
Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright (c) 2006 The Apache Software Foundation, http://www.apache.org/Benchmarking free.xxx.com (be patient).....doneServer Software: Resin/2.1.17
Server Hostname: free.xxx.com
Server Port: 8080Document Path: /forum/bbsMessageList.act?bbsThreadId=1580107
Document Length: 27012 bytesConcurrency Level: 10
Time taken for tests: 92.148883 seconds
Complete requests: 100
Failed requests: 0
Write errors: 0
Keep-Alive requests: 0
Total transferred: 2722500 bytes
HTML transferred: 2701200 bytes
Requests per second: 1.09 [#/sec] (mean)
Time per request: 9214.888 [ms] (mean)
Time per request: 921.489 [ms] (mean, across all concurrent requests)
Transfer rate: 28.84 [Kbytes/sec] receivedConnection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.0 0 0
Processing: 9089 9187 139.4 9140 9789
Waiting: 3067 3163 138.3 3117 3766
Total: 9089 9187 139.4 9140 9789Percentage of the requests served within a certain time (ms)
50% 9140
66% 9178
75% 9189
80% 9201
90% 9281
95% 9560
98% 9739
99% 9789100% 9789 (longest request)
每一個請求的響應時間大概去到8-9秒時間,這個是客戶所不能接受的。
這時我們決定采用JDK5.0自帶的jstack來進行trouble-shoot,首先重新做加壓測試,并行請求為10個,總共100個請求,這時對Resin服務器所起的Java進程間隔10秒用jstack做一次采集工作。為什么要間隔10秒?主要是想看看在這三十秒內Java進程是否都阻塞在同一個地方。結果如下:
大部分的線程都阻塞在同一個java stack上面:
Thread t@38: (state = BLOCKED)- java.lang.Object.wait(long) @bci=0 (Interpreted frame)
- java.lang.Object.wait(long) @bci=0 (Interpreted frame)
- com._xxx.vportal.common.rpc.session.RemoteServiceGroupFactory.getMaxBalanceFactoryEntry() @bci=165,
line=180 (Interpreted frame)
- com._xxx.vportal.common.rpc.session.RemoteServiceGroupFactory.getService() @bci=80, line=195 (Interpreted
frame)
- com._xxx.vportal.common.rpc.session.RemoteServiceFactory.getSynSender() @bci=1, line=331 (Interpreted
frame)
- com._xxx.vportal.common.rpc.session.RemoteServiceSupport.synRequestHardTask(java.lang.String,
java.lang.Object) @bci=6, line=35 (Interpreted frame)
- com._xxx.vportal.amus.user.client.UserClientRpcImpl.getIconSigner(int, int) @bci=36, line=90 (Interpreted frame)
- net._xxx.forum.model.user.UserInfo.getLogoPath() @bci=109, line=546 (Interpreted frame)
- sun.reflect.GeneratedMethodAccessor13.invoke(java.lang.Object, java.lang.Object[]) @bci=36 (Interpreted frame)
- sun.reflect.DelegatingMethodAccessorImpl.invoke(java.lang.Object, java.lang.Object[]) @bci=6, line=25
(Compiled frame)
- org.apache.velocity.runtime.parser.node.ASTReference.execute(java.lang.Object,
org.apache.velocity.context.InternalContextAdapter) @bci=40, line=207 (Compiled frame)- org.apache.velocity.runtime.parser.node.ASTBlock.render(org.apache.velocity.context.InternalContextAdapter,
java.io.Writer) @bci=18, line=94 (Compiled frame)- org.apache.velocity.runtime.parser.node.SimpleNode.render(org.apache.velocity.context.InternalContextAdapter,
java.io.Writer) @bci=18, line=271 (Interpreted frame)-
org.apache.velocity.runtime.parser.node.ASTIfStatement.render(org.apache.velocity.context.InternalContextAdapter,
java.io.Writer) @bci=63, line=128 (Interpreted frame)- org.apache.velocity.runtime.parser.node.ASTBlock.render(org.apache.velocity.context.InternalContextAdapter,
java.io.Writer) @bci=18, line=94 (Compiled frame)- org.apache.velocity.runtime.directive.Foreach.render(org.apache.velocity.context.InternalContextAdapter,
java.io.Writer, org.apache.velocity.runtime.parser.node.Node) @bci=95, line=344 (Interpreted frame)- org.apache.velocity.runtime.parser.node.ASTDirective.render(org.apache.velocity.context.InternalContextAdapter,
java.io.Writer) @bci=14, line=153 (Interpreted frame)- org.apache.velocity.runtime.parser.node.SimpleNode.render(org.apache.velocity.context.InternalContextAdapter,
java.io.Writer) @bci=18, line=271 (Interpreted frame)- org.apache.velocity.app.Velocity.evaluate(org.apache.velocity.context.Context, java.io.Writer, java.lang.String,
java.io.Reader) @bci=102, line=359 (Interpreted frame)- org.apache.velocity.app.Velocity.evaluate(org.apache.velocity.context.Context, java.io.Writer,
java.lang.String, java.lang.String) @bci=18, line=253 (Interpreted frame)- net._xxx.forum.util.velocity.VelocityUtil.getVelocityEvaluate(java.util.Map, java.io.Writer,
java.lang.String) @bci=14, line=35 (Interpreted frame)
- net._xxx.forum.action.forum.BbsMessageListAction.go() @bci=1284, line=268 (Interpreted
frame)
–
net._xxx.forum.action.AbstractAction.execute() @bci=1, line=39 (
–
..............
和應用的開發人員交流后,發現這些有問題的程序,都是和論壇系統中Socket調用有關,當用戶打開一個頁面是,頁面中的用戶信息需要同過Socket的方式調用相冊那邊的數據,這個操作存在bug,經過用戶的重新同步更新程序,問題解決。
解決后的實測的數據如下, 效果非常理想:
This is ApacheBench, Version 2.0.41-dev <$Revision: 1.121.2.12 $> apache-2.0
Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright (c) 2006 The Apache Software Foundation, http://www.apache.org/Benchmarking free.xxx.com (be patient)
Completed 5000 requests
Completed 10000 requests
Completed 15000 requests
Completed 20000 requests
Completed 25000 requests
Completed 30000 requests
Completed 35000 requests
Completed 40000 requests
Completed 45000 requests
Finished 50000 requests
Server Software: Apache/2.0.59
Server Hostname: free.xxx.com
Server Port: 80Document Path: /forum/bbsMessageList.act?bbsThreadId=1581280
Document Length: 27508 bytes
Concurrency Level: 30
Time taken for tests: 252.583749 seconds
Complete requests: 50000
Failed requests: 0
Write errors: 0
Total transferred: 1384158363 bytes
HTML transferred: 1375408188 bytes
Requests per second: 197.95 [#/sec] (mean)
Time per request: 151.550 [ms] (mean)
Time per request: 5.052 [ms] (mean, across all concurrent requests)
Transfer rate: 5351.56 [Kbytes/sec] receivedConnection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.4 0 11
Processing: 45 150 154.1 117 4349
Waiting: 41 145 153.7 112 4346
Total: 45 150 154.1 117 4349
Percentage of the requests served within a certain time (ms)
50% 117
66% 142
75% 163
80% 180
90% 241
95% 321
98% 478
99% 764
100% 4349 (longest re
2. 另外的一個是最近做的,我們有個教育行業方面的ISV上來實驗室做T2000的Benchmark實驗,我們花了一天的時間部署整個架構,包括安裝Solaris操作系統,應用服務器,數據庫。& amp; amp; lt; /div>
整個應用的架構如下:Tomcat + Jdk 1.5 + Oracle 10g
運行的操作系統:Solaris 10 Update 3 (11/06), EIS patches包.
測試工具:LoadRunner 8.1
在實驗的初段,Tomcat, Oracle 10g服務器都是架設在T2000上,我們在對T2000服務器的OS,網絡,應用服務器做了必要的調整后,發現其表現還是不盡如人意。& #160;
我們使用Loadrunner做測試,用戶上到了100個同時并發10個迭代時已經出現問題,有許多的請求都被阻塞住,不能正常地進行。
這時我們決定使用jconsole和jstack來看看系統出現了什么問題。
A. 首先我們需要在Tomcat的啟動腳本catalina.sh里面加入JVM選項:
Dcom.sun.management.jmxremote把tomcat服務器java進程置于JDK5.0的性能監控范圍之內。B. 然后我們用jconsole連接到tomcat服務器的java進程,發現基本上Heap size, 垃圾回收都比較正常,但發現tomcat服務器的大部分線程有問題,都處于被Block的狀態。
觀察每條線程的stack trace, 發現它們基本上都被堵塞在uk.org.primrose.pool.core.Pool.put和uk.org.primrose.pool.core.Pool.get()的SyncHack同步機制上,我們嘗試了改大數據連接池的大小,發現結果是一樣的。
C.這個結論在jstack的結果中同樣得到了驗證,使用jstack連接到tomcat服務器java進程,并觀察結果。
D. 最后我們決定用tomcat服務器的連接池配置來代替Primrose數據庫連接池,更改以后,發現結果比較理想。
E. 后來,我們把Oracle數據庫建立在另外的一臺服務器X4200上,而Tomcat應用服務器依然放在T2000上,使用千兆網絡交換機,同樣地,使用Tomcat服務器自己的連接池配置表現較為理想。
以上兩個是我對JDK5.0工具的一些實際操作的例子,在這里和大家分享一下,希望對大家有所幫助。而Sun Microsystem公司也在不斷地完善JDK,在新的JDK版本里面加入越來越多的實用的方便開發者開發和調試的新特性,比如在最新的JDK6.0里面就內嵌了Dtrace里面許多關于Java程序中內存,方法,線程等等新的探針,通過這些探針和Dtrace,我們可以更加方便地調試Java程序。
文檔資料:
http://java.sun.com/j2se/1.5/pdf/jdk50_ts_guide.pdf
http://developers.sun.com.cn/home/export/sites/default/home/ISVs/docs/docs/thead.html
http://java.sun.com/j2se/1.5.0/docs/guide/management/jconsole.html
http://java.sun.com/docs/hotspot/gc5.0/ergo5.html#0.0.Behavior%20based%20tuning%7Coutline
http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html
http://java.sun.com/
http://www.java.net/
http://developers.sun.com.cn/home/export/sites/default/home/ISVs/docs/docs/thead.html
http://java.sun.com/j2se/1.5.0/docs/guide/management/jconsole.html
http://java.sun.com/docs/hotspot/gc5.0/ergo5.html#0.0.Behavior%20based%20tuning%7Coutline
http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html
http://java.sun.com/
http://www.java.net/