Arquivo da tag: Design Patterns

As principais funções de um ESB (Enterprise Service Bus)

Olá pessoal!

Frequentemente sou questionado com relação a quando a utilização de um ESB (Enterprise Service Bus ou Barramento de Serviços Corporativo) é interessante em um dado cenário de integração ou não. Espero que este post ajude a esclarecer a esta dúvida, bem como a elucidar as principais funcionalidades que se pode tirar proveito quando se emprega uma ferramenta robusta como esta. Vamos lá!

Arquitetura Espaguete

Em geral, um Enterprise Service Bus está relacionado a estratégias de arquiteturas orientadas a serviço (SOA), com o objetivo de proporcionar a disponibilização de serviços em um local único e centralizado, alavancando reuso, diminuindo acoplamento entre consumidores e provedores de serviços, o que por sua vez reduz significativamente a dependência entre ambos, de forma que manutenções – que, diga-se de passagem, são inevitáveis – possam ser feitas de forma mais tranquila. Todos estes fatores apoiam na redução de custos, seja pela manutenção facilitada (ou com baixo impacto), seja pelo reuso proporcionado.

Continue lendo

Como tratar falhas em web services – Idempotent Retry Pattern (parte 2 de 2)

Olá pessoal,

Livro Service Design Patterns - Ian RobinsonNo post anterior vimos as possíveis situações em que uma chamada a um web service pode falhar. Vimos também que uma possível solução seria utilizar estruturas de enfileiramento de mensagens (MSMQ, WebSphere MQ, por exemplo), e que porém, tais soluções não são indicadas para cenários em que a necessidade de entrega ou recebimento de mensagens ultrapasse o escopo da rede interna da organização.

Outro ponto a se considerar, é que tais abordagens caracterizam o que é conhecido com integração near real-time, onde o dado consumido ou provido chega ao seu destino não em tempo real, mais próximo disso. Existem situações em que requisitos estabelecerão que o dado deverá ser obtido ou entregue ao seu destino em tempo real, o que gera uma demanda por abordagens denominadas real-time. Web service é uma abordagem que permite a implementação de integrações real-time, porém, como visto anteriormente, como endereçar as possíveis falhas que podem ocorrer quando da sua utilização?

Continue lendo

Como tratar falhas em web services – Idempotent Retry Pattern (parte 1 de 2)

Livro Service Design Patterns - de Ian RobinsonOlá pessoal,

Nos dois posts anteriores vimos alguns padrões para requisição e reposta de serviços, como por exemplo, os padrões síncronos Request/Response e Asynchronous Response Handler e os padrões assíncronos Request/Acknowledge/Pool e Request/Acknowledge/Callback, que foram discutidos em detalhes. Em todos os padrões para requisição e resposta de serviços que vimos, podemos nos deparar com problemas de indisponibilidade, o que levará a uma falha que será percebida pela aplicação consumidora. Se tal falha não for tratada adequadamente, poderemos ter o nível de confiabilidade (reliability) da solução diminuído, além da possibilidade de termos impactos para o negócio.

Neste post veremos como endereçar esta questão através de um padrão para tratamento de falhas de disponibilidade de serviços, também descrito no livro Service Design Patterns, de Ian Robinson.

Infraestruturas em geral muito dificilmente estão disponíveis em 100% do tempo. Comumente encontramos níveis de disponibilidade estabelecidas por SLA’s de 99.9%, 99.8% e 98%, que implicam em 8,76, 17,52 e 175 horas de indisponibilidade por ano, respectivamente. Menos comuns, porém, são infraestruturas estruturadas para 99.99% ou 99.999%, que representam 52,56 e 5,25 minutos de indisponibilidade por ano, respectivamente. Diversos são os recursos envolvidos para se estabelecer uma infraestrutura de alta disponibilidade e o custo associado é proporcionalmente alto. Mesmo em infraestruturas de alta disponibilidade, como as que garantem 99.999%, ainda temos períodos de indisponibilidade acordados em contrato, que podem calhar no momento exato da chamada de um serviço hospedado em tal infraestrutura.

É preciso ainda considerar que mesmo serviços hospedados na nuvem estão sujeitos à impossibilidade de acesso, seja por uma indisponibilidade prevista em um SLA definido pelo próprio provedor da infraestrutura, ou por indisponibilidade de banda da organização consumidora, ou ainda do seu provedor de internet (ISP), por exemplo.

Neste contexto, como garantir que chamadas à web services (sejam síncronas ou assíncronas) sejam bem sucedidas, independentemente de indisponibilidades de infraestrutura (falhas de rede ou de servidores)? Veremos a seguir mais detalhes sobre as possíveis causas de falhas em requisições de serviços e posteriormente possíveis soluções.

