Archive for the ‘JBoss’ category

jboss.management.local:* already registered

March 28th, 2012

A exceção é da forma:

javax.management.InstanceAlreadyExistsException: jboss.management.local:<MBEAN NAME> already registered.
        at org.jboss.mx.server.registry.BasicMBeanRegistry.add(BasicMBeanRegistry.java:756)
        at org.jboss.mx.server.registry.BasicMBeanRegistry.registerMBean(BasicMBeanRegistry.java:233)
        at sun.reflect.GeneratedMethodAccessor107.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:157)
        at org.jboss.mx.server.Invocation.dispatch(Invocation.java:96)
        at org.jboss.mx.interceptor.AbstractInterceptor.invoke(AbstractInterceptor.java:138)
        at org.jboss.mx.server.Invocation.invoke(Invocation.java:90)
        at org.jboss.mx.interceptor.ModelMBeanOperationInterceptor.invoke(ModelMBeanOperationInterceptor.java:140)
        at org.jboss.mx.server.Invocation.invoke(Invocation.java:90)

O JBoss, atendendo à JSR-77, registra sobre o domínio jboss.management.local todos os pacotes deployados. O problema ocorre quando dois pacotes com o mesmo nome estão presentes. A princípio isso nunca aconteceria, os OS não permitem isso. Mas o JBoss tem a capacidade de fazer deploy de pastas aninhadas, além de poder ser configurado para possuir várias pastas de deploy.

Então a solução mais simples seria alterar o nome dos pacotes (pode ser também uma Persistence Unit ou qualquer outro deployable) conflitantes. Se essa não for uma opção, é possível também desabilitar a implementação JSR-77 do JBoss, que não deve trazer maiores consequências (a não ser que esses MBeans estejam sendo explicitamente usados).

Para tanto basta remover ou desabilitar (adicionando a extensão .rej) o arquivo $JBOSS_CONF/deployers/jsr77-deployers-jboss-beans.xml

Adicionando segurança ao JBoss Messaging

March 22nd, 2012

Nesse post quero falar de como prover segurança na troca de mensagens utilizando JBoss Messaging. Segurança é um conceito bem amplo. Em termos da mensagens, o que queremos é:

  • autenticidade: garantia de que a mensagem é de quem achamos que é;
  • integridade: garantia que a mensagem é a que foi escrita originalmente;
  • confidencialidade: garantia que a mensagem não foi lida por mais ninguém.

Também não queremos que qualquer consumidor leia da fila. Portanto, além de todas essas garantias, vamos adicionar autenticação e autorização para restringir o acesso ao nosso provedor JMS.

Como alguns já devem ter notado, grande parte dos nossos requisitos são atendidos utilizado-se Certificados Digitais. E é justamente o que vamos usar.

Utilizando um canal SSL para envio de mensagens

O JBoss Messaging (JBM) utiliza um subprojeto da JBoss chamado JBoss Remoting para comunicação de rede. Para utilizarmos SSL, basta configurar o conector do JBoss Remoting para utilizar um socket SSL. Para nossa sorte a equipe da JBoss já fez isso para nós, basta copiar o arquivo $JBOSS_HOME/docs/examples/jms/remoting-sslbisocket-service.xml para a pasta de deploy.

Será preciso criar um Keystore $JBOSS_HOME/server/default/conf/messaging.keystore com a par de chaves e o certificado. Se o certificado for auto-assinado, será também preciso adicioná-lo Truststore do cliente. A senha do Keystore deve ser “secureexample”.

Para produção é possível alterar configurações de keystore e senha no MBean org.jboss.remoting.security.SSLSocketBuilder, dentro do arquivo remoting-sslbisocket-service.xml que copiamos.

Feito isso, vamos criar um ConnectionFactory que utilize esse conector. Dentro de deploy, crie um arquivo messaging-secure-socket-service.xml:

