Criando microsserviços: usando um gateway de API

NGINX | 15 de junho de 2015

Editor – Esta série de artigos em sete partes está agora completa:

  1. Introdução aos microsserviços
  2. Construindo microsserviços: usando um gateway de API (este artigo)
  3. Criando microsserviços: comunicação entre processos em uma arquitetura de microsserviços
  4. Descoberta de serviços em uma arquitetura de microsserviços
  5. Gerenciamento de dados orientado a eventos para microsserviços
  6. Escolhendo uma estratégia de implantação de microsserviços
  7. Refatorando um monólito em microsserviços

Você também pode baixar a coleção completa de artigos, além de informações sobre como implementar microsserviços usando o NGINX Plus, no formato de ebook – Microsserviços: do projeto à implantação. Confira também a nova página de soluções para microsserviços.

O primeiro artigo desta série de sete partes sobre projeto, desenvolvimento e implantação de microsserviços apresentou o padrão de arquitetura de microsserviços. Ele abordou as vantagens e desvantagens do uso de microsserviços e explicou como, apesar de sua complexidade, eles geralmente são a escolha ideal para aplicações complexas. Este é o segundo artigo da série e abordará o desenvolvimento de microsserviços usando um gateway de API.

Ao optar por desenvolver sua aplicação como um conjunto de microsserviços, você precisa decidir como os clientes da aplicação interagirão com esses microsserviços. Em uma aplicação monolítica, há apenas um conjunto de endpoints (normalmente replicados e com balanceamento de carga). Em uma arquitetura de microsserviços, no entanto, cada microsserviço disponibiliza um conjunto de endpoints que geralmente são bastante específicos. Neste artigo, analisamos como isso afeta a comunicação entre o cliente e a aplicação e propomos uma abordagem que utiliza um Gateway de API.

Introdução

Imagine que você esteja desenvolvendo um cliente móvel nativo para um aplicativo de compras. É provável que você precise implementar uma página de detalhes do produto, que exiba informações sobre qualquer produto selecionado.

Por exemplo, o diagrama a seguir mostra o que você verá ao rolar pelos detalhes do produto no aplicativo móvel da Amazon para Android.

Elementos indexados do aplicativo móvel da Amazon para Android, conforme aparecem na tela de um celular

Embora este seja um aplicativo para smartphones, a página de detalhes do produto exibe muitas informações. Por exemplo, além das informações básicas do produto (como nome, descrição e preço), esta página também mostra:

  • Número de itens no carrinho de compras
  • Histórico de pedidos
  • Avaliações de clientes
  • Aviso de estoque baixo
  • Opções de envio
  • Várias recomendações, incluindo outros produtos frequentemente comprados junto com este produto, outros produtos comprados por clientes que adquiriram este produto e outros produtos visualizados por clientes que compraram este produto
  • Opções alternativas de compra

Ao usar uma arquitetura de aplicação monolítica, um cliente móvel recuperaria esses dados fazendo uma única chamada REST (GET api.company.com/productdetails/productId) para a aplicação. Um balanceador de carga encaminha a solicitação para uma das N instâncias idênticas da aplicação. Em seguida, a aplicação consultaria várias tabelas do banco de dados e retornaria a resposta ao cliente.

Por outro lado, ao usar a arquitetura de microsserviços, os dados exibidos na página de detalhes do produto pertencem a vários microsserviços. Veja alguns dos possíveis microsserviços responsáveis pelos dados exibidos na página de detalhes do produto do exemplo:

  • Serviço de Carrinho de Compras – Número de itens no carrinho de compras
  • Serviço de pedidos – Histórico de pedidos
  • Serviço de Catálogo – Informações básicas do produto, como nome, imagem e preço
  • Serviço de avaliações – Avaliações de clientes
  • Serviço de estoque – Alerta de estoque baixo
  • Serviço de envio – Opções, prazos e custos de envio obtidos separadamente da API da transportadora
  • Serviço(s) de recomendação – Itens sugeridos

O cliente móvel do aplicativo de e-commerce precisa de uma forma de acessar as APIs RESTful dos sete microsserviços

Precisamos decidir como o cliente móvel acessará esses serviços. Vamos analisar as opções.

Comunicação direta entre cliente e microsserviço

