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

NGINX | 24 de maio de 2018

A versão do módulo JavaScript do NGINX lançada com o NGINX Plus R15 agora pode emitir subsolicitações, o que significa que as solicitações podem ser iniciadas no código JavaScript. Isso permite atender a um conjunto totalmente novo de casos de uso.

Um desses casos de uso é o agrupamento de solicitações de API, de modo que uma única solicitação de API de um cliente possa ser transformada em várias solicitações de API para um conjunto de servidores de backend, e as respostas sejam agregadas em uma única resposta para o cliente. Neste blog, usamos um site de comércio eletrônico como exemplo: quando o cliente solicita informações sobre um produto específico, são feitas subsolicitações a três serviços de backend: catálogo, estoque e avaliações de clientes.

Este post se baseia no exemplo de subsolicitação do anúncio do NGINX Plus R15, que mostra como usar subsolicitações para enviar a mesma solicitação a dois servidores de backend e retornar ao cliente apenas a primeira resposta.

[Editor – Este post é um dos vários que exploram casos de uso do módulo JavaScript do NGINX. Para ver a lista completa, consulte Casos de uso do módulo JavaScript do NGINX.

A publicação foi atualizada para usar a js_import diretiva, que substitui a diretiva js_include no NGINX Plus R23 e versões posteriores. Para obter mais informações, consulte a documentação de referência do módulo JavaScript do NGINX – a seção Exemplo de configuração mostra a sintaxe correta para os arquivos de configuração do NGINX e JavaScript.]

Introdução

O objetivo deste post é fornecer exemplos funcionais, simples e diretos de processamento em lote de requisições de API. Os exemplos atendem a todos os seguintes requisitos:

  • O método HTTP GET é usado para todas as solicitações.
  • Todas as respostas estão no formato JSON.
  • Há suporte para dois estilos de solicitações de API: observe que, em ambos os estilos, pode haver argumentos adicionais na string de consulta.
    • O argumento para o programa da API é o elemento final do URI. Chamamos isso de estilo de solicitação por elemento final. Em nosso exemplo, uma solicitação do cliente para /batch-api/product/14286 gera solicitações para /myapi/catalog/14286, /myapi/inventory/14286 e /myapi/review/14286.
    • O argumento é identificado na string de consulta do URI. Chamamos isso de estilo de solicitação por string de consulta. No exemplo, uma solicitação para /batch-api2/product?item=14286 gera solicitações para /myapi/catalog.php?item=14286, /myapi/inventory.php?item=14286 e /myapi/review.php?item=14286.
  • O conjunto de subsolicitações acionadas por uma solicitação do cliente pode ser configurado dinamicamente, o que significa que podemos alterá-lo sem editar manualmente a configuração do NGINX Plus e recarregá-la.
  • As solicitações de API aos servidores de backend são independentes umas das outras.

Visão geral da solução

Além de usar o novo recurso de subsolicitação do NGINX JavaScript, esta solução utiliza o recurso de armazenamento de chave-valor do NGINX Plus, permitindo que alterações de configuração sejam feitas dinamicamente com a NGINX Plus API.

Os gráficos a seguir ilustram os dois estilos de solicitação compatíveis.

Estilo de solicitação de elemento final:

O cliente faz solicitações a uma API no estilo de elemento final

Estilo de solicitação por string de consulta:

O cliente faz solicitações a uma API usando parâmetros na string de consulta

Em ambos os exemplos, o cliente precisa obter informações sobre um produto nos serviços de catálogo, estoque e avaliações. Ele envia uma solicitação ao NGINX Plus, passando o número do item como parte do URI ou na string de consulta. Em seguida, as solicitações são enviadas aos três serviços, e as respostas são agregadas em uma única resposta para o cliente.

São necessários dois componentes para que isso funcione com o NGINX Plus: um programa JavaScript e a configuração do NGINX Plus.

O programa JavaScript

A função JavaScript batchAPI() é chamada para cada solicitação do cliente. Ela obtém a lista de URIs de API separadas por vírgulas do armazenamento de chave-valor e percorre cada uma delas, fazendo uma subsolicitação para cada URI e especificando a função de callback done() para processar cada resposta. Para solicitações no estilo de elemento final, o último elemento da URI, armazenado na variável do NGINX $uri_suffix, é passado como a string de consulta de cada subsolicitação, juntamente com quaisquer outros argumentos da string de consulta presentes na URI original do cliente. Para solicitações no estilo de string de consulta, a string de consulta das solicitações do cliente é passada como a string de consulta de cada subsolicitação.

As chamadas são feitas na ordem em que estão listadas no armazenamento de chave-valor, mas são assíncronas, portanto, as respostas podem retornar em qualquer ordem. As respostas são agregadas em uma única resposta ao cliente na ordem em que são recebidas. Veja uma versão mínima do programa JavaScript:

Carregando exemplo de código…

Uma versão do programa JavaScript com tratamento de erros, registros de log e comentários mais abrangentes está disponível no repositório GitHub Gist como batch-api.js.

Configuração mínima do NGINX Plus

A configuração do NGINX Plus a seguir implementa os dois estilos de solicitação discutidos acima, usando um grupo de servidores upstream. Para simplificar, essa configuração pressupõe que os servidores upstream sejam capazes de converter uma chamada no formato /myapi/serviço/item# (estilo de elemento final) em /myapi/serviço.php/?item=item# (estilo de string de consulta), que é o formato de URI “nativo” do PHP, a linguagem usada em nossos serviços de exemplo de catálogo, inventário e avaliações.

Para uma configuração mais abrangente do NGINX Plus que realize a conversão, consulte Expansão da configuração do NGINX para converter URIs abaixo.

Vamos analisar o arquivo de configuração seção por seção e explicar o que cada parte faz:

  • Importe o arquivo JavaScript:

    Carregando exemplo de código…

  • Defina um armazenamento de chave-valor para manter a lista de solicitações de API em que o último elemento do URI identifica o argumento do programa da API. A chave usa a variável $uri_prefix para capturar a parte do URI anterior à última /:

    Carregando exemplo de código…

    No NGINX Plus R16 e versões posteriores, você pode aproveitar dois recursos adicionais de chave-valor: para obter instruções sobre como configurar a sincronização de armazenamentos de chave-valor, consulte o Guia de Administração do NGINX Plus.
    • Defina um tempo de expiração para as entradas em um armazenamento de chave-valor adicionando o parâmetro timeout à diretiva keyval_zone. Por exemplo, para que cada URI em lote expire diariamente, adicione timeout=1d.
    • Sincronize o armazenamento de chave-valor em um cluster de instâncias do NGINX Plus adicionando o parâmetro sync à diretiva keyval_zone. Nesse caso, você também deve incluir o parâmetro timeout.
  • Defina outro armazenamento de chave-valor para APIs em que o argumento é identificado na string de consulta. Aqui, a chave ($uri) captura o URI completo, sem incluir a string de consulta:

    Carregando exemplo de código…

  • Defina dois mapas para dividir o URI em duas partes para APIs que aceitam solicitações nas quais o argumento é o último elemento do URI. A variável $uri_prefix captura os elementos do URI antes da última /, e $uri_suffix captura o elemento final:

    Carregando exemplo de código…

  • Defina o grupo upstream de servidores de API (neste caso, eles estão sendo executados no localhost junto com o NGINX Plus):

    Carregando exemplo de código…

  • Defina o servidor virtual que processa solicitações e subsolicitações de clientes:

    Carregando exemplo de código…

  • Defina um local para processar solicitações de clientes que usam o estilo de elemento final, indicado à função batchAPI ao definir a variável $batch_api_arg_in_uri como on:

    Carregando exemplo de código…

  • Defina um local para processar solicitações de clientes que usam o formato de string de consulta, o que é indicado à função batchAPI definindo a variável $batch_api_arg_in_uri como off:

    Carregando exemplo de código…

  • Defina o local que processa as subsolicitações:

    Carregando exemplo de código…

  • Habilite a API do NGINX Plus para que os dados possam ser mantidos no armazenamento de chave-valor:

    Carregando exemplo de código…

Veja a configuração completa:

Carregando exemplo de código…

Configurando as solicitações de API em lote

Estamos usando o recurso de armazenamento de chave-valor do NGINX Plus para mapear as solicitações recebidas dos clientes para um conjunto de solicitações de API a serem executadas. A configuração na seção anterior define armazenamentos de chave-valor separados para os dois estilos de solicitação:

  • O armazenamento de chave-valor para o estilo de elemento final é denominado batch_api e a chave é a variável $uri_prefix, que captura os elementos anteriores à última / do URI da solicitação.
  • O armazenamento de chave-valor para o formato de string de consulta é denominado batch_api2 e a chave é a variável $uri, que captura o URI completo da solicitação sem a string de consulta.

Em ambos os armazenamentos de chave-valor, o valor associado a cada chave é uma lista de URIs separadas por vírgulas, disponibilizadas em tempo de execução nas variáveis $batch_api ou $batch_api2.

Para solicitações no estilo de elemento final, queremos mapear uma solicitação do cliente para /batch-api/product para solicitações aos três serviços /myapi/catalog, /myapi/inventory e /myapi/review, de modo que uma solicitação para /batch-api/product/14286 resulte em solicitações para /myapi/catalog/14286, /myapi/product/14286 e /myapi/review/14286.

Para adicionar esses mapeamentos ao armazenamento de chave-valor batch_api, enviamos a seguinte solicitação à instância do NGINX Plus em execução na máquina local:

$ curl -iX POST -d '{"/batch-api/product":"/myapi/catalog,/myapi/inventory,/myapi/review"}' http://localhost/api/3/http/keyvals/batch_api

Para as solicitações no estilo de string de consulta, queremos mapear uma solicitação do cliente para /batch-api2/product para solicitações aos três serviços /myapi/catalog.php, /myapi/inventory.php e /myapi/review.php, de modo que uma solicitação para /batch-api2/product?item=14286 resulte em solicitações para /myapi/catalog?item=14286, /myapi/product?item=14286 e /myapi/review?item=14286.

Para adicionar esses mapeamentos ao armazenamento de chave-valor batch_api2, enviamos esta solicitação:

$ curl -iX POST -d '{"/batch-api2/product":"/myapi/catalog.php,/myapi/inventory.php,/myapi/review.php"}' http://localhost/api/3/http/keyvals/batch_api2

Executando os exemplos

As mesmas páginas PHP processam solicitações feitas nos dois estilos de requisição. Para simplificar, pressupomos que os servidores de backend sejam capazes de converter URIs no estilo de elemento final (/myapi/serviço/item#) em URIs no estilo de string de consulta (/myapi/serviço.php?item=item#). Não é necessário converter URIs no estilo de string de consulta, pois esse é o formato de URI “nativo” dos programas PHP.

Todos os serviços retornam uma resposta no formato JSON que inclui o nome do serviço e o argumento do item. Por exemplo, uma solicitação para /myapi/catalog.php?item=14286 resulta na seguinte resposta de catalog.php:

{"service":"Catalog","item":"14286"}

Embora os programas PHP usados nestes exemplos incluam o nome do serviço na resposta, talvez isso não ocorra com todos os serviços. Para ajudar a associar as respostas aos serviços que as geraram, o programa JavaScript inclui o URI na resposta agregada.

Por exemplo, a resposta agregada a uma solicitação para /batch-api/product/14286 é a seguinte (embora a ordem das três respostas que a compõem possa variar):

[["/myapi/review/14286",{"service":"Review","item":"14286"}],["/myapi/inventory/14286",{"service":"Inventory","item":"14286"}],["/myapi/catalog/14286",{"service":"Catalog","item":"14286"}]]

Expandindo a configuração do NGINX Plus para traduzir URIs

Como mencionado, a configuração mínima do NGINX Plus discutida acima pressupõe que os servidores de API sejam capazes de converter URIs no formato /myapi/serviço/nº do item em /myapi/serviço.php/?item=nº do item. Também podemos implementar essa conversão na configuração do NGINX Plus fazendo as seguintes alterações.

  • Adicione um novo grupo upstream para receber as subsolicitações:

    Carregando exemplo de código…

  • Adicione um novo servidor virtual para escutar as solicitações recebidas pelo grupo upstream services. Quando solicitações no formato de string de consulta são recebidas, elas são simplesmente encaminhadas por proxy para o grupo upstream api_servers, pois o URI já tem a extensão .php. Quando solicitações no formato de elemento final são recebidas, o URI é reescrito para que o último elemento seja removido e convertido em um argumento de string de consulta:

    Carregando exemplo de código…

  • Altere o /myapi local para encaminhar as solicitações ao novo grupo de upstream:

    Carregando exemplo de código…

Esta é a configuração completa:

Carregando exemplo de código…

Componentes adicionais

Os programas JavaScript de exemplo e as configurações do NGINX Plus podem ser adaptados a outros estilos de APIs, mas, se você quiser fazer testes usando todos os componentes utilizados na criação desta publicação, eles estão disponíveis em nosso repositório Gist no GitHub, incluindo a configuração do NGINX Unit para disponibilizar as páginas PHP:

batch-api.js
catalog.php
inventory.php
review.php
unit.config

Conclusão

Estes exemplos mostram como agrupar solicitações de API em lotes e fornecer uma resposta agregada ao cliente. O armazenamento de chave-valor do NGINX Plus permite configurar dinamicamente as solicitações de API com a API do NGINX Plus. Os sistemas de API variam bastante em suas operações específicas, portanto, muitas melhorias podem ser feitas neste exemplo para adaptá-lo às necessidades de uma determinada API.

Você pode começar a testar as subsolicitações JavaScript do NGINX com o NGINX Open Source, mas, se quiser experimentar os exemplos de processamento em lote de APIs ou testar outros casos de uso que aproveitam recursos do NGINX Plus, como o armazenamento de chave-valor e a API do NGINX Plus, solicite uma avaliação gratuita de 30 dias e comece a experimentar.


Compartilhar

Sobre o autor

Rick Nelson
Rick NelsonVice-presidente regional de Engenharia de Soluções

Mais publicações de Rick Nelson

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.