Configurando o JBoss Messaging em cluster

May 30th, 2010 by rafaelliu Leave a reply »

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

Advertisement

3 comments

  1. Thomás says:

    Olá Rafael,

    Muito bom seu artigo, parabéns!

    Estou precisando fazer algo parecido, porém estou usando o apache para fazer o balanceamento. Configurei tudo certinho, o apache, modjk + 2 jboss, sendo o apache e 1 jboss em uma máquina e o segundo jboss na segunda máquina.

    Até aí tudo ok, as duas máquinas conforme os logs iniciam em cluster, uma adiciona a outra, etc. O apache faz o balancemento certinho, se derrubo algum jboss o outro assume a mesma URL que está sendo acessada, conforme eu preciso.

    Porém, eu configurei conforme seu tutorial, estou utilizando o oracle, criei o datasource, etc. As tabelas foram criadas na inicialização do jboss (tabelas JBM_*), então fiz uma aplicação teste, que apenas salvo na session uma string qualquer, e escrevo ela na saída do servlet e no system.out. também mostro se ela já existia ou não. chamo meu servlet e mostra que o atributo existe, porém se eu parar o jboss que está responsável pela session em questão, e efetuo um refresh na página o outro jboss assume porém a session não é propagada para este segundo jboss.

    Dei uma olhada nas tabelas que foram criadas, nada muda, exceto a tabela JBM_COUNTER que os valores mudam, as demais parmanecem sem dados.
    Também não da nenhum erro nos logs.

    Teria idéia do que posso fazer para verificar o que está acontecendo?

    Ufa, chega de escrever.

    Abraço

    • rafaelliu says:

      A noção de cluster do JBoss é por serviço. Então existe cluster de sessão web e cluster de mensageria. Estou entendendo que a replicação de sessão que não está funcionando no teu caso. Bom, nesse caso não tem muito a ver com o post mas.. supondo que tu configurou tudo certinho, tens que te certificar de algumas coisas na tua aplicação:
      * os objetos da sessão são serializáveis
      * o web.xml possui o “”

Leave a Reply