quinta-feira, 4 de agosto de 2011

Como criar um Pool de Conexões no JBoss

Este artigo ensina de maneira prática e rápida como criar um pool de conexões para qualquer banco de dados no JBoss, independente das aplicações. O pool criado terá suporte a transações e poderá ser usado de qualquer aplicação através da tecnologia JNDI. Ele será inicializado quando o JBoss iniciar e aguardará as solicitações das aplicações para compartilhar uma conexão. Note que este assunto é muito vasto e não pretendo exaurí-lo, mas sim criar um tutorial fácil e simples para que seu pool funcione.


  • Instalando o Driver do Banco de Dados no JBoss

O driver de seu banco de dados é simplesmente uma biblioteca jar. Basta copiá-lo para um dos seguintes locais (sendo JBOSS_HOME o diretório de instalação de seu JBoss):


JBOSS_HOME/common/lib
[aqui funcionará para o JBoss em qualquer situação ou configuração. É este local que eu recomendo ficarem os drivers dos bancos de dados que você tem]

Outras opções:

JBOSS_HOME/server/default/lib
[funcionará para a configuração default]

JBOSS_HOME/server/minimal/lib
[funcionará para a configuração minimal]
 
JBOSS_HOME/server/standard/lib
[funcionará para a configuração standard]

JBOSS_HOME/server/all/lib


  • Nomeando o Arquivo do Pool de Conexões

Vamos criar um arquivo que descreva a conexão com seu banco de dados e crie o seu pool. Este arquivo deve se chamar "aplicacao-banco-ds.xml", onde aplicacao é o nome do sistema que deve utilizar suas conexões (não obrigatório) e banco é o nome do sistema de gerenciamento de banco de dados (SGDB) a que o arquivo se refere (obrigatório). O importante é que o nome de seu arquivo termine com "-ds.xml", indicando que é um arquivo de um DataSource. Exemplos de nomes de arquivos são:

sistemas01-mysql-ds-xml
auditoria-oracle-ds.xml
sqlserver-ds.xml

O JBoss suporta vários pools de conexões, inclusive conexões a bancos diferentes. Assim, você pode criar quantos destes arquivos você quiser ou precisar. Note que as conexões só serão realmente abertas quando uma aplicação solicitar ao JBoss a conexão. Enquanto não houver solicitação, o DataSource existirá, porém sem conexão ativa.


  • Conteúdo do Arquivo de Pool de Conexões do JBoss

Suponhamos que você tenha criado um arquivo chamado "mysql-ds.xml" (ou qualquer outro nome que você deseje). O conteúdo do arquivo deverá ser:

<?xml version="1.0" encoding="UTF-8"?>
<datasources>
<local-tx-datasource>
<jndi-name>MysqlDS</jndi-name>
<connection-url>jdbc:mysql://localhost:3306/database</connection-url>
<driver-class>com.mysql.jdbc.Driver</driver-class>
<user-name>nomeusuario</user-name>
<password>senhausuario</password>
<min-pool-size>5</min-pool-size>
<max-pool-size>10</max-pool-size>
<idle-timeout-minutes>5</idle-timeout-minutes>

<exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter</exception-sorter-class-name>
<!-- should only be used on drivers after 3.22.1 with "ping" support    -->
<valid-connection-checker-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLValidConnectionChecker</valid-connection-checker-class-name>

<!-- corresponding type-mapping in the standardjbosscmp-jdbc.xml -->
<metadata>
<type-mapping>mySQL</type-mapping>
</metadata>
</local-tx-datasource>
</datasources>

OBS: Mantenha uma tag em cada linha. Talvez a listagem acima quebre muitas tags em mais de uma linha, dependendo do seu monitor e resolução. Como se trata de um arquivo XML, então a quebra de linha é entendida como um caracter, e pode provocar erros na interpretação (
parser) do arquivo.

Entendendo as tags do arquivo:

datasources = Indica que aqui serão listadas informações para completar um DataSource, ou seja, uma fonte de conexões. Existem 3 tipos de DataSources, basicamente:

no-tx-datasource - um DataSource que não suporta JTA Transactions (transações).
local-tx-datasource - um DataSource que suporta transações com JTA, mas não suporta two phase commit.
xa-datasource - suporta transações com JTA e two phase commit usando javax.sql.XADataSource.



O que você precisará, na maioria das vezes, é o local-tx-datasource. Ainda que você não use transações diretamente, esta é a melhor opção.


local-tx-datasource = É a fonte de conexões em si.

jndi-name = O nome do JNDI que você usará para pedir uma conexão quando dentro de sua aplicação. Escolha um nome claro e simples. Este nome é a sua referência para obter a conexão dentro de qualquer aplicação rodando em seu JBoss.