Tipos de Falha

Toleráveis

Em determinadas situações, falhas em chamadas de serviços são toleráveis. Considere, por exemplo, um serviço de busca de restaurantes, acionado pela implementação de uma funcionalidade acessada diretamente pelo usuário. Caso a requisição a este serviço não seja bem-sucedida, o usuário poderá ser notificado, podendo, por sua vez, acionar a mesma funcionalidade novamente, até que uma eventual falha temporária seja corrigida e o resultado esperado seja retornado.

Falha no estabelecimento de conexão

Um consumidor de serviço pode não ser capaz de se conectar ao serviço seja por instabilidade de rede – redes possuem intrinsicamente características de baixa confiabilidade – ou indisponibilidade de servidor (aquele que hospeda o serviço, por exemplo). Tais problemas podem ser temporários – uma instabilidade retomada em poucos segundos – ou crônica – uma indisponibilidade de servidor mais séria, por exemplo, como danos à CPU ou ao disco, em uma infraestrutura não projetada para alta disponibilidade.

Perda de conexão

Um consumidor de serviço pode enviar uma requisição ao serviço com sucesso, porém, pode ter sua conexão perdida enquanto o serviço ainda está processando sua requisição. Se o consumidor do serviço considerar que houve uma falha e enviar a mesma requisição novamente, é possível que dados sejam duplicados no provedor do serviço, o que causaria inconsistências e diminuiria a confiabilidade da solução.

Sobrecarga de servidores

Servidores podem estar sobrecarregados de tempos em tempos, de forma que se tais eventos coincidirem com momentos em que os serviços hospedados por eles são requisitados, haverá a possibilidade de o servidor recusar o estabelecimento da conexão ou não ser capaz de processá-la.

Timeout

Seja por sobrecarga de servidores, ou por qualquer falha que faça com que o servidor destino demore mais para responder do que o normal, um timeout poderá ser lançado no consumidor do serviço. A configuração e um tempo condizente de timeout é de extrema importância, para que o consumidor do serviço não fique bloqueado indefinidamente em tais situações. É importante notar que quando um timeout é lançado no consumidor do serviço, não é possível estabelecer se a requisição foi processada com sucesso ou não pelo serviço, uma vez que o processamento pode ter sido bem-sucedido momentos após a perda da conexão.

Indisponibilidade de URI

Uma vez estabelecido o serviço em produção, tal problema é menos comum. Porém, existem cenários de implementação que podem potencializar situações como esta. Serviços que implementam o padrão REST, por exemplo, frequentemente retornam como resposta URI’s para outras funcionalidades / dados. Tais URI’s podem ou ser inválidas por um bug de implementação ou podem ainda não estar disponíveis no momento da sua requisição. Este último cenário é conhecido como “race condition”, onde o consumidor do serviço compete com o serviço em si. Se o cliente for mais rápido, então links providos na comunicação anterior podem ser inválidos. Porém, se o cliente aguardar ou tentar novamente, as mesmas URI’s serão válidas posteriormente.

Possíveis soluções

A utilização de um sistema de enfileiramento de mensagens, como Microsoft Message Queue ou WebSphere MQ, resolveria o problema, uma vez que tais sistemas implementam o que se chama de garantia de entrega. Com a garantia de entrega (ou guaranteed delivery), quando uma fila remota não está disponível ou acessível, as mensagens são guardadas em uma fila local até que a infraestrutura remota seja restabelecida. Uma vez que a infraestrutura de enfileiramento de mensagens remota esteja estabelecida novamente, as mensagens pendentes serão entregues, podendo ser consumidas pelo sistema destino.

O problema com esta abordagem é que ele requer um protocolo de comunicação específico e proprietário, o pode não ser viável ou acessível para qualquer sistema. Ou seja, a interoperabilidade provida por protocolos de comunicação estabelecidos sobre HTTP, como SOAP e REST, não é mantida em tal abordagem. Além disso, a exposição de sistemas de enfileiramento de mensagens diretamente através de um firewall corporativo para consumidores externos à organização pode implicar na necessidade de abertura de portas, o que junto com outras questões, podem implicar em riscos à segurança.

Como endereçar então falhas em requisições de web servies de forma adequada?

Este é tópico do próximo post, onde será detalhado o padrão Idempotent Retry Pattern.

Até lá!

Synchronous x Asynchronous Services – Parte 2

Livro Service Design Patterns

Olá pessoal,