<?xml version="1.0" encoding="UTF-8"?>
<server>
   <mbean code="org.jboss.jms.server.connectionfactory.ConnectionFactory"
          name="jboss.messaging.destination:service=SecureConnectionFactory"
          xmbean-dd="xmdesc/ConnectionFactory-xmbean.xml">
 
      <depends optional-attribute-name="ServerPeer">jboss.messaging:service=ServerPeer</depends>
      <depends optional-attribute-name="Connector">jboss.messaging:service=Connector,transport=sslbisocket</depends>
 
      <attribute name="JNDIBindings">
         <bindings>
            <binding>/SecureConnectionFactory</binding>
         </bindings>
      </attribute>
   </mbean>
</server>

Note que o atributo Connector possui o Name do MBean que utiliza o conector SSL. Estamos informando para o JBoss que esse ConnectionFactory deve utilizar um canal SSL. Sempre que o client utilizar um ConnectionFactory obtido pelo lookup de “/SecureConnectionFactory” estará se comunicando em um canal encriptado.

NOTA: cuidado para não utilizar binds JNDI padrões do JBM, definidos em connection-factories-service.xml. Eles usam o jboss.messaging:service=Connector,transport=bisocket, que não utiliza Certificado.

Configurando autenticação/autorização para filas

Para autenticar o client vamos utilizar usuário/senha. O JBM por padrão utiliza o Security Domain “messaging” definido em messaging-jboss-beans.xml, que utiliza datasource DefaultDS. Nesse mesmo arquivo é possível alterar o Security Domain utilizado.

As definições de autorização devem ser feitas por fila. Ao definir uma fila, devemos fazê-lo da seguinte forma:

<?xml version="1.0" encoding="UTF-8"?>
<server>
   <mbean code="org.jboss.jms.server.destination.QueueService"
      name="jboss.messaging.destination:service=Queue,name=securityTestQueue"
      xmbean-dd="xmdesc/Queue-xmbean.xml">
 
      <depends optional-attribute-name="ServerPeer">jboss.messaging:service=ServerPeer</depends>
      <depends>jboss.messaging:service=PostOffice</depends>
      <attribute name="SecurityConfig">
         <security>
            <role name="guest" read="false" write="false" create="false" />
            <role name="publisher" read="true" write="true" create="true" />
         </security>
      </attribute>
   </mbean>
</server>

Note o atributo SecurityConfig. Acho que é tudo bem auto-explicativo, a não ser o create. Esse atributo se aplica a tópico e dá o privilégio do client criar uma subscrição DURABLE.

O para publicar na fila, o client deve obter uma conexão usando a chamada createConnection() que passa usuário e senha:

javax.jms.ConnectionFactory.createConnection(username, password);

NOTA: cuidado ao utilizar os arquivos *-persistence-service.xml que vêm de exemplo no JBoss. Alguns usuário padrões são definidos neles e podem ser utilizados para obter acesso privilegiado. Em um post anterior postei mais informações sobre o JBoss Messaging.

Criando um MDB para consumir

Para consumir mensagens autenticando-se e utilizando o ConnectionFactory sobre SSL, o MDB deve ser configurado com algumas propriedade a mais:

@MessageDriven(activationConfig =
{
   @ActivationConfigProperty(propertyName="destinationType", propertyValue="javax.jms.Queue"),
   @ActivationConfigProperty(propertyName="destination", propertyValue="queue/securityTestQueue"),
   @ActivationConfigProperty(propertyName="ConnectionFactoryName", propertyValue="SecureConnectionFactory"),
   @ActivationConfigProperty(propertyName="user", propertyValue="john"),
   @ActivationConfigProperty(propertyName="password", propertyValue="needle")
})
public class QueueConsumer implements MessageListener {
   public void onMessage(Message message) {
      System.out.println(this.getClass().getName() + " -> " + message);
   }
}

That’s it!

Medindo consecutivos tempos de subida do JBoss

December 5th, 2011

Estava com um problema que causava congelamentos de até 10 minutos nas máquinas do JBoss em um cliente. Estes congelamentos eram intermitentes e aconteciam sempre no boot do JBoss.

A fim de fazer testes com várias configurações diferentes e gerar um relatório com dados precisos, escrevi um script que executa o init script do JBoss, espera ele inicializar completamente, grava o tempo de inicialização e mata o processo. Faz isso 50 vezes.