Em teoria, um cliente poderia fazer solicitações diretamente a cada um dos microsserviços. Cada microsserviço teria um endpoint público (https://serviceName.api.company.name). Essa URL apontaria para o balanceador de carga do microsserviço, que distribui as solicitações entre as instâncias disponíveis. Para obter os detalhes do produto, o cliente móvel faria solicitações a cada um dos serviços listados acima.

Infelizmente, essa opção apresenta desafios e limitações. Um dos problemas é a incompatibilidade entre as necessidades do cliente e as APIs granulares disponibilizadas por cada um dos microsserviços. Neste exemplo, o cliente precisa fazer sete solicitações distintas. Em aplicações mais complexas, talvez seja necessário fazer muitas outras. Por exemplo, a Amazon descreve como centenas de serviços estão envolvidos na renderização da página de um produto. Embora um cliente pudesse fazer tantas solicitações em uma rede local (LAN), isso provavelmente seria ineficiente demais pela Internet pública e certamente seria inviável em uma rede móvel. Essa abordagem também torna o código do cliente muito mais complexo.

Outro problema de o cliente chamar diretamente os microsserviços é que alguns deles podem usar protocolos que não são adequados para a Web. Um serviço pode usar RPC binário do Thrift, enquanto outro pode usar o protocolo de mensagens AMQP. Nenhum desses protocolos é particularmente compatível com navegadores ou firewalls, sendo mais indicado para uso interno. Fora do firewall, uma aplicação deve usar protocolos como HTTP e WebSocket.

Outra desvantagem dessa abordagem é que ela dificulta a refatoração dos microsserviços. Com o tempo, talvez seja necessário mudar a forma como o sistema é dividido em serviços. Por exemplo, podemos unir dois serviços ou dividir um serviço em dois ou mais. No entanto, se os clientes se comunicarem diretamente com os serviços, realizar esse tipo de refatoração poderá ser extremamente difícil.

Devido a esses tipos de problemas, raramente faz sentido que os clientes se comuniquem diretamente com os microsserviços.

Usando um API Gateway

Geralmente, uma abordagem muito melhor é usar o que é conhecido como um Gateway de API. Um Gateway de API é um servidor que funciona como o único ponto de entrada no sistema. Ele é semelhante ao padrão Fachada do design orientado a objetos. O Gateway de API encapsula a arquitetura interna do sistema e fornece uma API adaptada a cada cliente. Ele também pode ter outras responsabilidades, como autenticação, monitoramento, balanceamento de carga, armazenamento em cache, formatação e gerenciamento de solicitações e tratamento de respostas estáticas.

O diagrama a seguir mostra como um API Gateway normalmente se encaixa na arquitetura:

Um gateway de API permite que os clientes móveis de um aplicativo de comércio eletrônico acessem as APIs RESTful de seus sete microsserviços

O API Gateway é responsável pelo roteamento e pela composição de solicitações, bem como pela tradução de protocolos. Todas as solicitações dos clientes passam primeiro pelo API Gateway, que as encaminha para o microsserviço apropriado. Muitas vezes, o API Gateway processa uma solicitação acionando vários microsserviços e agregando os resultados. Ele pode fazer a tradução entre protocolos web, como HTTP e WebSocket, e protocolos incompatíveis com a web usados internamente.

O API Gateway também pode fornecer uma API personalizada para cada cliente. Normalmente, ele disponibiliza uma API de granularidade grossa para clientes móveis. Considere, por exemplo, o cenário de detalhes do produto. O API Gateway pode fornecer um endpoint (/productdetails?productid=xxx) que permite a um cliente móvel obter todos os detalhes do produto com uma única solicitação. O API Gateway processa a solicitação acionando os diversos serviços – informações do produto, recomendações, avaliações etc. – e combinando os resultados.

Um ótimo exemplo de API Gateway é o API Gateway da Netflix. O serviço de streaming da Netflix está disponível em centenas de tipos diferentes de dispositivos, incluindo televisores, conversores de TV, smartphones, consoles de videogame, tablets etc. Inicialmente, a Netflix tentou oferecer uma API única para todos para seu serviço de streaming. No entanto, descobriu que isso não funcionava bem devido à grande variedade de dispositivos e às necessidades específicas de cada um. Hoje, a empresa usa um API Gateway que fornece uma API adaptada a cada dispositivo por meio da execução de código de adaptador específico para o dispositivo. Normalmente, um adaptador processa cada solicitação invocando, em média, de seis a sete serviços de backend. O API Gateway da Netflix processa bilhões de solicitações por dia.

Benefícios e desvantagens de um API Gateway

Como seria de esperar, o uso de um API Gateway apresenta vantagens e desvantagens. Uma das principais vantagens é que ele encapsula a estrutura interna da aplicação. Em vez de precisar invocar serviços específicos, os clientes simplesmente se comunicam com o gateway. O API Gateway fornece uma API específica para cada tipo de cliente. Isso reduz o número de idas e vindas entre o cliente e a aplicação, além de simplificar o código do cliente.

O API Gateway também apresenta algumas desvantagens. Trata-se de mais um componente de alta disponibilidade que precisa ser desenvolvido, implantado e gerenciado. Também existe o risco de o API Gateway se tornar um gargalo no desenvolvimento. Os desenvolvedores precisam atualizar o API Gateway para expor os endpoints de cada microsserviço. É importante que o processo de atualização do API Gateway seja o mais simples possível. Caso contrário, os desenvolvedores serão obrigados a esperar na fila para atualizar o gateway. Apesar dessas desvantagens, para a maioria das aplicações do mundo real, faz sentido usar um API Gateway.

Implementando um API Gateway

Agora que analisamos as motivações e os prós e contras do uso de um API Gateway, vamos examinar várias questões de design que você precisa considerar.

Desempenho e escalabilidade

Apenas algumas empresas operam na escala da Netflix e precisam processar bilhões de solicitações por dia. No entanto, para a maioria das aplicações, o desempenho e a escalabilidade do API Gateway costumam ser muito importantes. Portanto, faz sentido desenvolver o API Gateway em uma plataforma compatível com E/S assíncrona e não bloqueante. Há diversas tecnologias que podem ser usadas para implementar um API Gateway escalável. Na JVM, você pode usar um dos frameworks baseados em NIO, como Netty, Vertx, Spring Reactor ou JBoss Undertow. Uma opção popular fora da JVM é o Node.js, uma plataforma desenvolvida com base no mecanismo JavaScript do Chrome. Outra opção é usar o NGINX Plus. O NGINX Plus oferece um servidor web e proxy reverso maduro, escalável e de alto desempenho, que pode ser facilmente implantado, configurado e programado. O NGINX Plus pode gerenciar autenticação, controle de acesso, balanceamento de carga das solicitações e armazenamento de respostas em cache, além de fornecer verificações de integridade e monitoramento com reconhecimento da aplicação.

Usando um modelo de programação reativa

O API Gateway processa algumas solicitações simplesmente encaminhando-as ao serviço de backend apropriado. Outras solicitações são processadas por meio da invocação de vários serviços de backend e da agregação dos resultados. Em algumas solicitações, como uma solicitação de detalhes de um produto, as solicitações aos serviços de backend são independentes entre si. Para minimizar o tempo de resposta, o API Gateway deve executar solicitações independentes simultaneamente. No entanto, às vezes há dependências entre as solicitações. O API Gateway pode precisar primeiro validar a solicitação chamando um serviço de autenticação antes de encaminhá-la a um serviço de backend. Da mesma forma, para obter informações sobre os produtos na lista de desejos de um cliente, o API Gateway deve primeiro recuperar o perfil do cliente que contém essas informações e, em seguida, recuperar as informações de cada produto. Outro exemplo interessante de composição de APIs é o Video Grid da Netflix.

Escrever código de composição de APIs usando a abordagem tradicional de callbacks assíncronos leva rapidamente ao inferno dos callbacks. O código ficará confuso, difícil de entender e sujeito a erros. Uma abordagem muito melhor é escrever o código do API Gateway em estilo declarativo, usando uma abordagem reativa. Alguns exemplos de abstrações reativas são Future em Scala, CompletableFuture no Java 8 e Promise em JavaScript. Há também as Reactive Extensions (também chamadas de Rx ou ReactiveX), originalmente desenvolvidas pela Microsoft para a plataforma .NET. A Netflix criou o RxJava para a JVM especificamente para uso em seu API Gateway. Há também o RxJS para JavaScript, que é executado tanto no navegador quanto no Node.js. O uso de uma abordagem reativa permitirá que você escreva um código de API Gateway simples e eficiente.

Invocação de serviço

Uma aplicação baseada em microsserviços é um sistema distribuído e precisa usar um mecanismo de comunicação entre processos. Há dois estilos de comunicação entre processos. Uma opção é usar um mecanismo assíncrono baseado em mensagens. Algumas implementações usam um broker de mensagens, como JMS ou AMQP. Outras, como o Zeromq, não usam broker, e os serviços se comunicam diretamente. O outro estilo de comunicação entre processos é um mecanismo síncrono, como HTTP ou Thrift. Normalmente, um sistema usa tanto o estilo assíncrono quanto o síncrono. Ele pode até mesmo usar várias implementações de cada estilo. Consequentemente, o API Gateway precisará oferecer suporte a diversos mecanismos de comunicação.

Descoberta de serviços

O API Gateway precisa saber a localização (endereço IP e porta) de cada microsserviço com o qual se comunica. Em uma aplicação tradicional, provavelmente seria possível definir essas localizações de forma fixa, mas, em uma aplicação moderna de microsserviços baseada em nuvem, esse é um problema nada trivial. Os serviços de infraestrutura, como um agente de mensagens, geralmente têm uma localização estática, que pode ser especificada por meio de variáveis de ambiente do sistema operacional. No entanto, determinar a localização de um serviço da aplicação não é tão simples. Os serviços da aplicação têm localizações atribuídas dinamicamente. Além disso, o conjunto de instâncias de um serviço muda dinamicamente devido ao escalonamento automático e às atualizações. Consequentemente, o API Gateway, assim como qualquer outro cliente de serviço no sistema, precisa usar o mecanismo de descoberta de serviços do sistema: Descoberta no lado do servidor ou Descoberta no lado do cliente. Um artigo posterior descreverá a descoberta de serviços em mais detalhes. Por enquanto, vale observar que, se o sistema usar a Descoberta no lado do cliente, o API Gateway deverá ser capaz de consultar o Registro de Serviços, que é um banco de dados de todas as instâncias de microsserviços e suas respectivas localizações.

Como lidar com falhas parciais

Outro problema que você precisa abordar ao implementar um API Gateway é o das falhas parciais. Esse problema ocorre em todos os sistemas distribuídos sempre que um serviço chama outro que está respondendo lentamente ou está indisponível. O API Gateway nunca deve ficar bloqueado indefinidamente aguardando um serviço downstream. No entanto, a forma como ele lida com a falha depende do cenário específico e de qual serviço está falhando. Por exemplo, se o serviço de recomendações não responder no cenário de detalhes do produto, o API Gateway deverá retornar ao cliente os demais detalhes do produto, pois eles ainda são úteis para o usuário. As recomendações podem ficar vazias ou ser substituídas, por exemplo, por uma lista fixa dos dez itens mais populares. No entanto, se o serviço de informações do produto não responder, o API Gateway deverá retornar um erro ao cliente.

O API Gateway também poderia retornar dados em cache, caso estivessem disponíveis. Por exemplo, como os preços dos produtos mudam com pouca frequência, o API Gateway poderia retornar dados de preços armazenados em cache se o serviço de preços estivesse indisponível. Os dados podem ser armazenados em cache pelo próprio API Gateway ou em um cache externo, como Redis ou Memcached. Ao retornar dados padrão ou armazenados em cache, o API Gateway garante que as falhas do sistema não afetem a experiência do usuário.

Netflix Hystrix é uma biblioteca extremamente útil para escrever código que invoca serviços remotos. O Hystrix encerra por tempo limite as chamadas que excedem o limite especificado. Ele implementa o padrão circuit breaker, que evita que o cliente espere desnecessariamente por um serviço que não responde. Se a taxa de erros de um serviço exceder um limite especificado, o Hystrix aciona o circuit breaker, e todas as solicitações falharão imediatamente durante um período determinado. O Hystrix permite definir uma ação alternativa para quando uma solicitação falhar, como ler dados de um cache ou retornar um valor padrão. Se você usa a JVM, sem dúvida deve considerar o uso do Hystrix. E, se estiver executando em um ambiente que não seja JVM, deve usar uma biblioteca equivalente.

Resumo

Para a maioria das aplicações baseadas em microsserviços, faz sentido implementar um API Gateway, que atua como um único ponto de entrada em um sistema. O API Gateway é responsável pelo roteamento e pela composição de solicitações, bem como pela tradução de protocolos. Ele fornece uma API personalizada para cada cliente da aplicação. O API Gateway também pode ocultar falhas nos serviços de back-end retornando dados armazenados em cache ou dados padrão. No próximo artigo da série, veremos a comunicação entre serviços.

Editor – Esta série de artigos em sete partes está concluída:

  1. Introdução aos microsserviços
  2. Construindo microsserviços: usando um gateway de API (este artigo)
  3. Criando microsserviços: comunicação entre processos em uma arquitetura de microsserviços
  4. Descoberta de serviços em uma arquitetura de microsserviços
  5. Gerenciamento de dados orientado a eventos para microsserviços
  6. Escolhendo uma estratégia de implantação de microsserviços
  7. Refatorando um monólito em microsserviços

Você também pode baixar o conjunto completo de artigos, além de informações sobre como implementar microsserviços usando o NGINX Plus, no formato de ebook – Microsserviços: do projeto à implantação.

Para uma análise detalhada de outros casos de uso, confira nossa série de três artigos no blog, Implantação do NGINX Plus como gateway de API:

  • Parte 1 fornece instruções detalhadas de configuração para diversos casos de uso.
  • Parte 2 amplia esses casos de uso e analisa uma série de medidas de proteção que podem ser aplicadas para proteger e manter seguros os serviços de API de backend em produção.
  • Parte 3 explica como implantar o NGINX Plus como um gateway de API para serviços gRPC.

O blogueiro convidado Chris Richardson é o fundador da plataforma original CloudFoundry.com, uma das primeiras PaaS (plataforma como serviço) Java para o Amazon EC2. Atualmente, ele presta consultoria a organizações para aprimorar a forma como desenvolvem e implantam aplicações. Ele também publica regularmente sobre microsserviços em http://microservices.io.


Compartilhar

Publicações relacionadas no blog

Como o F5 NGINX One aprimora o gerenciamento e a observabilidade
NGINX | 10/10/2024

Como o F5 NGINX One aprimora o gerenciamento e a observabilidade

Descubra como o F5 NGINX One aprimora o gerenciamento e a observabilidade de ambientes híbridos e multicloud ao oferecer um console web centralizado baseado em SaaS, com insights em tempo real, conformidade automatizada e gerenciamento simplificado de configurações.

Do OpenAPI ao NGINX como gateway de API usando uma API declarativa
NGINX | 17/06/2024

Do OpenAPI ao NGINX como gateway de API usando uma API declarativa

Descubra como transformar uma definição de esquema OpenAPI em uma configuração NGINX totalmente funcional, operando como um API Gateway com a segurança de um Web Application Firewall e um Portal do Desenvolvedor, usando uma abordagem declarativa de API.

Como gerenciar picos repentinos de tráfego e sobrecarga do servidor
NGINX | 14/07/2021

Como gerenciar picos repentinos de tráfego e sobrecarga do servidor

Picos de tráfego e sobrecarga de servidores são preocupações sérias para varejistas online em qualquer época, mas especialmente durante a “Cyber Season” de compras de fim de ano. Detalhamos como você pode aproveitar as soluções de entrega de aplicações de nível de produção da NGINX para se preparar para aumentos repentinos de tráfego.

Distribuição segura de chaves privadas SSL com o NGINX
NGINX | 02/04/2019

Distribuição segura de chaves privadas SSL com o NGINX

Descrevemos três maneiras progressivamente mais seguras de proteger chaves privadas SSL ao configurar o NGINX para processar tráfego HTTPS: permitir acesso de leitura apenas ao usuário root, criptografar as chaves com senhas armazenadas separadamente e distribuir as senhas a partir de um repositório central.

Agrupando solicitações de API em lotes com NGINX Plus e o módulo JavaScript do NGINX
NGINX | 24/05/2018

Agrupando solicitações de API em lotes com NGINX Plus e o módulo JavaScript do NGINX

O módulo JavaScript do NGINX lançado com o NGINX Plus R15 oferece suporte a subsolicitações, possibilitando uma classe totalmente nova de casos de uso para o NGINX Plus. Este exemplo completo também usa a API do NGINX Plus e os módulos de chave-valor para converter solicitações de API dos clientes em solicitações separadas para as APIs dos microsserviços que compõem um aplicativo.

Como superar o esgotamento de portas efêmeras no NGINX e no NGINX Plus
NGINX | 19/04/2016

Como superar o esgotamento de portas efêmeras no NGINX e no NGINX Plus

Confira dicas para evitar o esgotamento de portas efêmeras com ajustes no kernel do Linux, conexões keepalive e conexões vinculadas dinamicamente a endereços IP locais.