O EJB e suas transações

May 28, 2008

(0) Comments

Introdução

Seguindo com a série de posts sobre EJB, vamos explanar e entender o suporte que ele proporciona no gerenciamento de transações. Primeiramente, precisamos entender o conceito de transação.

Na vida real realizamos diversas transações diariamente: desde bancárias até mesmo amorosas. Por exemplo, você só leva pra casa a camisa do maior time do Brasil (para os menos informados, falo do glorioso Internacional), se a operadora do seu cartão de crédito autorizar a compra. Caso contrário, a camisa fica lá iluminando a vitrina da loja. Assim, também, podemos relacionar os casos amorosos. Neles precisamos seguir uma cartilha de regras (para os homens: lêia-se o complicado mundo das mulheres) a nós impostas, para podermos levar a um final feliz (ou pelo menos uma tentativa disso) a relação. Caso contrário…

Então uma transação é tudo aquilo que envolve uma série de ações onde o seu desfecho final depende do sucesso dessas ações para poder acontecer (committed). Caso contrário todas essas ações são desfeitas imediatamente (rolled back).

No nosso incrível mundo de desenvolvimento de sistemas, as transações funcionam seguindo
essa mesma linha de raciocínio. Nele as transações são contempladas por quatro características, denominadas pelo acronômo ACID (Atomicidade, Consistência, Isolação e Durabilidade).

Propriedades ACID

  • Atomicidade: transações são atômicas desde sempre. Isso quer dizer que: ou tudo é executado com sucesso, ou seu estado original é retomado.
  • Consistência: somos os responsáveis diretos por cuidarmos dessa propriedade. Por isso é a mais delicada desse grupo. Está diretamente ligada a forma como escrevemos o código. O sistema de informação deverá estar consistente com seus dados e regras de negócios ao término da transação se o mesmo a iniciou assim. Embora durante uma transação o sistema não necessita estar consistente com essas informações.
  • Isolação: todas as mudanças que são realizadas durante uma transação podem ser isoladas, isto é, tornadas imperceptiveis para outras transações até que a a mesma seja finalizada. Isso ocorre em sincronização de threads e “locking” em um banco de dados. Essa característica é muito importante para ambientes onde existem muitos processos concorrentes.
  • Durabilidade: uma vez uma transação finalizada com sucesso (commited), seus dados devem estar devidamente armazenadas e não podendo ser desfeitas. Ou seja, uma vez confirmada a transação, temos que garantir que seu resultado é “durável”.

Gerenciamento de transações

As transações quando são responsáveis por gerenciar somente um recurso, é uma transação local. Entretanto, na experiência do dia-a-dia sabemos que isso não é algo tão comum. O momento é todo das aplicações distribuídas. E apenas um recurso de armazenamento de dados, muitas vezes, não é o suficiente. Por isso existe o transaction manager, que é o responsável por abstrair toda essa complexidade para nós. É ele que coloca todos esses recursos dentro de uma única transação.

Para que isso possa ocorrer com sucesso ele usufrui do chamado Two-Phase-Commit, que consiste basicamente em dividir a fase de commit de uma transação em dois passos. Primeiramente verifica se existe a possibilidade de commit em todos os recursos envolvidos. Caso sim, deixa todos eles em estado commitment (compromisso). E só após todos estarem “compromissados” com a transação é que realmente ela será commited.

O protocolo mais utilizado e recomendado para coordenar o Two-Phase-Commit é o Protocolo XA. Ele é o responsável por fazer com que os recursos envolvidos e o transactional manager falem a mesma língua tornando assim viável essa comunicação.