Estou postando ele aqui na esperança de ser útil para mais alguém. Ele é bastante auto-explicativo:

#!/bin/bash
# Notes: all Java processes are going to the KILLED and
# previous probe.log ERASED!
 
JBOSS_LOG_FILE="/opt/jboss/server/default/log/server.log"
REPEAT=50
 
START_STRING="Started in"
RESULT_FILE="/root/probe.log-`date +%F`"
> $RESULT_FILE
 
for i in $(seq 1 $REPEAT); do
	# clean
	killall -9 java
	> $JBOSS_LOG_FILE
 
	# init and wait
	sh /etc/init.d/jboss start
	while [ "x$( grep "$START_STRING" $JBOSS_LOG_FILE )" == "x" ]; do
		sleep 1
	done
 
	# log
	cat $JBOSS_LOG_FILE | grep "$START_STRING" >> $RESULT_FILE
done
 
echo "Done"

Separando logs por aplicação no JBoss

October 20th, 2011

Separar logs de aplicações no JBoss é uma tarefa comum e existem alguns modos de fazer isso:

1. Adicionando uma Category ao $JBOSS_CONF/conf/jboss-log4j.xml pegando todos o package da aplicação e usando um Appender específico. Por exemplo:

   <category name="net.rafaelliu">
     <priority value="INFO" />
     <appender-ref ref="BLOG_LOG"/>
   </category>

Embora seja a solução mais fácil, a separação não está perfeita. Como estamos separando por pacotes, um erro no Hibernate por exemplo, ainda vai ser escrito no server.log, mesmo tendo sido lançado pela aplicação.

 

2. Usando Filters é possível criar um TCLFilter para pegar apenas logs de determinada aplicação. Basta criar um Appender específico:

   <appender name="BLOG_LOG" class="org.jboss.logging.appender.DailyRollingFileAppender">
      <errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler"/>
      <param name="File" value="${jboss.server.log.dir}/blog.log"/>
      <param name="Append" value="true"/>
      <param name="DatePattern" value="'.'yyyy-MM-dd"/>
      <layout class="org.apache.log4j.PatternLayout">
         <param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n"/>
      </layout>
 
      <!-- filter -->
      <filter class="org.jboss.logging.filter.TCLFilter">
         <param name="AcceptOnMatch" value="true"/>
         <param name="DeployURL" value="blog.war"/>
      </filter>    
      <filter class="org.apache.log4j.varia.DenyAllFilter"></filter>
   </appender>

O problema aqui é que, embora o log seja gravado separadamente (inclusive de pacotes do Hibernate, por exemplo), ele será gravado duas vezes: uma vez no blog.log que definimos e uma vez no server.log do JBoss. Isso resulta em mais IO e mais espaço em disco.

 

3. Empacotando um log4j na própria aplicação, em WEB-INF/lib, é possível inverter o classloader e fazer com que as configurações do log4j valham apenas para sua aplicação:

<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
	<class-loading java2ClassLoadingCompliance="false">
		<loader-repository>
			net.rafaelliu:loader=blog.war
			<loader-repository-config>java2ParentDelegation=false</loader-repository-config>
		</loader-repository>
	</class-loading>
</jboss-web>

Feito isso, é preciso criar o log4j.properties (ou xml) normalmente:

log4j.rootLogger=${jboss.server.log.threshold}, fileout
 
log4j.appender.fileout=org.apache.log4j.DailyRollingFileAppender
log4j.appender.fileout.File=${jboss.server.log.dir}/blog.log
log4j.appender.fileout.Append=true
log4j.appender.fileout.DatePattern='.'yyyy-MM-dd
log4j.appender.fileout.layout=org.apache.log4j.PatternLayout
log4j.appender.fileout.layout.ConversionPattern=%d %-5p [%c] (%t) %m%n

