Bem, esta é uma dica que apesar de simples, muita gente não conhece. O Hibernate pode ser configurado para gerar estatísticas de uso da SessionFactory. Em meus projetos já é comum rodar estas estatísticas uma vez que o projeto entra em homologação e ate mesmo em produção. Estas estatísticas vão ajudá-lo em alguns pontos:
- Encontrar queries que podem estar consumindo muito tempo
- Identificar possíveis objetos que podem ser colocados em cache
- Verificar se os caches de 2nd level estão realmente sendo utilizados
- Identificar possíveis campos que podem ser definidos como índices em suas tabelas
Por maior que seja nosso esforço como arquitetos de software, é muito difícil prevermos quais consultas serão mais usadas, quais objetos deveremos manter em cache, e quando sua equipe for grande, por mais que você tente, peça, xingue, sempre vai existir um desenvolvedor que não executa as queries no Hibernate tools e verifica se o SQL gerado é realmente a versão mais otimizada. Se eu ganhasse 1 real para cada join desnecessário que já encontrei em queries de projetos quando faço revisão de código, eu provavelmente poderia adiantar minha aposentadoria.
Fica aqui então uma forma de como verificar as estatísticas do hibernate. A abordagem que vou adotar é de disponibilizar um ManagedBean que irá exportar como serviço o HibernateStatistics. Vamos lá.
A aplicação de exemplo a ser monitorada, é uma aplicação de aprovação de horas (usando seam + jbpm_ que foi demonstrada neste blog neste link
Primeiro precisamos da nossa interface de MBean:
package com.furiousbob.hibernate.stats; public interface HibernateStatsMBean { public void start() throws Exception; public void stop() throws Exception; public void create()throws Exception; public void destroy(); }
Bem, alguns poderão questionar aqui que poderíamos usar o ServiceMBeanSupport do JBoss, mas eu preferi manter a forma tradicional de mbeans
Agora nossa implementação:
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 | package com.furiousbob.hibernate.stats; import javax.management.MBeanServer; import javax.management.ObjectName; import javax.naming.InitialContext; import javax.persistence.EntityManager; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.jmx.StatisticsService; import org.jboss.mx.util.MBeanServerLocator; import org.jboss.system.ServiceMBeanSupport; public class HibernateStats implements HibernateStatsMBean { private final String SessionFactoryName = "java:/AprovacaoHorasSessionFactory"; public void start() throws Exception { InitialContext ctx = new InitialContext(); SessionFactory sessionFactory = (SessionFactory)ctx.lookup(SessionFactoryName); MBeanServer server = MBeanServerLocator.locateJBoss(); ObjectName on = new ObjectName("Hibernate:type=statistics,application=AprovacaoHoras"); StatisticsService service = new StatisticsService(); service.setSessionFactory(sessionFactory); server.registerMBean(service, on); } public void stop() throws Exception { MBeanServer server = MBeanServerLocator.locateJBoss(); ObjectName on = new ObjectName("Hibernate:type=statistics,application=AprovacaoHoras"); server.unregisterMBean(on); } public void create() throws Exception { } public void destroy() { } |
Como podem notar é realmente muito simples registrar o servico de stats do Hibernate. Note que estamos usando o nome da SessionFactory de forma fixa dentro do código, você poderia por exemplo, definir isto como um atributo de seu MBean de forma que este código possa ser usado em várias aplicações. O nome do MBean também reflete o nome da aplicação a ser monitorada, e é outro candidato a se tornar uma propriedade configurável.
A última parte de nosso exemplo é o arquivo jboss-service.xml que deve ser colocado na pasta META-INF de sua aplicação
1 2 3 4 5 6 7 8 | <?xml version="1.0" encoding="UTF-8"?> <server> <mbean name="MyApp:Hibernate=Stats" code="com.furiousbob.hibernate.stats.HibernateStats"> <depends>jboss:service=Naming</depends> <depends>persistence.units:ear=AprovacaoHoras.ear,unitName=AprovacaoHoras</depends> </mbean> </server> |
Este arquivo irá informar que nosso Mbean possui uma dependência com a PersistenceUnit. E esta também deve sofrer uma pequena modificação, devemos adicionar as propriedades abaixo em nosso arquivo de configuração de persistencia:
<property name="hibernate.generate_statistics" value="true"/> <property name="hibernate.session_factory_name" value="java:/AprovacaoHorasSessionFactory"/>
Agora precisamos de empacotar nossas classes como um Service ARchive (SAR). Um SAR é nada mais que um JAR com o jboss-service.xml em seu META-INF. Ao final da operação você deverá ter um arquivo SAR com a seguinte estrutura:
vinicius@cybertron:~/workspace/HibernateStats/dist$ jar -tvf HibernateStats.sar
0 Wed Mar 04 09:09:40 BRT 2009 META-INF/
106 Wed Mar 04 09:09:38 BRT 2009 META-INF/MANIFEST.MF
305 Wed Mar 04 09:02:46 BRT 2009 META-INF/jboss-service.xml
0 Wed Mar 04 09:03:02 BRT 2009 com/
0 Wed Mar 04 09:03:02 BRT 2009 com/furiousbob/
0 Wed Mar 04 09:03:02 BRT 2009 com/furiousbob/hibernate/
0 Wed Mar 04 09:03:02 BRT 2009 com/furiousbob/hibernate/stats/
2082 Wed Mar 04 09:03:34 BRT 2009 com/furiousbob/hibernate/stats/HibernateStats.class
290 Wed Mar 04 09:03:02 BRT 2009 com/furiousbob/hibernate/stats/HibernateStatsMBean.class
Agora, acesse seu jmx-console de você deverá encontrar uma tela contendo um link para seu novo mbean. Existem dois mebans novos o primeiro:
AprovacaoHoras:Hibernate=Stats é o seu MBean que registra o serviço de stats
Hibernate:application=AprovacaoHoras,type=statistics: é o serviço de stats que você poderá coletar as métricas
Pronto, agora basta acessar o serviço e começar a coletar algumas métricas de seu Hibernate.
Aproveitem