Todo o suporte que EJB dá a transações é fornecido através da JTA (Java Transaction API). É ela que expõe as funcionalidades que são distribuidas na camada de gerenciamento de transações pelo servidor de aplicação. Com isso temos duas saídas básicas para gerenciarmos nossas transações:

  • Container-Managed Transactions (CMT): pode ser configurada com anotações ou com um descriptor. Elas iniciam antes da chamada de um método de negócio de um EJB e dependendo dos acontecimentos na execução desse método a transação é rollback ou commited. Elas podem ser classificadas em:
  1. Requerid (requerida): onde o container cria uma transação ou, se houver uma transação no método que chamante, cria uma junção (continuação), dessa transação.
  2. Requires new (requer nova): onde o container cria uma transação ou, se houver uma transação no método que chamante, suspende esta transação e cria uma nova transação.
  3. Supports (apoia): onde o container não cria uma transação se não houver no método chamante, ou se houver realiza uma junção (continuação), dessa transação.
  4. Mandatory (obrigatória): sempre precisará de uma transação anterior para poder realizar uma junção com ela. Caso contrário lançara uma exceção.
  5. Not suported (não suportada) : Se não houver transação anterior, aqui continua sem também. Se houver, ela é suspensa e o método continua sem controle de transação.
  6. Never (nunca): Se não houver transação anterior, aqui continua sem também. Se houver, é lançada uma exceção.
  • Bean-Managed Transactions (BMT): requer uma configuração programática onde devemos mostrar onde teremos uma transação e onde ela poderá realizar um roll back através da chamada da interface javax.transaction.UserTransaction.

Bom, isso foi só algumas referências básicas sobre o funcionamento das transações com o uso de EJB. Com o tempo quero aprofundar o artigo aqui no blog.

Muito obrigado pela leitura.

Abraços a todos.

Popularity: 46% [?]

Daniel Tamiosso

,

EJB: Stateless e Stateful Session Beans

May 5, 2008

(0) Comments

Session Beans

Basicamente, de acordo com a especificação de EJB, os Session Beans representam objetos transientes. Disponibilizados em um servidor de aplicações, eles podem ser acessados remotamente por diversos clientes. São os responsáveis por modelar processos de negócios de um determinado caso de uso e de tarefas referentes a um cliente.

Bom, conhecendo os princípios básicos dos Session Beans, podemos começar a entender as diferenças e o motivo do uso entre os dois tipos em que são classificados: Stateless e Stateful.

Stateless

Normalmente destinam-se a executar automaticamente operações individuais não mantendo o seu estado para cada invocação de um método. Cada cliente pode usar em qualquer momento uma instância de um Stateless Session Bean. São leves, pois o servidor de aplicação mantem um certo número de instâncias preparadas para receber requisições de seus clientes. Ao término de cada requisição suas instâncias retornam para o pool para serem reutilizadas. Por isso um pequeno número de Stateless Session Beans garante um número relativamente grande de requisições de clientes.

Stateful

Sua principal característica é a manutenção de estado entre as suas operações. Por isso é associado a um cliente específico. Para manter os estados das operações o Stateful Session Bean implementa a interface SessionSynchronization. Sendo assim o cliente pode facilmente configurar os valores dos atributos do bean, para serem utilizados nos métodos de negócios. Mas a manutenção de estados tem seu preço, uma instância não pode ser facilmente devolvida ao seu pool enquanto uma sessão entre o bean e o cliente ainda está ativa. Vale lembrar que os dados de uma sessão são transientes e não foram projetados para serem persistentes.

Diferenças e afins

Quando usamos Stateful mantemos o estado da conversação com o cliente. Esse estado é mantido somente enquanto durar essa conversação. Ou seja, quando o cliente termina a sessão o estado do bean é destruído. Para isso temos que garantir que quando a conversação é encerrada nem o estado nem o bean deveriam ter utilidade para o cliente.

Totalmente o oposto disso o tipo Stateless mantém estado de conversação apenas durante a vigência da invocação de um método. Após isso, os estados de todas as variáveis do bean são perdidos. Portanto os beans Stateless nos dão alguns benefícios como: escalabilidade, pois são capazes de atender de forma escalável um grande número de requisições comparadas aos beans Stateful; e desempenho, pois container EJB nunca irá mover um bean Stateless da memória RAM para um armazenamento secundário, o que poderá fazê-lo com um bean Stateful.

Boas práticas

A escolha do tipo de um session bean tem que ser realizada cuidadosamente. Sabemos que os Stateful Session Beans têm um preço caro no mercado. As interfaces de acesso devem ser analisadas cautelosamente. Interfaces remotas envolvem acesso a rede podendo ser crucial para um baixo desempenho e a escalabilidade das nossas aplicações. Se utilizarmos somente uma máquina virtual então uma interface local será o suficiente.