O log4j faz parse de system properties, que podem ser usadas no arquivo de configuração. Uma observação importante é que não é possível usar classes do JBoss aqui! Isso causaria ClassCastExceptions. Algumas dicas:

  • No JBoss 5, use o jboss.server.log.dir e o jboss.server.log.threshold. Isso facilitará o deploy da sua aplicação em outros ambientes;
  • Use o mesmo Appender do jboss-log4j (provavelmente uma classe da JBoss estará lá, veja o equivalente da Apache). Isso deixa os logs do JBoss e das aplicações sincronizados, facilitando o correlacionamento de erros;

O problema dessa abordagem é que perdemos o “hot deploy” do jboss-log4j.xml, que nos permite alterar o nível de log sem indisponibilidade.

Referências:
http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PropertyConfigurator.html
http://viragine.blogspot.com/2009/02/separando-o-log-do-jboss-as-por.html
http://community.jboss.org/wiki/SeparatingApplicationLogs

SumUp do JBossInBossa 2011

October 11th, 2011

EDIT: slides da palestra disponíveis no SlideShare

Foi muito bom! Um dia inteiro com geeks das mais diversas áreas num ambiente de troca de conhecimento incrível. As fotos estão no Picasa.

O local do evento ficou apertado para o tanto de gente que deu. Em algumas apresentações as salas ficaram abarrotadas, como a do @brunorst e @claudio4j falando de Tuning de JBoss e a do @vtcorrea e @g_luszczynski falando de Alta Disponibilidade. Ambas as palestras muito bem criticadas e ambas não pude ver..

O @salaboy abriu o evento com um keynote sobre jBPM5 seguido do @jedgarsilva, com toda sua manha de fazer apresentações, falando sobre Cloud. O @porcelli e o Pedro Igor falaram sobre noSQL e data grids e se complementaram bem o primeiro dando um banho (muito bem dado) de conceitos e o segundo falando de produto mesmo, o Infinispan. Para mim foram as apresentações mais interessantes porque nunca tinha ido atrás desses assuntos, que já estão há um bom tempo ai como buzzwords.

Uma apresentação que eu queria muito ter visto e perdi foi a do @jpviragine falando sobre Federação de Dados com o Teiid. No horário da apresentação dele eu estava na outra sala falando sobre JBoss Portlet Bridge. Uma pena, ainda mais vendo a boa repercussão que teve =/

Teve também Weld e Seam com o @rimolive e a @hannelita, que cobriram muito bem o assunto. O @rafabene e o @osmanlira mandaram muito bem na apresentação de Drools. O @rafaeltuelho falou sobre RHQ, com uma demo que pelo que ouvi foi massa. E restou à Flávia Rainone fechar o evento falando sobre JBoss7.

O evento foi nota 10, mesmo sendo apenas a primeira edição em Brasília. Fiquei muito feliz de ter podido palestrar nele porque o público estava muito interessado e não tem nada melhor do que ver gente interessada perguntando na sua palestra =)

Aos que não foram, recomendo não perderem a chance de se inscrever para a edição de 2012 já já deve tá vindo ai.

Cheers!

Rodando GateIn no Eclipse

September 30th, 2011

Graças ao módulo WCI, o GateIn pode rodar em vários servidores. A JBoss distribui ele em duas formas: baseado no JBoss e baseado no Tomcat. Desenvolver portlets para o GateIn utilizando o empacotamento em JBoss é bem simples, basta adicionar um novo servidor (é preciso ter o módulo WTP, e preferencialmente o JBoss Tools também) JBoss apontando para a instalação do GateIn e está tudo resolvido.

Se você quer utilizar o GateIn com Tomcat é um pouco mais complicado, mas nada preciso adicionar a instalação do Tomcat do GateIn normalmente fazer algumas alterações:

1. Mudar no “Server Location” para “Use Tomcat installation (takes control of Tomcat installation)”

2. No  ”Launch Configuration” configurar o “Working directory” com o $TOMCAT_HOME

3. Ainda no  ”Launch Configuration” adicionar os parâmetros:

-Djava.security.auth.login.config=../conf/jaas.conf

-Dexo.conf.dir.name=gatein/conf

4. Provavelmente será também preciso alterar limites de memória da JVM e timeouts de subida/descida do WTP.