connection-url = É a URL de conexão com o banco. Cada banco tem uma URL de um jeito. Uma lista das URLs de bancos de dados mais comuns está neste tutorial aqui, na seção "Set up specific DataSources". Não coloque aqui o nome do usuário do banco.

driver-class = A classe de seu Driver. Consulte o manual de seu driver para saber qual a classe que deve ser colocada aqui.

user-name = O nome do usuário do banco que será usado. Não coloque este nome diretamente na URL lá em cima!! Deixe para colocá-lo aqui, nesta tag.

password = Sim, aqui você escreverá a senha do usuário do banco. CUIDADO: se seu JBoss está em algum lugar acessível pelos usuários da rede, mesmo que somente como leitura, a senha poderá ser lida facilmente (está em texto puro), o que representa uma grande vulnerabilidade em seu sistema. Zele pelas permissões de acesso a este arquivo!!

min-pool-size e max-pool-size = representam, respectivamente, o valor mínimo e máximo de quantas conexões devem ser mantidas abertas. Assim que uma conexão é solicitada, ela é aberta e será mantida aberta se o total de conexões abertas é menor ou igual ao min-pool-size. Controle estes dados atentamente, de acordo com a carga de uso de seu sistema. Mantenha valores diferentes para ambientes de desenvolvimento e produção ou para sua máquina local.

idle-timeout-minutes = O valor em minutos máximo de ociosidade para que uma conexão seja fechada. Se uma conexão alcançar este valor de tempo sem ser utilizada, ela será fechada. Isto poupa recursos e memória da máquina. Assim como no caso acima, use-o com cuidado e de acordo com o perfil de seu sistema. Recomendo valores diferentes para máquinas locais, servidores de desenvolvimento e de produção.

As outras tags citadas acima são específicas do MySQL e estão comentadas.


  • Testando Conexões (DataSources) Diretamente no JBoss

Bom, vamos testar tudo, né?? Sem testes, como garantiremos que este trabalho todo funcionará?? Com o JBoss, é possível testar os DataSources diretamente na interface administrativa JMX-Console Admin. Dúvidas sobre esta interface?? Consulte nosso artigo Trocando a Senha do Administrador do JBoss (JMX-Console Admin).
Acesse o JMX-Console e faça login. Na tela de administração, acesse a opção:

Resources --> Datasources

Conforme mostra a Figura 01. Deve aparecer uma listagem com os seus DataSources, exibindo o nome de cada um deles (JNDI name), o tipo de DataSource, o status ("Up" significa que está funcionando) e um botão "Delete" para apagá-lo.


Figura 01: Tela de administração de DataSources do Administrador do JBoss.


Clique no nome do DataSource e logo surgirá uma nova tela, com todas as opções de administração do mesmo. Vá até a última aba (Control) e selecione "Test Connection" (Figura 02).


Figura 02: Controle administrativo do Pool de Conexões.


Se a conexão funcionou, então a sua tela vai mostrar uma linda mensagem de sucesso verdinha, conforme a Figura 03.


Figura 03: Tela de teste de conexão, após realizado.


Existe outra maneira de se testar a conexão, que é obtendo um objeto DataSource ao se fazer um Lookup a partir do InitialContext. Mas isto fica para outro artigo, onde poderemos detalhar melhor estes passos.


  • Dicas de Boas Práticas

1- Nunca crie pool de conexões dentro das aplicações, mesmo que elas usem um framework em especial, como o Hibernate. O JBoss serve para isso e ele oferece flexibilidade e recursos para as mais diferentes situações e cenários.

2- Conforme você pode ver, é possível se criar vários pools de conexão em um mesmo arquivo -ds.xml (vários local-tx-datasource, por exemplo). Não é errado, mas não é recomendável. Para se administrar melhor, mantenha um pool em cada arquivo específico.

3- Zele pela carga de seu sistema, controlando a quantidade de conexões abertas e o tempo de ociosidade delas. Se muito necessário, crie dois pools com perfis diferentes, de forma a flexibilizar seus ambientes.



Bom, este artigo detalhou bastante um processo que é mais do que comum em qualquer projeto web usando Java e JBoss, mas a que usualmente se precisa voltar e revisar, especialmente quando se é preciso criar o ambiente todo desde o início. Espero sinceramente ter ajudado. Não se esqueça de tecer seus comentários abaixo!!



7 comentários:

Te vejo na 6° ~ BF ~ disse...

Olá, muito bom esse post!
Uma duvida, esse arquivo que você ensina criar, tem a mesma função que o standalone.xml, que fica no diretório JBOSS_HOME\standalone\configuration ?