No post anterior vimos alguns padrões para modelos de processamento síncronos de web services. Vimos também os problemas decorrentes destes padrões, como por exemplo, o acoplamento temporal, que está relacionado à dependência que consumidores de serviços síncronos possuem com relação ao tempo de processamento do serviço, para que a operação seja bem sucedida. Problemas com estouro do tempo de resposta previsto (timeout) podem fazer com que mensagens sejam perdidas, diminuindo a confiabilidade da abordagem. Outros problemas relacionados também são, por exemplo, a dependência com relação à disponibilidade de todos os demais sistemas subjacentes ao serviço (sistemas gerenciadores de banco de dados, rede, servidores de aplicação, sistema de arquivos, etc.). Caso haja qualquer indisponibilidade em tais componentes, consumidores de serviços síncronos são diretamente afetados. Além disso, cargas acima do planejado em serviços que implementam o padrão Request/Response comprometem seu funcionamento e o da infraestrutura que o suporta, uma vez que todas as requisições são processadas assim que recebidas, dado o fato de que o número de requisições a serem processadas em paralelo é, em geral, comandado pelo cliente.

Para endereçar tais questões, no livro Service Design Patterns é sugerido à utilização de padrões assíncronos, e a utilização de message queues seria uma alternativa. Tal mecanismo permite que um cliente envie uma mensagem para uma fila remota em qualquer horário, independentemente do estado operacional do sistema destino. Usualmente, mensagens são salvas em filas locais até que as filas destino estejam disponíveis. Consumidores de mensagens podem proteger recursos dos sistemas remotos pela implementação de mecanismos de “throttling” (afunilamento – controle da taxa de Fluxo do padrão Request/Acknowledgeprocessamento de mensagens), desta forma endereçando requisitos de escalabilidade e disponibilidade de forma mais eficiente do que o padrão síncrono Request/Response visto anteriormente.

Se por um lado a utilização de message queues resolve boa parte dos problemas, por outro, novos problemas podem ser introduzidos. O uso de mensageria, em geral, é aconselhado como uma abordagem interna à corporação, ou seja, não deveria ser exposto diretamente além do firewall corporativo, seja por questões de segurança, seja por acoplar consumidores externos às tecnologias específicas dos sistemas de mensageria.

Para endereçar tais questões, é sugerida então a utilização do padrão de web services Request/Acknowledge, no qual um web service recebe uma requisição, a encaminha para um processo em background (uma thread secundária, por exemplo) e então retorna uma mensagem ao consumidor (acknowledgment) contendo um identificador único para referência futura. Veja como isso funciona no diagrama de sequencia ao lado (direito).

Em diversas situações apenas o recebimento de um “acknowledgment” é suficiente para o consumidor saber que sua requisição foi armazenada para processamento posterior. Porém, em outras situações, um cliente pode precisar de uma resposta, seja, por exemplo, de um processo de longa duração iniciado pela requisição inicial. Imagine um cenário em que uma requisição é enviada contendo uma solicitação de compra. Um retorno (acknowledgment) é enviado para consumidor informando que a solicitação foi recebida e que será processada. Um acknowledgment contendo um ID único serve como um protocolo de recebimento, um recibo. Quando todos os processos de aprovação da compra (sejam automáticos ou manuais) forem finalizados, o que pode demorar horas ou dias, dependendo do processo da organização, o cliente deverá ser informado, para que possa tomar outras ações.

Existem três formas no qual o padrão Request/Acknowledge permite prover respostas assíncronas aos consumidores de serviços. Vejamos a seguir.

Request/Acknowledge/Poll

Fluxo do padrão Request/Acknowledge/PollNeste padrão, uma vez que o cliente possui um acknowledge contendo um identificador único da sua requisição, ele fica constantemente consultando um outro serviço pelo resultado do seu processamento. Veja no diagrama de sequencia ao lado (esquerdo) a ilustração do fluxo deste padrão.

Os problemas decorrentes da utilização deste padrão estão relacionados ao intervalo de tempo em que o cliente efetua consultas pelo resultado final da operação. Se o intervalo de tempo for alto, então poderá haver um atraso entre o tempo em que o resultado final está pronto e o tempo em que ele é obtido. Se for baixo, então uma carga excessiva poderá ser colocada nos servidores envolvidos, além de aumentar trafego de rede.

Request/Acknowledge/Callback e Request/Acknowledge/Relay

No padrão Request/Acknowledge/Callback ao invés do cliente ficar constantemente buscando pelo resultado final da operação, ele é avisado através de um serviço que ele deve prover ou através do encaminhamento para outras partes interessadas. Esta última variação descreve o padrão Request/Acknowledge/Relay. A vantagem de tais abordagens com relação ao Request/Acknowledge/Poll está no tempo em que o cliente receberá a resposta e nos recursos consumidos para tal. Veja no diagrama de sequencia a mais abaixo (à direita) a ilustração do fluxo descrito.