Para desenvolver no GateIn, tanto no JBoss quanto no Tomcat, pode ser interessante adicionar o parâmetro -Dexo.product.developing=true, que desabilita vários caches e desabilita o merge/compressão de CSS e JS.

Rapidinha: enviando mensagens JGroups no viewAccepted()

August 21st, 2011

No JGroups, enviar mensagens no viewAccepted() é útil quando novos nós precisam passar ao cluster alguma informação ao entrarem no cluster.

No entanto nós do cluster apenas aceitam mensagens de nós que façam parte da sua view, o que pode trazer problemas. Imagine um cluster com view V1={A,B,C} e um novo nó D que entra no cluster. Quando a nova view V2={A,B,C,D} é instalada no nó D, os outros nós A, B e/ou C podem ainda ter a view V1 (views são instaladas sem ordem específica). Isso quer dizer que eles  vão descartar mensagens enviadas por D, já que ele não faz parte do cluster (porque a view V2 ainda não foi instalada).

Para isso é possível usar o protocolo FLUSH [1] (já existe uma configuração padrão no JGroups chamada flush-udp.xml) que resolve o problema de outros nós não terem a mesma view do nó que enviou a mensagem. No entanto é preciso subir outra thread ao enviar mensagens com o FLUSH no view Accepted() [2].

Referências
[1] http://www.jgroups.org/manual-3.x/html/user-channel.html#Receiver
[2] http://community.jboss.org/wiki/SendingOfMessagesInViewAcceptedCallback

Weld no Tomcat 7

May 29th, 2011

Havia escrito há muito tempo atrás como fazer o deploy de uma aplicação Seam no Tomcat. Daquele tempo para cá muita coisa mudou: o Seam junto com outros frameworks de IoC gerou a JSR-299 de Contexts and Dependency Injection (CDI), a JBoss criou o Weld (implementação de referência CDI), o Seam 3 foi lançado baseado na nova especificação.

Com a padronização numa JSR, agora implementações CDI são obrigadas a suportar uma variedade maior de ambientes de forma vendor neutral. O Weld faz isso e entre os ambientes suportados está o Tomcat. Portanto não há necessidade de configurações extras e gambiarras! O próprio projeto Weld provê archetypes maven com várias configuração, para criar uma aplicação para rodar em um servlet container:

mvn archetype:generate -DarchetypeArtifactId=weld-jsf-servlet-minimal \
                       -DarchetypeGroupId=org.jboss.weld.archetypes \
                       -DarchetypeVersion=1.0.0.Beta1 \
                       -DarchetypeRepository=central

E um projeto pronto para ser executado no Tomcat/Jetty será criado. O problema é que, devido a um bug, no Tomcat 7 pode ser que você veja a seguinte exceção:

SEVERE: Exception sending context initialized event to listener instance of class org.jboss.weld.environment.servlet.Listener
java.lang.NoClassDefFoundError: org/apache/AnnotationProcessor
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:634)
	at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
	at org.apache.catalina.loader.WebappClassLoader.findClassInternal(WebappClassLoader.java:2820)
	at org.apache.catalina.loader.WebappClassLoader.findClass(WebappClassLoader.java:1143)
	at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1638)
	at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1516)
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:634)
	at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
	at org.apache.catalina.loader.WebappClassLoader.findClassInternal(WebappClassLoader.java:2820)
	at org.apache.catalina.loader.WebappClassLoader.findClass(WebappClassLoader.java:1143)
	at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1638)
	at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1516)
	at org.jboss.weld.environment.tomcat.Tomcat6Container.initialize(Tomcat6Container.java:47)
	at org.jboss.weld.environment.servlet.Listener.contextInitialized(Listener.java:184)
	at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4544)
	at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5016)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:140)
	at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:1035)
	at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:738)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:140)
	at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:1035)
	at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:289)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:140)
	at org.apache.catalina.core.StandardService.startInternal(StandardService.java:442)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:140)
	at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:674)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:140)
	at org.apache.catalina.startup.Catalina.start(Catalina.java:596)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:616)
	at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:303)
	at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:431)
