Software development is much more than just coding application by requirements and deploying it to production as the real work really starts after it has been shipped: maintenance, improvements and problem solving. And for that it's good to have some data. It's said "if you can't measure it, you can't improve it" and in ideal situations you plan for measuring your app but often you have to do it in production to detect and diagnose performance problems. There are different ways to measure a Java EE application and one good tool to achieve performance and monitoring statistics is Javamelody which has low overhead, is non-intrusive, informative and simple to setup but still very capable.
"If you can not measure it, you can not improve it." - Lord Kelvin
Application performance can be measured by two main methods: computational resources used by the application and the performance as seen by a user of the application. By measuring these quantities we get an empirical performance baseline of the application which then can used to detect changes in performance. By using performance monitoring, which is an act of non-intrusively collect or observe performance data from running application, we get measurements to identify or isolate potential issues from real operation of an application without having a severe impact on runtime responsiveness or throughput.
There are different ways to achieve performance and monitoring statistics and it's useful to plan for measuring application's performance while still in development as later on you surely want to know how it is performing. You can do it by leveraging different JMX-based tools like Metrics and Servo but if you didn't really plan for it you still have choices. You can use tools like standard JDK tools (jconsole, jstat, jmap, jstack, hprof) for low level JVM monitoring or some monitoring application like Javamelody. And as time is always scarce in development it's useful to deploy a tool like JavaMelody which provide quick and easy access to performance monitoring. But if you are interested of some narrow focus measurement you're better of with some custom tool.
Monitoring with JavaMelody
JavaMelody is an open source (LGPL) application to monitor Java or Java EE application servers in QA and production environments. It is a tool to measure and calculate statistics on real operation of an application depending on the usage of the application by users and is mainly based on statistics of requests and on evolution charts which can be viewed on the current day, week, month, year or custom period. The statistics can be viewed on a HTML page and sent as PDF reports by email.
JavaMelody lists the following use cases:
- It allows to improve applications in QA and production
- Give facts about the average response times and number of executions
- Make decisions when trends are bad, before problems become too serious
- Optimize based on the more limiting response times
- Find the root causes of response times
- Verify the real improvement after optimization
Setting up JavaMelody is quite easy and the needed steps are covered in User guide. Integrating JavaMelody to your application can be done in less than 10 minutes, by automatic discovery of environment: it only requires to copy 2 jar files and to add 10 lines in a xml file. But for more detailed and wider measurements you need couple more lines to xml files and here are the changes I made for our Wicket, Spring, JPA, Hibernate -Java EE project.
JavaMelody and dependencies
Getting JavaMelody and it's dependencies is easy with Maven2 and you just need to add javamelody-core and if you want to have PDF reports also iText in your pom.xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
<!-- javamelody-core --> <dependency> <groupId>net.bull.javamelody</groupId> <artifactId>javamelody-core</artifactId> <version>1.45.0</version> </dependency> <!-- itext, option to add PDF export --> <dependency> <groupId>com.lowagie</groupId> <artifactId>itext</artifactId> <version>2.1.7</version> <exclusions> <exclusion> <artifactId>bcmail-jdk14</artifactId> <groupId>bouncycastle</groupId> </exclusion> <exclusion> <artifactId>bcprov-jdk14</artifactId> <groupId>bouncycastle</groupId> </exclusion> <exclusion> <artifactId>bctsp-jdk14</artifactId> <groupId>bouncycastle</groupId> </exclusion> </exclusions> </dependency>
JavaMelody needs just a monitoring filter before the description of webapp's servlet in WEB-INF/web.xml or not even that as described in the User guide. But usually you want a little bit more than the minimum 10 additional lines in web.xml.
By adding the customResourceFilter you get customized look & feel, you can exclude some urls from statistics with url-exclude-pattern regular expression pattern, eamil-parameters are for weekly reports and by including monitoring-spring.xml you can monitor DataSource with a Spring post-processor and objects initialized with Spring.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
... <context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:net/bull/javamelody/monitoring-spring.xml classpath:applicationContext-service.xml classpath:applicationContext-persist.xml classpath:applicationContext-web.xml classpath:applicationContext-security.xml </param-value> </context-param> <!-- Must be defined before javamelody filters --> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!--====================== Monitoring ===================================--> <!-- Custom CSS --> <filter> <filter-name>customResourceFilter</filter-name> <filter-class>net.bull.javamelody.CustomResourceFilter</filter-class> <init-param> <param-name>monitoring.css</param-name> <param-value>/styles/monitoring.css</param-value> </init-param> </filter> <filter-mapping> <filter-name>customResourceFilter</filter-name> <url-pattern>/monitoring</url-pattern> </filter-mapping> <!-- Monitor filter --> <filter> <filter-name>monitoring</filter-name> <filter-class>net.bull.javamelody.MonitoringFilter</filter-class> <init-param> <param-name>storage-directory</param-name> <param-value>logs/monitoring</param-value> </init-param> <init-param> <param-name>url-exclude-pattern</param-name> <param-value>(/images/.*|/js/.*|/styles/.*)</param-value> </init-param> <init-param> <param-name>admin-emails</param-name> <param-value>firstname.lastname@example.org</param-value> </init-param> <init-param> <param-name>mail-session</param-name> <param-value>MailSession</param-value> </init-param> <init-param> <param-name>mail-periods</param-name> <param-value>week,month</param-value> </init-param> </filter> <filter-mapping> <filter-name>monitoring</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <listener> <listener-class>net.bull.javamelody.SessionListener</listener-class> </listener> ...
Spring Security config
For restricting the access to monitoring statistics I added the following to the Spring Security's applicationContext-security.xml. There are also other options for security. The key point here is to make sure, that the monitoring-filter in web.xml (above) is defined after the Spring Security filter chain.
1 2 3 4 5 6
<http auto-config="true" use-expressions="true"> ... <intercept-url pattern="/monitoring/**" access="hasRole('ROLE_ADMIN')" /> <intercept-url pattern="/**" access="hasAnyRole('ROLE_ADMIN, 'ROLE_USER'')" /> </http>
Monitoring SQL and datasources
For monitoring datasources and SQL I just added jndi-lookup to applicationContext-persist.xml. Other options to enable JDBC monitoring are described in the User guide.
1 2 3 4 5 6 7
... <jee:jndi-lookup id="dataSource" jndi-name="jdbc/myAppDS"/> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource" /> ...
Business facades (Spring)
If the application to monitor contains some objects initialized by Spring, EJB or Guice their methods execution can also be added to statistics. As described in the User guide for monitoring Spring Business facades there are couple of options and for example with JdkRegexpMethodPointcut in applicationContext-web.xml you can catch objects with regular expression like "all that have Service in their names".
1 2 3 4 5 6 7 8 9
... <bean id="facadeMonitoringAdvisor" class="net.bull.javamelody.MonitoringSpringAdvisor"> <property name="pointcut"> <bean class="org.springframework.aop.support.JdkRegexpMethodPointcut"> <property name="pattern" value=".*Service.*" /> </bean> </property> </bean> ...
If you want to see also EHCache statistics add statistics="true" to ehcache.xml config file.
1 2 3 4 5
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"> <defaultCache eternal="true" maxElementsInMemory="100" overflowToDisk="false" statistics="true" /> <cache name="fooCache" maxElementsInMemory="1000" eternal="false" overflowToDisk="false" /> <cache name="barCache" maxElementsInMemory="1000" eternal="false" overflowToDisk="false" /> </ehcache>
Database information and statistics
JavaMelody already shows datasource and SQL information but it's also possible to display information and statistics on the database like the longest requests in cumulative time with display of the cpu time and of the elementary cost. For showing that information the user in the database used by the monitored application must have the necessary rights to read those information and statistics.
In Oracle database the request practically means
select * from v$session and you can grant access as 'system' user with
GRANT SELECT any dictionary TO myapplicationuser. Strangely granting just the select for v$session (
GRANT SELECT ON sys.v_$session TO myapplicationuser;) wasn't enough.
There is also a possibility to get weekly, daily or monthly report in pdf format sent by email to one or several people. It needs iText library for webapp and Java's JavaMail and Activation libraries in your server for the mail session.
With WebLogic you add some email parameters in webapp's web.xml (above) and configure a Mail Session in WebLogic AdminServer: Services > Mail Sessions with JNDI Name and JavaMail properties. The report provides the same information you can find in monitoring web page with high and detailed level information.
Javamelody data is stored in files on disk and there are 2 types of files: *.rrd files for values in graphics in RRD format (using jrobin library) and *.ser.gz for values in statistics.
The performance statistics are stored to temp/javamelody directory by default which means /tmp/javamelody in Linux and in Windows when running webapp in Eclipse something like Users/developer/AppData/Local/Temp/javamelody. If you want to reset the counters just delete all the files. The location can be changed with storage-directory parameter and if the name of the directory starts with '/', it is considered as an absolute path, otherwise it is considered as relative to the temporary directory.
There is also option to use centralized collect server to store statistics and for monitoring of several applications.
Viewing performance monitoring
After you have set up your webapp to have the monitoring you can see statistics at URL like
http:// depending your configuration.
Some example JavaMelody statistics from development:
Monitoring and filtering doesn't come without costs and there has been discussions on JavaMelody wiki about the overhead the monitoring does. It is said that the overhead is so low that it can be enabled continuously in Quality Assuarance environment and if no problem arises in QA, also continuously in production environment. And with little overhead you will be able to know what needs optimizing in the QA or production servers so that the overhead of JavaMelody will practically be negative.
The discussion contained some notes:
- Architecture of JavaMelody is lightweight so it has a lower overhead as compared it to other available solutions
- It is only statistics and not events so the overhead of memory is quite minimal.
- It does monitoring not profiling: there is no instrumentation of classes and instead "interceptors" for http, jdbc, spring or ejb3.
- No database and no recording of each events even in a file or over the wire: only statistics of requests are kept. The overhead of cpu is minimal with no I/O on the wire and minimal I/O on disk (just to take a backup of statistics at a regular interval). The overhead of some other good monitoring solutions is in the recording of each event in a database or in a master server.
- You have the choice to use centralized collect server which unloads the memory, the backup storage and the generation of reports to another server while adding I/O on the wire for sending deltas of the statistics.
"If you can not measure it, you can not improve it." It doesn't matter how you do it but if you want to use real user data and environment just do it non-intrusively with performance monitoring tools like Javamelody.