Note que a forma pela qual o processador de requests pode saber para qual serviço ele deve retornar o resultado pode ser tanto através de um endereço provido no request inicial, pelo próprio cliente (veja, por exemplo, WS-Addressing), quanto através de configurações que relacionem o tipo de mensagem / processamento aos destinatários interessados (relay). Quando os destinatários de mensagens de callback são especificados pelo consumidor, cuidados especiais devem ser tomados para que eles não sejam alterados no meio do caminho. Segurança no nível de transFluxo do padrão Request/Acknowledge/Callbackporte ou mesmo WS-Security podem ser usados para mitigar este risco.

Algumas considerações devem ser levadas em conta antes de optar por um dos padrões. Em geral, o padrão Request/Acknowledge/Poll é mais simples de se implementar e de se depurar do que o padrão Request/Acknowledge/Callback. O planejamento de capacity também é diferenciado dentre as abordagens. Se o callback for efetuado sempre para um destinatário apenas, então o número de mensagens de resposta deve ser semelhante ao que se teria no padrão Request/Response. Porém, se o número de destinatários for significante e se houver necessidade de transformar mensagens em formatos específicos para cada destinatário, então, os recursos de infraestrutura necessários devem ser maiores, o que pode implicar em investimentos mais significativos.

O padrão Request/Acknowledge/Callback pode não ser viável em cenários em que o cliente não pode ou não está disposto a prover um serviço para receber retornos, seja pela necessidade de abertura de porta para recebimento de trafego de dados, seja pela falta de recursos para prover infraestrutura necessária. Neste caso, a única alternativa possível para o recebimento de retornos seria o Request/Acknowledge/Poll.

Conclusão

Diante de tantos fatores a serem levados em consideração quando da escolha por um dos padrões mencionados, uma “Trade-off Analysis” pode lhe ser útil para ajudar em sua decisão, dado seu contexto de aplicação.

Neste post ficamos por aqui. Até o próximo!

Synchronous x Asynchronous Services – Parte 1

Olá pessoal,

Livro Service Design Patterns

Neste post gostaria de trazer um assunto bastante recorrente em discussões relacionadas à integração, principalmente quando o meio escolhido para a tal é web service: quando que serviços devem ser síncronos ou assíncronos e quais as vantagens e desvantagens de ambas as abordagens. Além disso, discutiremos também, para o caso de serviços assíncronos, quais os padrões que podemos considerar para retornarmos um determinado resultado para o chamador do serviço, uma vez que o processamento tenha sido concluído. Padrões como Request/Response, Asynchronous Response Handler, Request/Acknowledge/Poll e Request/Acknowledge/Callback serão explicados, bem como o impacto da sua adoção na forma como os serviço são estruturados, o que incorre em esforço de desenvolvimento, timing de atualização e recuperação de informações, além de disponibilidade e escalabilidade do serviço provido. Neste primeira parte (parte 1) focarei em em padrões de serviços síncronos (padrão Request/Response e Asynchronous Response Handler) e no seguinte fecharei a comparação com os padrões de implementação de serviços assíncronos (Request/Acknowledge/Poll e Request/Acknowledge/Callback).

Todas estas questões e diversas outras, como padrões de APIs de serviços, padrões de interação client-service (que discutiremos em parte neste artigo), padrões para gerenciamento de requisição e resposta, padrões para implementação de serviços, padrões de infraestrutura de serviços e padrões de evolução de serviços, todos bastante relevantes e úteis em qualquer discussão que envolva web service como meio de integração, podem ser encontradas no livro Service Design Patterns de Robert Daigneau, que conta com prefácio de nada mais nada menos que Martin Fowler, além de Ian Robinson.

Serviços que implementam o padrão Request/Response

Padrão Request/Response

Um serviço que implementa o padrão Request/Response processa requisições assim que elas são recebidas, retornando resultados em uma mesma conexão de um cliente, de forma síncrona. Uma vez que o cliente submeta uma requisição, usualmente ele não continua com seu processamento até que uma resposta seja retornada. Na utilização deste padrão, frequentemente assume-se que o processamento será concluído em apenas alguns segundos. Dentre os padrões que serão abordados, o padrão Request/Response é mais simples de se implementar, depurar e testar, uma vez que funciona como uma chamada remota de uma operação, com parâmetros de entrada e resposta síncrona. Veja a exemplificação do padrão Request/Response no diagrama de sequencia ao lado.