Caused by: java.lang.ClassNotFoundException: org.apache.AnnotationProcessor
	at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1671)
	at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1516)
	... 36 more

O problema é que o Weld identifica erroneamente o Tomcat 7 como Tomcat 6. Para resolver o problema podemos definir explicitamente que o container que estamos usando é o Tomcat 7. Isso é feito criando-se um arquivo META-INF/services/org.jboss.weld.environment.Container no classpath com o conteúdo:

org.jboss.weld.environment.tomcat7.Tomcat7Container

Note que estamos definindo na mão o container! Ou seja, abrimos mão da portabilidade. Vamos esperar o bug ser corrigido, mas até lá é isso!

Referência: https://issues.jboss.org/browse/WELD-879

Configurando o JBoss Messaging em cluster

May 30th, 2010

Uma das grandes evoluções do JBoss Messaging sobre o JBossMQ (seu predecessor) foi a robustez da solução em cluster.

Introdução (ou como era com o JBossMQ)

Antigamente, o JBossMQ já era clusterizável (ouch.. neologismo..) mas conseguia isso usando o HA Singleton do JBoss. O JBoss quando configurado em cluster pode ser serviços deployados (ouch de novo..) como singletons através do cluster. Funciona assim: você diz ao JBoss que aquele serviço é um HA Singleton e o JBoss vai garantir a você que em seu cluster haverá sempre um, e apenas um, serviço ativo no cluster (enquanto restar nós no cluster, claro). Essa é uma funcionalidade muito interessante pois permite serviços cluster unaware serem clusterizáveis.

O balanceamento de carga pudia ser feito através dos consumidores: implementando um ReceiverImpl consumidores iriam receber as mensagens a la round robin. Melhor que nada.

JBoss Messaging

O JBoss Messaging é a implementação padrão do JBoss 5. Com o JBoss Messaging a infraestrutura de clusterização melhorou Muito. Podemos agora criar um cluster ativo/ativo, que quando um nó falhar o outro se encarregará de enfileirar suas mensagens. E ainda mais, temos balanceamento de carga de fato: cada conexão aberta usará uma fila diferente, round robin way.

Montando o cluster

Configurar o JBoss Messaging em cluster é extremamente fácil:

  • Ative a clusterização nos arquivos de configuração do JBoss Messaging e configure um banco de dados compartilhado;
  • User um ConnectionFactory e uma Queue/Topic marcados como clusterizados.

Bom, vamos aos bits. As versões usadas seguem:

  • JBoss 5.1.0.GA
  • JBoss Messaging 1.4.3.GA (a que vem por padrão)
Configurando o JBoss Messaging

Para fazer o failover, o JBoss Messaging precisa usar um banco de dados compartilhado. Copie de $JBOSS_HOME/examples/config o XML apropriado sobrescrevendo o $JBOSS_HOME/server/all/deploy/messaging/hsqldb-persistence-service.xml (lembre de configurar/iniciar o banco de dados!). Vou usar o MySQL:

rm $JBOSS_HOME/server/all/deploy/messaging/hsqldb-persistence-service.xml
cp $JBOSS_HOME/examples/config/mysql-persistence-service.xml $JBOSS_HOME/server/all/deploy/messaging

Ative a clusterização:

<attribute name="Clustered">true</attribute>
<attribute name="FailoverOnNodeLeave">true</attribute>

Aponte para apontar para o datasource do seu banco:

<attribute name="DataSource">java:/DefaultDS</attribute>
Criando as filas e factories

Vamos usar o ClusteredConnectionFactory, que é uma factory padrão do JBoss que vá vem configurada em cluster, se quiser ver como é feito: $JBOSS_HOME/server/all/deploy/messaging/connection-factories-service.xml.

Só precisamos criar nossas filas clusterizadas. Adicionem um arquivo $JBOSS_HOME/server/all/deploy/clustered-destinations-service.xml com o seguinte conteúdo:

<?xml version="1.0" encoding="UTF-8"?>
 