Ana disse...

Olá, muito obrigada pelo Post. Gostaria de tirar uma dúvida. Quando eu defino no JBoss EAP 6.4 o número mínimo de conexões com o valor 0, significa que seria o default, isto é, 20 conexões? Por que há um sistema em que estamos trabalhando que configurei o pool de conexões com os valores 0 (min-pool-size) e 60 (max-pool-size). No entanto, o sistema funciona por um período, e logo após, ele apresenta problemas de conexão com o banco, identificando a mensagem: "Internal Exception: java.sql.SQLRecoverableException: Conexão Fechada". Interpreto que não seja regra de firewall inexistente porque se assim fosse, ele não se conectaria nem uma só vez, estão desconfiamos do pool de recursos. O mais apropriado seria definir um valor mínimo? Mas se eu defino um valor mínimo, ele não irá estabelecer conexões desnecessárias? Aguardo sua ajuda. Um abraço.

O Pajé disse...

Olá Ana,

Respondendo a suas perguntas:

1- O número de conexões mínimas deve ser indicado para justamente auxiliar o sistema com a reciclagem de conexões, evitando manter muitas conexões abertas desnecessariamente ou acabar fechando conexões demais e precisando reabri-las com muita freqüência. É claro que estes valores dependem diretamente do perfil de uso de seu sistema, assim como das condições de desempenho de seu servidor. Uma vez aberta a conexão, ela será mantida aberta, caso não se atinja o número mínimo de conexões. Se esse valor for alcançado, ela poderá ser fechada, de acordo com o uso do sistema. Todo esse gerenciamento é realizado pelo próprio JBoss, então você não deve se preocupar com isso. Afinal, o JBoss serve para coisas como essas.

2- Se o JBoss gerencia as conexões para você, então nenhuma exceção deve ser gerada por falha nas conexões, exceto se realmente acontecer problemas críticos, como: falhas na rede que deixem o banco de dados inacessível; sobrecarga no sistema, exaurindo todas as conexões abertas e solicitando ainda mais recursos; dentre problemas semelhantes.

3- A exceção que você pega pode ser decorrente de outros problemas no código, como alguma chamada mal-posicionada a um ".close()" de algum objeto contendo acesso ao banco ou resultados dele; problemas de concorrência, que acabem por tentar utilizar recursos antes que eles estejam disponíveis (os chamados "race conditions"); dentre outros problemas do gênero. Para informar melhor o que acontece, eu precisaria olhar o código e testá-lo.

4- Verifique se o seu sistema tem, em algum ponto, algum código que force a conexão a ser fechada. Isto não deveria acontecer, já que o gerenciamento das conexões deve ficar por conta do JBoss. Use sempre o JBoss para solicitar a conexão e devolvê-la a ele. Nunca feche conexões diretamente. Este é o trabalho dele. Forçar, no seu código, conexões a serem abertas e fechadas estará comprometendo o gerenciamento do JBoss e pode ocasionalmente produzir situações em que todas as conexões se encontrem fechadas, gerando erros como este que você pegou.

Unknown disse...

em que pasta eu coloco os xmls de configuração da pool ("db_teste-mysql-ds.xml")?

O Pajé disse...

Olá amigo,

Os arquivos de configuração de DataSource (*-ds.xml) devem entrar no mesmo diretório onde estiver a sua aplicação web (o arquivo *.war ou *.ear). Naturalmente, isto depende da configuração do JBoss em uso (minimal, default, etc...). O JBoss vai varrer o diretório e fazer deploy de suas aplicações junto com os pools de conexão configurados para os bancos de dados, de modo que estes estejam disponíveis para aquelas.

Boa sorte!

Unknown disse...
Este comentário foi removido pelo autor.
Unknown disse...

Boa tarde pajé

Estou saindo seu tutorial mas a conexão não aparece no jboss management por nafa, lá só aparece a ExampleDs, não faço idéia o q posso ter feito de errado.

O xml esta na pasta "deployments" a mesma para onde esta o Painel.war

Segue o xml:

<?xml version="1.0" encoding="UTF-8"?>
<datasources>
<local-tx-datasource>
<jndi-name>MSSQL-test</jndi-name>
<connection-url>jdbc:sqlserver://-----;databaseName=******</connection-url>
<driver-class>com.microsoft.sqlserver.jdbc.SQLServerDriver</driver-class>
<user-name>m****</user-name>
<password>m----</password>
<min-pool-size>5</min-pool-size>
<max-pool-size>30</max-pool-size>
<idle-timeout-minutes>5</idle-timeout-minutes>

<exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter</exception-sorter-class-name>

</local-tx-datasource>
</datasources>