Caso utilizarmos Injeção de Dependência devemos certificar que não estamos injetando um Stateful Session Bean em um Stateless Session Bean. Pois informações de estados serão armazenadas em uma instância variável e estarão disponíveis para todos os clientes, contendo assim informações imprecisas. Agora injetarmos um Stateful Session Bean em outro pode ser uma boa solução para alguns casos.

Uma boa prática é separar em interceptadores as rotinas de logging e de auditoria, tento assim as regras de negócios limpas de outras funções que não condizem com o processo em si. Devemos ter cuidado também nos tipos de dados que estaremos armazenando em nossos Stateful Beans, principalmente com aqueles grandes objetos compostos. Existem algumas formas de melhorar o uso de um Stateful Bean, que estarei comentando nos próximos posts como: passivation e configuração de timeout ideal.

Popularity: 63% [?]

Daniel Tamiosso

, , ,

Apache Tomcat - Performance interna

April 14, 2008

(4) Comments

Qual mortal desenvolvedor de sistemas que trabalha, principalmente, com Java nunca entrou em contato com o Apache Tomcat. Bom, mas para aqueles menos informados, saibam que ele é conteiner web, cuja função é servir aplicações web escritas em Java. Foi desenvolvido pela Apache Software Foundation

Vale lembrar, que o seu código é aberto e que a SUN considera o projeto como a Implementação de Referência para JSP e Java Servlet.

Em muitos casos, no nosso dia-a-dia, não temos acesso a JVM e ao SO no qual implantamos nossos sistemas. O que resta a nós, nesses casos, para incrementarmos a performance do Tomcat é configurará-lo internamente. A seguir, cito duas dicas básicas, de configuração interna do Apache Tomcat.

Ajustando o número de Threads:

Uma forma de controlar a performance de suas aplicações é ajustando o número de requisições das threads em uso. O Tomcat define por padrão um pool de threads para prover uma resposta rápida aos pedidos recebidos. Normalmente essa configuração padrão normalmente é suficiente para a maioria dos aplicações. Mas você pode ajustar esse pool de acordo com a real necessidade de sua aplicação. Para isso definimos as propriedades “minThreads” e “maxThreads”.

Um exemplo para a configuração da propriedade minThread é a seguinte: em um pequeno momento do dia seu site recebe dez requisições por segundo e cada requisição demora 1 segundo para ser processada, um minímo dez threads, alocadas inicialmente, deve ser o suficiente para garantir uma boa performance do seu servidor.

Agora precisamos configurar o máximo de threads que o servidor irá disponibilizar. Pois, provavelmente, teremos picos de acessos em determinados momentos do dia. Caso isso ocorra, o valor que definirmos na propriedade maxThreads, será o máximo de threads que serão realocadas aquelas iniciais para garantirmos que o servidor não fique ocupado, e garanta as requisições solicitadas. Só não podemos esquecer de termos um limite de thread que condiz realmente com a nossa real necessidade. Visto que, um número alto nessa configuração, poderá estourar a memória da JVM em um ataque malicioso que realizará um ataque em massa no servidor.

Podemos utilizar para testar as nossas configurações, ferramentas que realizam uma carga no servidor configurada por nós. E com a análise dos resultados obtidos podemos chegar a um ponto adequado para as nossas aplicações.

Essa configuração é feita no conector de sua aplicação no arquivo server.xml.

Desabilitando pesquisas de DNS

O servidor, onde está localicazada a nossa aplicação, precisará para gerar um log sobre cada requisição de um cliente, algumas informações com o número do IP ou o resultado de uma pesquisa na busca do seu nome no DNS. Porém, pesquisa de DNS utilizam banda de rede, envolvendo troca de informações de vários servidores.

O que pode acontecer é que um desses servidores poderá ficar inoperante, resultando em tempos de espera pelo nosso servidor. Para evitarmos isso podemos desabilitar as pesquisas de DNS. Após estar desabilitado, toda a requisição pelo servidor remoto (getRemoteHost() emHttpRequest), somente retornará o IP numérico, sem tentar resolver o seu nome.

Essa configuração também é feita no conector de sua aplicação no arquivo server.xml. Em um conector comum o atributo responsável por essa propriedade é o enableLookups.

Popularity: 66% [?]

Daniel Tamiosso

, , , ,