Energy of Love  
          日歷
          <2010年7月>
          27282930123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567
          統計
          • 隨筆 - 70
          • 文章 - 0
          • 評論 - 80
          • 引用 - 0

          導航

          常用鏈接

          留言簿

          隨筆分類

          隨筆檔案

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

           
          /**
          *作者:張榮華(ahuaxuan)
          *2007-8-15
          *轉載請注明出處及作者
          */

          前兩天在看Spring內置的攔截器的時候,發現了一個之前沒有注意的類:org.springframework.aop.interceptor.JamonPerformanceMonitorInterceptor,好奇心促使我上網查了一下這個jamon。大概看了一下之后發現這個玩意還真挺好用的而且挺重要的,而且現在國內對它的介紹也很少,所以寫了一篇文章和大家分享。

          一,Jamon簡介:
          Jamon的全名是:Java Application Monitor。它是一個小巧的,免費的,高性能的,線程安全的性能監測工具。它可以用來測定系統的性能瓶頸,也可以用來監視用戶和應用程序之間的交互情況。 Jamon主要是用來檢測jee的應用程序。它最新的版本是2.1,可以用在1.4以上的jdk上。

          二,將jamon導入到你的應用程序中去
          首先下載jamon的開發包,見我的附件,同時你也可以去Sourceforge上自己下載。Sourceforge的下載地址為http://jamonapi.sourceforge.net。解壓之后可以得到一個jar包和一個war包。jar包是自己會用到的,而war包是一個例子(不要小看這個例子,待會也要把它導入到項目中)。把war包之間丟到服務器上,訪問:localhost:8080/jamon就可以看到這個例子了,這個例子是一個簡單的性能監控系統。

          接著把例子中的所有的包都導入到項目中,并把war包中的jsp和images還有css都考到項目中,比如新建一個目錄叫monitor(它和WEB-INF是同級目錄)。

          三,正確配置自己的應用
          我們在性能監測的時候最監測的就是頁面的訪問率和類中方法的訪問率。所以在這一部分主要講解一下如何監測自己的頁面和類中方法的訪問。

          1, 檢測自己的頁面訪問率
          首先我們需要在web.xml中添加一個filter,這個filter就是用來判斷哪些頁面需要被監視的,如下所示:
          Java代碼 復制代碼
          1. <filter>   
          2.         <filter-name>JAMonFilter</filter-name>   
          3.         <filter-class>com.easywebwork.filter.EasyPageMonFilter</filter-class>   
          4.     </filter>   
          5.     <filter-mapping>   
          6.         <filter-name>JAMonFilter</filter-name>   
          7.         <url-pattern>/*</url-pattern>   
          8.     </filter-mapping>  
          接下來我們看看這個filter的寫法:
          Java代碼 復制代碼
          1. /**  
          2.  * @author 張榮華(ahuaxuan)  
          3.  *  
          4.  * @since 2007-8-13  
          5.  */  
          6. public class PageMonFilter extends JAMonFilter{   
          7.   
          8.     private static final long serialVersionUID = 5746197114960908454L;   
          9.   
          10.     public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {   
          11.          Monitor allPages = MonitorFactory.start(new MonKeyImp("org.easywebwork.allPages",getURI(request),"ms."));   
          12.          //這里就是我們要監視的所有的頁面的配置   
          13.          Monitor monitor = MonitorFactory.start(getURI(request));   
          14.          //這里就是我們要監視的某個頁面的配置   
          15.          try {   
          16.           filterChain.doFilter(request, response);   
          17.          } finally {   
          18.           monitor.stop();   
          19.           allPages.stop();   
          20.          }   
          21.        }   
          22.   
          23.        protected String getURI(ServletRequest request) {   
          24.          if (request instanceof HttpServletRequest) {   
          25.            return ((HttpServletRequest) request).getRequestURI();   
          26.          }  else {   
          27.            return "Not an HttpServletRequest";   
          28.          }   
          29.        }   
          30.   
          31.        private FilterConfig filterConfig = null;   
          32.           
          33. }}  

          這個類看上去很簡單,其實也挺簡單的,就是得到uri,然后把它注冊到MonitorFactory類中。這樣只要我們去訪問剛才創建的monitor目錄下的jsp就可以看到性能監測頁面了。

          2, ,接下來我們看看在使用spring的情況下如何監測一個bean的方法調用。Spring也提供了對Jamon的支持(spring支持的東西還真多啊),也就是文章開頭提出的那個攔截器,為了給我們的bean加上攔截器,我們在spring的applicationcontext配置文件中加入如下語句:
          Java代碼 復制代碼
          1. <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">   
          2.         <property name="beanNames">   
          3.             <list>   
          4.                 <value>userService</value>                 
          5.             </list>   
          6.         </property>   
          7.         <property name="interceptorNames">   
          8.             <list>   
          9.                 <value>jamonInterceptor</value>   
          10.             </list>   
          11.         </property>   
          12.     </bean>   
          13.        
          14.     <bean id="jamonInterceptor" class="org.springframework.aop.interceptor.JamonPerformanceMonitorInterceptor">   
          15. </bean>  

          上面這個是典型的spring的aop的配置,如果對spring的aop配置不了解的可以去看一下spring中文文檔,當然如果不想了解的話即使直接把這段配置拷到自己的項目中也是可以直接使用的。

          還有一個步驟就是在你的log4j.properties中加入這句代碼:
          Java代碼 復制代碼
          1. log4j.logger.org.springframework.aop.interceptor.JamonPerformanceMonitorInterceptor = TRACE  

          如果沒有這一行,那么這個攔截器是不會把方法調用的信息向MonitorFactory注冊的。

          只需要這些步驟,userservice中的方法在調用的時候就可以被攔截,然后將其注冊到MonitorFactory中去了。

          所有的配置完成之后我們來看一下效果吧:
          http://www.javaeye.com/topics/download/b2bac96e-6c18-4340-b7e0-f84c7bb6adca從這個圖上我們可以看到,所有頁面被訪問的次數,UserService中的getAllUsers被調用的次數,最右邊的是訪問時間。這只是整個圖的一部分,當然這個頁面中也包括每一個頁面被訪問的次數和第一次訪問的時間等等。下載附件運行,就可以看到所有的頁面了。

          三,總結
          根據以上的步驟,我們就可以監測我們的程序了,應用程序中哪些頁面被訪問的多,哪些頁面被訪問的少,哪些方法被訪問的多,哪些方法被訪問的少,以及訪問高峰期集中在什么時間等等,有了這些參數,我們更可以有針對性的對應用程序進行優化了,比如說某個頁面訪問比較頻繁,我就可以用ehcache或oscache給這個頁面做一個緩存。如果某個方法的訪問比較頻繁那就看看這個方法能否進一步優化,是需要異步,還是需要緩存,還是需要其他等等,總之有了jamon可以給我們帶來更多的便捷,既可以讓我們知道我們的客戶的行為,也可以讓我們知道我們開發的程序的“能力”。

          其實本文提供的只是對頁面和方法調用的監控,但是jamon可以提供更多功能,比如說sql語句的監控等等,這就需要我們共同去發掘了。

          附件中包括了一個easywebwork的例子,我把jamon導入到這個例子工程中去,大家可以直接下載運行觀看效果。Easywebwork是一個旨在減少webwork2.2.x系列的xml配置文件的項目,
          如果對這個主題感興趣請到
          http://www.javaeye.com/topic/91614
          http://www.javaeye.com/topic/93814
          參加討論。





          之前有一篇文章講到如何使用jamon來監控請求以及方法得調用(原文地址見:[url]http://www.javaeye.com/post/354575 [/url]),本文屬于其姊妹篇,使用jamon監控系統的sql調用及其調用效率。

          需求:
          1我們知道在使用hibernate得時候,我們可以打開show sql選項,可以直接查看sql語句調用的情況,那么當我們使用其他持久技術的時候我們也需要這個功能怎么辦呢,沒有關系,jamon能夠幫我們做到。

          2 很多時候,不同的程序員會寫出不同的性能的sql,有時候可能會不小心或者因為不知道而寫出性能很差的sql,我自己曾經就發生過這種事情,在500w條數據的表里使用了一個limit來分頁,到后面,執行一條sql都需要幾分鐘,諸如此類的時候可能大家都有碰到過,如果能有監控sql性能的工具嵌在應用里該多好,當然有jamon就可以幫我們做到。

          對于jamon來說,每一個query的執行之后的統計結果都會被保存下來,這些概要統計都以MonProxy-SQL開頭。這些統計中包括查詢執行的時間,有比如平均時間,執行總時間,最小執行時間,最大執行時間,這些東西難道不是我們正想要的嗎。

          那么讓我們開始吧,我們知道,這些query執行的統計應該是在connection中被統計的,也就是說我們要代理一般的connection,而connection又是由datasource產生的,所以我們可以代理datasource,說干就干。

          一個datasource接口中關于connection的方法只有兩個:
          Java代碼 復制代碼
          1. /**  
          2.    * <p>Attempts to establish a connection with the data source that  
          3.    * this <code>DataSource</code> object represents.  
          4.    *  
          5.    * @return  a connection to the data source  
          6.    * @exception SQLException if a database access error occurs  
          7.    */  
          8.   Connection getConnection() throws SQLException;   
          9.          
          10.   /**  
          11.    * <p>Attempts to establish a connection with the data source that  
          12.    * this <code>DataSource</code> object represents.  
          13.    *  
          14.    * @param username the database user on whose behalf the connection is   
          15.    *  being made  
          16.    * @param password the user's password  
          17.    * @return  a connection to the data source  
          18.    * @exception SQLException if a database access error occurs  
          19.    * @since 1.4  
          20.    */  
          21.   Connection getConnection(String username, String password)    
          22.     throws SQLException;  

          也就是說我們只要override這兩個方法即可。
          根據這個思路我寫了以下代碼:
          Java代碼 復制代碼
          1. /**  
          2.  * @author ahuaxuan(aaron zhang)  
          3.  * @since 2008-2-25  
          4.  * @version $Id$  
          5.  */  
          6. public class MonitorDataSource implements DataSource {   
          7.     public DataSource realDataSource;   
          8.   
          9.     public void setRealDataSource(DataSource realDataSource) {   
          10.         this.realDataSource = realDataSource;   
          11.     }   
          12.   
          13.     public DataSource getRealDataSource() {   
          14.         return realDataSource;   
          15.     }   
          16.     public Connection getConnection() throws SQLException {   
          17. //表示由jamon來代理realDataSource返回的Connection   
          18.         return MonProxyFactory.monitor(realDataSource.getConnection());   
          19.     }   
          20.   
          21.     public Connection getConnection(String username, String password)   
          22.             throws SQLException {   
          23. //表示由jamon來代理realDataSource返回的Connection   
          24.   
          25.         return MonProxyFactory.monitor(realDataSource.getConnection(username,   
          26.                 password));   
          27.     }   
          28. }  

          顯然這個一個代理模式。接下來就是生成這個代理類,我是在spring中注冊了這么一個類:
          Java代碼 復制代碼
          1. <bean id="writeMonitorDataSource" class="org.ahuaxuan.MonitorDataSource" destroy-method="close">   
          2.         <property name="realDataSource" ref="writeDataSource"/>   
          3.     </bean>  


          writeMonitorDataSource 所依賴的writeDataSource就是我們真正配置的datasource,比如:
          Java代碼 復制代碼
          1. <bean id="writeDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">   
          2.         <property name="driverClassName">   
          3.             <value>${jdbc.driverClassName}</value>   
          4.         </property>   
          5.         <property name="url">   
          6.             <value>${jdbc.url}</value>   
          7.         </property>   
          8.         <property name="username">   
          9.             <value>${jdbc.username}</value>   
          10.         </property>   
          11.         <property name="password">   
          12.             <value>${jdbc.password}</value>   
          13.         </property>   
          14.         <property name="maxActive">   
          15.             <value>${jdbc.maxActive}</value>   
          16.         </property>   
          17.         <property name="maxIdle">   
          18.             <value>${jdbc.maxIdle}</value>   
          19.         </property>   
          20.         <property name="maxWait">   
          21.             <value>${jdbc.maxWait}</value>   
          22.         </property>   
          23. </bean>  

          好了,那么在使用datasource的時候,我們應該用哪個呢,當然是writeMonitorDataSource這個里,我們可以把它注入給jdbcTemplate,或者sessionfactory,或者其他需要用到datasource的地方。

          到這里,就一切準備完畢了,我們可以看看我們sql語句的執行效率了(這個頁面的地址為sql.jsp):
          見圖1
          當然要我們的應用能夠顯示這個頁面,我們需要把jamon的一組頁面拷到我們的應用中,這一組頁面包含在我提供下載的包中,最新的jamon版本是2.7。

          我們可以看到id為153的那條sql語句執行了78ms,我要去看看這條sql語句是不是有點什么問題或者是否有優化的可能性。

          當然,剛才說到每一條sql語句都是有統計平均時間,最大最小執行時間等等,沒錯,在另外一個頁面jamonadmin.jsp上就包含這些內容
          見圖2
                

          上面的圖片代表hits表示執行次數,avg表示sql執行的平均時間,后面的min和max表示sql執行的最小耗時和最大耗時。從這里我們能夠更直觀的看到我們每條sql語句執行的情況。很有用的一個功能。

          而且在上面那兩個頁面上,我們還可以選擇把sql執行的結果導出來,可以導成xml或excel格式。

          總結:使用jamon來監控我們的sql語句我覺得很有使用意義,而且使用jamon對我們的應用來說完全是松耦合的,根本不需要更改我們的業務邏輯代碼,完全是可插拔的,我們也可以開發時使用jamon,部署時拔掉jamon。有了它能夠使一些程序員能夠更多一點的關注自己所寫的sql的效率,當然如果之前開發的時候沒有使用jamon也沒有關系,即使上線后也可以查看一下sql語句是否有問題,比如哪些sql語句執行得比較頻繁,是否存在給其做緩存得可能性等等。總之使用jamon在應用程序中來監控我們得sql語句具有很強得實用意義,

          再次總結:jamon,很好,很強大。
          posted on 2010-07-28 16:06 不高興 閱讀(2090) 評論(0)  編輯  收藏 所屬分類: JavaSpring
           
          Copyright © 不高興 Powered by: 博客園 模板提供:滬江博客
          主站蜘蛛池模板: 临朐县| 嘉祥县| 凤城市| 沭阳县| 广安市| 洪洞县| 永定县| 普兰县| 张北县| 长葛市| 沈丘县| 剑河县| 牟定县| 和静县| 凉山| 曲麻莱县| 碌曲县| 水富县| 马鞍山市| 平潭县| 繁峙县| 大同市| 石景山区| 鸡泽县| 定州市| 宜城市| 吐鲁番市| 盈江县| 武邑县| 台南市| 分宜县| 兰州市| 隆化县| 潍坊市| 南岸区| 宜川县| 特克斯县| 拜泉县| 徐汇区| 屏南县| 丹东市|