<server>
 
   <mbean code="org.jboss.jms.server.destination.QueueService"
      name="jboss.messaging.destination:service=Queue,name=clusteredQueue"
      xmbean-dd="xmdesc/Queue-xmbean.xml">
      <depends optional-attribute-name="ServerPeer">jboss.messaging:service=ServerPeer</depends>
      <depends>jboss.messaging:service=PostOffice</depends>
      <attribute name="Clustered">true</attribute>
   </mbean>
 
</server>
Criando os profiles

Se queremos criar um cluster vamos precisar de dois nós! Então copie o profile all e crie dois outros profiles:

cp -r all jms1
cp -r all jms2

Testando

Vamos subir os dois nós usando o serviço de ServiceBinding do JBoss para não haver conflitos de porta ou ip:

./run.sh -c jms1 -Djboss.service.binding.set=ports-01 -Djboss.messaging.ServerPeerID=1
./run.sh -c jms2 -Djboss.service.binding.set=ports-02 -Djboss.messaging.ServerPeerID=2

Agora vamos usar uns programinhas que fiz para produzir e consumir mensagens, ele é bem simples e intuitivo e é empacotado junto com os fontes. Vamos usá-lo para testar nosso cluster.

Iniciamos um consumer para cada nó do cluster:

java -cp JmsSample.jar:$JBOSS_HOME/client/jbossall-client.jar net.rafaelliu.jms.JmsConsumer 127.0.0.1:1100 ClusteredConnectionFactory queue/clusteredQueue
java -cp JmsSample.jar:$JBOSS_HOME/client/jbossall-client.jar net.rafaelliu.jms.JmsConsumer 127.0.0.1:1200 ClusteredConnectionFactory queue/clusteredQueue

E iniciar o nosso producer:

java -cp JmsSample.jar:$JBOSS_HOME/client/jbossall-client.jar net.rafaelliu.jms.JmsProducer 127.0.0.1:1100,127.0.0.1:1200 ClusteredConnectionFactory queue/clusteredQueue 10 1 "Mensagem de teste"

Viram que as mensagens foram balanceadas? Agora podemos tentar o seguinte:

  • fechar um dos consumers: as mensagens são enviadas para o outro consumer;
  • fechar um dos consumers enquanto estão sendo enviadas mensagens: o outro consumer assume a partir da última mensagem;
  • pausar e despausar um consumer: as mensagens vão sendo enfileiradas e quando despausamos, elas são todas consumidas;
  • pausar um consumer e depois fechar: as mensagens vão sendo enfileiradas e quando fechamos, elas são repassadas para o outro nó.

Dá pra brincar muito!

Futuro

Atualmente, sendo empacotado junto com o último Milestone do JBoss 6, o serviço de mensageria foi trocado pelo HornetQ. Isso significa ainda outra evolução na área do MOM para a JBoss. Vamos ver se quando for para GA não escrevo sobre ele. Até a próxima o/

PS: para produção dêem uma olhada nos parâmetros DefaultPreserveOrdering e SuckerPassword.

Binário: http://github.com/downloads/rafaelliu/rafaelliu.net/JmsSample.jar

Abertas inscrições para o JBoss In Bossa 2010

April 10th, 2010

Ainda que tarde, vale a pena anunciar.

Foram abertas as incrições para o JBoss In Bossa 2010 que acontecerá em São Paulo dias 7 e 8 de maio. O evento é o maior da América Latina relacionado a JBoss e contará com a presença de palestrantes internacionais como o Peter Muir (project lead do Seam e do Weld), Benjamin Mestrallet (CEO da eXo Platform) e Mauricio Salatino (CTO da PlugTree).

Veja alguns dos principais assuntos previstos na agenda:

  • O novo JBoss 6
  • Tuning JBoss
  • Java Persistence API
  • Seam
  • Weld
  • Contexts and Dependency Injection
  • Java ServerFaces 2.0
  • Teiid
  • Drools
  • Jopr
  • E a lista continua..

É uma ótima oportunidade para conhecer pessoalmente alguns nomes de peso na comunidade e fazer networking. Se inscreva!

Acompanhe também o evento via @jbossinbossa.