O padrão Request/Response é indicado para casos em que uma resposta imediata seja necessária, como por exemplo, uma página web que proveja uma funcionalidade para consulta de abertura de vagas, cuja consulta das vagas disponíveis seja provida por um serviço.

Acoplamento temporal (temporal coupling)

A adoção do padrão Request/Response incorre em algumas implicações. Acoplamento temporal é uma delas. O acoplamento temporal remete à dependência do tempo de resposta que um serviço que implementa o padrão Request/Response implica para seu consumidor. No padrão Request/Response é assumido que o serviço sempre poderá processar uma requisição quando esta for recebida e que uma resposta será enviada assim que o processamento for encerrado. A implicação neste caso é que todos os sistemas dos quais o serviço depende (banco de dados, servidores de arquivos, etc.) sempre devem estar operacionais e sempre devem estar aptos a processar requisições imediatamente. Se tais sistemas estiverem indisponíveis, seja por uma falha ou por uma parada programada para manutenção, então as requisições dos clientes poderão ser rejeitadas.

Problemas relacionados ao tempo de resposta do serviço podem ainda acontecer mesmo quando todos os recursos dos quais o serviço dependem estão disponíveis. Uma vez que este padrão requer que requisições sejam processadas assim que recebidas, um grande volume de requisições pode comprometer a capacidade do sistema. Ao adotar tal padrão é preciso compreender a carga típica que o serviço deterá ter e projetar a capacidade de servidores, bancos de dados, rede, etc. de forma a endereçar tais cargas. Uma arquitetura tal deve ser projetada para que seja possível escalar horizontal ou verticalmente tais recursos, uma vez que as demandas de requisição aumentem ao longo do tempo. A adoção dos padrões assíncronos Request/Acknowledge/Poll e Request/Acknowledge/Callback, que serão vistos no próximo post, ajuda a mitigar esta necessidade, uma vez que transfere do cliente do serviço para o provedor do serviço o controle das requisições que serão processadas em paralelo.

O acoplamento temporal também traz implicações relacionadas ao tempo em que o consumidor do serviço aguardará por uma resposta antes que um timeout seja lançado. Nestes casos, uma vez que o processamento já tenha sido iniciado pelo serviço, a resposta não seria recebida pelo cliente, implicando em perda de sincronismo ou inconsistência de dados. As razões para que um serviço demore mais para responder do que o tempo planejado são inúmeras. Atividades que requeiram maior I/O, altos níveis de trafego de rede são exemplos comuns. Neste ponto, mais uma vez os padrões de serviços assíncronos são mais vantajosos.

Client-side Blocking / Asynchronous Response Handler

Por padrão, clientes de serviços que implementam o padrão Request/Response aguardam pela resposta do serviço invocado sem realizar outras operações no meio tempo. Esta característica é conhecida como “Client-side Blocking”, uma vez que o cliente fica bloqueado até que uma resposta do serviço chamado seja retornada. Para casos em que se deseje aproveitar o tempo de espera de um serviço processando outras atividades, pode-se utilizar o padrão denominado “Asynchronous Response Handler” em conjunto com o padrão Request/Response, o qual permite que o cliente efetue requisições para um serviço Request/Response, delegando o recebimento da resposta para um thread apartada da thread principal, de forma que outras atividades sejam executadas na thread principal logo após a requisição do serviço. Veja no diagrama de sequencia mais abaixo a ilustração desta implementação.

É importante destacar que este padrão também não garante que respostas não sejam perdidas, como já descrito anteriormente.

Sync Services with Async Response Handler

Por todos os motivos apresentados, podemos concluir que o padrão Request/Response deve ser usado apenas quando for possível garantir que o tempo médio de resposta do serviço seja relativamente baixo, e que o cliente será projetado para tolerar perda de respostas. No próximo post veremos como os padrões assíncronos ajudam a mitigar os riscos relacionados ao acoplamento temporal, à perda de sincronismo e inconsistência de dados, além de permitir que o cliente não fique bloqueado enquanto aguarda o resultado do processamento.

Neste post ficamos por aqui. Até o próximo!

AOP e Design Patterns na prática

Edição número 69 da revista .NET Magazine
Olá pessoal!

Em novembro de 2009 foi publicado um artigo que escrevi sobre Aspect Oriented Programming, Design Patterns e caching. Pois é, são diversos assuntos em apenas um artigo! A publicação foi feita em uma revista técnica renomada, conhecida e distribuída em todo o Brasil, a .NET Magazine. O artigo foi matéria de capa da revista em sua edição número 69. Confira a imagem ao lado.

Abaixo segue o link para sua versão digital no site da editora:

http://www.devmedia.com.br/post-15239-AOP-e-Design-Patterns-na-pratica.html