OpenTracing para NGINX e NGINX Plus

NGINX | 17 de junho de 2019

Apesar de todos os seus benefícios, uma arquitetura de microsserviços também introduz novas complexidades. Uma delas é o desafio de rastrear as solicitações à medida que são processadas, com os dados fluindo entre todos os microsserviços que compõem a aplicação. Uma nova metodologia chamada rastreamento distribuído (de solicitações) foi criada para essa finalidade, e o OpenTracing é uma especificação e um conjunto padronizado de APIs destinados a orientar o projeto e a implementação de ferramentas de rastreamento distribuído.

No NGINX Plus Release 18 (R18), adicionamos o módulo NGINX OpenTracing ao nosso repositório de módulos dinâmicos (ele já estava disponível como um módulo de terceiros no GitHub havia alguns anos). Uma grande vantagem do módulo NGINX OpenTracing é que, ao instrumentar o NGINX e o NGINX Plus para rastreamento distribuído, você obtém dados de rastreamento para cada aplicação que passa pelo proxy, sem precisar instrumentar as aplicações individualmente.

Neste blog, mostramos como habilitar o rastreamento distribuído de solicitações no NGINX ou NGINX Plus (para simplificar, daqui em diante usaremos apenas NGINX Plus). Fornecemos instruções para dois serviços de rastreamento distribuído (rastreadores, na terminologia do OpenTracing): Jaeger e Zipkin. (Para ver uma lista de outros rastreadores, consulte a documentação do OpenTracing.) Para ilustrar o tipo de informação fornecida pelos rastreadores, comparamos o processamento de solicitações antes e depois de habilitar o cache do NGINX Plus.

Um rastreador tem dois componentes básicos:

  • Um agente que coleta dados de rastreamento de aplicativos em execução no mesmo host em que ele está sendo executado. No nosso caso, o “aplicativo” é o NGINX Plus, e o agente é implementado como um plug-in.
  • Um servidor (também chamado de coletor) que recebe dados de rastreamento de um ou mais agentes e os exibe em uma interface centralizada. Você pode executar o servidor no host do NGINX Plus ou em outro host, conforme preferir.

Instalando um servidor de rastreamento

A primeira etapa é instalar e configurar o servidor para o rastreador de sua escolha. Fornecemos instruções para o Jaeger e o Zipkin; adapte-as conforme necessário para outros rastreadores.

Instalando o servidor Jaeger

Recomendamos o método a seguir para instalar o servidor Jaeger. Você também pode baixar imagens do Docker no URL especificado na Etapa 1.

  1. Acesse a página de download do Jaeger e baixe o binário para Linux (no momento da redação deste texto, jaeger-1.12.0-linux-amd64.tar).
  2. Mova o binário para /usr/bin/jaeger (criando o diretório primeiro, se necessário) e execute-o.
$ mkdir /usr/bin/jaeger$ mv jaeger-1.12.0-linux-amd64.tar /usr/bin/jaeger
$ cd /usr/bin/jaeger
$ tar xvzf jaeger-1.12.0-linux-amd64.tar.gz
$ sudo rm -rf jaeger-1.12.0-linux-amd64.tar.gz
$ cd jaeger-1.12.0-linux-amd64
$ ./jaeger-all-in-one
  1. Verifique se você consegue acessar a interface do Jaeger no navegador em http://endereço-IP-do-servidor-Jaeger:16686/ (16686 é a porta padrão do servidor Jaeger).

Instalando o servidor Zipkin

  1. Baixe e execute uma imagem Docker do Zipkin (estamos usando a porta 9411, que é a padrão).
$ docker run -d -p 9411:9411 openzipkin/zipkin
  1. Verifique se você consegue acessar a interface do Zipkin no navegador, em http://endereço-IP-do-servidor-Zipkin:9411/.

Instalação e configuração de um plug-in de rastreamento

Execute estes comandos no host do NGINX Plus para instalar o plug-in do Jaeger ou do Zipkin.

Instalando o plug-in do Jaeger

  1. Instale o plug-in do Jaeger. O comando wget a seguir é destinado a sistemas Linux x86-64:
$ cd /usr/local/lib
$ wget https://github.com/jaegertracing/jaeger-client-cpp/releases/download/v0.4.2/libjaegertracing_plugin.linux_amd64.so -O /usr/local/lib/libjaegertracing_plugin.so
  1. As instruções para compilar o plug-in a partir do código-fonte estão disponíveis no GitHub.
  2. Crie um arquivo de configuração no formato JSON para o plug-in, chamado /etc/jaeger/jaeger-config.json, com o conteúdo a seguir. Estamos usando a porta padrão do servidor Jaeger, 6831:
{  "service_name": "nginx",
  "sampler": {
    "type": "const",
    "param": 1
  },
  "reporter": {
    "localAgentHostPort": "Jaeger-server-IP-address:6831"
  }
}
  1. Para obter detalhes sobre o objeto sampler, consulte a documentação do Jaeger.

Instalando o plug-in do Zipkin

  1. Instale o plug-in do Zipkin. O comando wget a seguir é destinado a sistemas Linux x86-64:
$ cd /usr/local/lib$ wget -O - https://github.com/rnburn/zipkin-cpp-opentracing/releases/download/v0.5.2/linux-amd64-libzipkin_opentracing_plugin.so.gz | gunzip -c > /usr/local/lib/libzipkin_opentracing_plugin.so
  1. Crie um arquivo de configuração no formato JSON para o plug-in, chamado /etc/zipkin/zipkin-config.json, com o conteúdo a seguir. Estamos usando a porta padrão do servidor Zipkin, 9411:
{  "service_name": "nginx",
  "collector_host": "Zipkin-server-IP-address",
  "collector_port": 9411
}
  1. Para obter detalhes sobre os objetos de configuração, consulte o esquema JSON no GitHub.

Configurando o NGINX Plus

Execute estas instruções no host do NGINX Plus.

  1. Instale o módulo NGINX OpenTracing de acordo com as instruções no Guia de Administração do NGINX Plus.
  2. Adicione a seguinte diretiva load_module ao contexto principal (nível superior) do arquivo de configuração principal do NGINX Plus (/etc/nginx/nginx.conf):
load_module modules/ngx_http_opentracing_module.so;
  1. Adicione as seguintes diretivas à configuração do NGINX Plus. Se você usar o esquema de configuração convencional, coloque as diretivas em um novo arquivo chamado /etc/nginx/conf.d/opentracing.conf. Verifique também se a seguinte diretiva include aparece no contexto http em /etc/nginx/nginx.conf:
http {
    include /etc/nginx/conf.d/*.conf;
}
# Load a vendor tracer#opentracing_load_tracer /usr/local/libjaegertracing_plugin.so 
#                        /etc/jaeger/jaeger-config.json;
#opentracing_load_tracer /usr/local/lib/libzipkin_opentracing_plugin.so
#                        /etc/zipkin/zipkin-config.json;

# Enable tracing for all requests
opentracing on;

# Set additional tags that capture the value of NGINX Plus variables
opentracing_tag bytes_sent $bytes_sent;
opentracing_tag http_user_agent $http_user_agent;
opentracing_tag request_time $request_time;
opentracing_tag upstream_addr $upstream_addr;
opentracing_tag upstream_bytes_received $upstream_bytes_received;
opentracing_tag upstream_cache_status $upstream_cache_status;
opentracing_tag upstream_connect_time $upstream_connect_time;
opentracing_tag upstream_header_time $upstream_header_time;
opentracing_tag upstream_queue_time $upstream_queue_time;
opentracing_tag upstream_response_time $upstream_response_time;

#uncomment for debugging
# log_format opentracing '$remote_addr - $remote_user [$time_local] "$request" '
#                        '$status $body_bytes_sent "$http_referer" '
#                        '"$http_user_agent" "$http_x_forwarded_for" '
#                        '"$host" sn="$server_name" '
#                        'rt=$request_time '
#                        'ua="$upstream_addr" us="$upstream_status" '
#                        'ut="$upstream_response_time" ul="$upstream_response_length" '
#                        'cs=$upstream_cache_status';
#access_log /var/log/nginx/opentracing.log opentracing;
 
server {
    listen 9001;

    location / {
        # The operation name used for OpenTracing Spans defaults to the name of the
        # 'location' block, but uncomment this directive to customize it.
        #opentracing_operation_name $uri;

        # Propagate the active Span context upstream, so that the trace can be 
        # continued by the backend.
        opentracing_propagate_context;

        # Make sure that your Ruby app is listening on port 4567
        proxy_pass http://127.0.0.1:4567;
    }
}
  • A diretiva opentracing_load_tracer habilita o plug-in de rastreamento. Remova o comentário da diretiva do Jaeger ou do Zipkin, conforme apropriado.
  • As diretivas opentracing_tag disponibilizam as variáveis do NGINX Plus como tags do OpenTracing que aparecem na interface do rastreador.
  • Para depurar a atividade do OpenTracing, remova o comentário das diretivas log_format e access_log. Se quiser substituir o log de acesso e o formato de log padrão do NGINX por estes, remova o comentário das diretivas e altere as três ocorrências de “opentracing” para “main”. Outra opção é registrar a atividade do OpenTracing apenas para o tráfego na porta 9001. Para isso, remova o comentário das diretivas log_format e access_log e mova-as para o bloco server.
  • O bloco server configura o OpenTracing para o aplicativo Ruby de exemplo descrito na próxima seção.
  1. Valide e recarregue a configuração do NGINX Plus:
$ nginx -t$ nginx -s reload

Configurando o aplicativo Ruby de exemplo

Com a configuração do rastreador e do NGINX Plus pronta, criamos um aplicativo Ruby de exemplo que mostra como são os dados do OpenTracing. O aplicativo nos permite medir o quanto o cache do NGINX Plus melhora o tempo de resposta. Quando o aplicativo recebe uma solicitação como a seguinte solicitação HTTP GET para /, ele aguarda um período aleatório (entre 2 e 5 segundos) antes de responder.

$ curl http://NGINX-Plus-IP-address:9001/
  1. Instale e configure o Ruby e o Sinatra (uma biblioteca de código aberto para aplicações web e uma linguagem específica de domínio escrita em Ruby, que serve como alternativa a outros frameworks de aplicações web em Ruby).
  2. Crie um arquivo chamado app.rb com o seguinte conteúdo:
#!/usr/bin/ruby

require 'sinatra'

get '/*' do
    out = "<h1>Ruby simple app</h1>" + "\n"

    #Sleep a random time between 2s and 5s
    sleeping_time = rand(4)+2
    sleep(sleeping_time)
    puts "slept for: #{sleeping_time}s."
    out += '<p>some output text</p>' + "\n"

    return out
end
  1. Torne o arquivo app.rb executável e execute-o:
$ chmod +x app.rb$ ./app.rb

Rastreando tempos de resposta sem cache

Usamos o Jaeger e o Zipkin para mostrar quanto tempo o NGINX Plus leva para responder a uma solicitação quando o cache não está habilitado. Para cada ferramenta de rastreamento, enviamos cinco solicitações.

Saída do Jaeger sem cache

Estas são as cinco solicitações exibidas na interface do Jaeger (da mais recente para a mais antiga):

Estas são as mesmas informações no console do aplicativo Ruby:

- -> /slept for: 3s. 
127.0.0.1 - - [07/Jun/2019: 10:50:46 +0000] "GET / HTTP/1.1" 200 49 3.0028
127.0.0.1 - - [07/Jun/2019: 10:50:43 UTC] "GET / HTTP/1.0" 200 49
- -> /
slept for: 2s. 
127.0.0.1 - - [07/Jun/2019: 10:50:56 +0000] "GET / HTTP/1.1" 200 49 2.0018 
127.0.0.1 - - [07/Jun/2019: 10:50:54 UTC] "GET / HTTP/1.0"1 200 49
- -> /
slept for: 3s. 
127.0.0.1 - - [07/Jun/2019: 10:53:16 +0000] "GET / HTTP/1.1" 200 49 3.0029 
127.0.0.1 - - [07/Jun/2019: 10:53:13 UTC] "GET / HTTP/1.0" 200 49
- -> /
slept for: 4s.
127.0.0.1 - - [07/Jun/2019: 10:54:03 +0000] "GET / HTTP/1.1" 200 49 4.0030 
127.0.0.1 - - [07/Jun/2019: 10:53:59 UTC] "GET / HTTP/1.0" 200 49
- -> /
slept for: 3s.
127.0.0.1 - - [07/Jun/2019: 10:54:11 +0000] "GET / HTTP/1.1" 200 49 3.0012
127.0.0.1 - - [07/Jun/2019: 10:54:08 UTC] "GET / HTTP/1.0" 200 49

Na interface do Jaeger, clicamos na primeira solicitação (a mais recente) para ver seus detalhes, incluindo os valores das variáveis do NGINX Plus que adicionamos como tags:

Saída do Zipkin sem cache

Aqui estão outras cinco requisições na interface do Zipkin:

As mesmas informações no console do aplicativo Ruby:

- -> /slept for: 2s.
127.0.0.1 - - [07/Jun/2019: 10:31:18 +0000] "GET / HTTP/1.1" 200 49 2.0021 
127.0.0.1 - - [07/Jun/2019: 10:31:16 UTC] "GET / HTTP/1.0" 200 49
- -> /
slept for: 3s.
127.0.0.1 - - [07/Jun/2019: 10:31:50 +0000] "GET / HTTP/1.1" 200 49 3.0029 
127.0.0.1 - - [07/Jun/2019: 10:31:47 UTC] "GET / HTTP/1.0" 200 49
- -> /
slept for: 3s.
127.0.0.1 - - [07/Jun/2019: 10:32:08 +0000] "GET / HTTP/1.1" 200 49 3.0026 
127.0.0.1 - - [07/Jun/2019: 10:32:05 UTC] "GET / HTTP/1.0" 200 49
- -> /
slept for: 3s.
127.0.0.1 - - [07/Jun/2019: 10:32:32 +0000] "GET / HTTP/1.1" 200 49 3.0015 
127.0.0.1 - - [07/Jun/2019: 10:32:29 UTC] "GET / HTTP/1.0" 200 49
- -> /
slept for: 5s.
127.0.0.1 - - [07/Jun/2019: 10:32:52 +0000] "GET / HTTP/1.1" 200 49 5.0030 
127.0.0.1 - - [07/Jun/2019: 10:32:47 UTC] "GET / HTTP/1.0" 200 49

Na interface do Zipkin, clicamos na primeira solicitação para ver seus detalhes, incluindo os valores das variáveis do NGINX Plus que adicionamos como tags:

Rastreando tempos de resposta com cache

Configurando o cache do NGINX Plus

Habilitamos o cache adicionando diretivas ao arquivo opentracing.conf que criamos em Configuração do NGINX Plus.

  1. No contexto http, adicione esta diretiva proxy_cache_path:
proxy_cache_path /data/nginx/cache keys_zone=one:10m;
  1. No bloco server, adicione as seguintes diretivas proxy_cache e proxy_cache_valid:
proxy_cache one;
proxy_cache_valid any 1m;
  1. Valide e recarregue a configuração:
$ nginx -t$ nginx -s reload

Saída do Jaeger com cache

Esta é a interface do Jaeger após duas requisições.

A primeira resposta (identificada como 13f69db) levou 4 segundos. O NGINX Plus armazenou a resposta em cache e, quando a solicitação foi repetida cerca de 15 segundos depois, a resposta levou menos de 2 milissegundos (ms), pois veio do cache do NGINX Plus.

Uma análise detalhada das duas solicitações explica a diferença no tempo de resposta. Na primeira solicitação, upstream_cache_status é MISS, o que significa que os dados solicitados não estavam no cache. O aplicativo Ruby adicionou um atraso de 4 segundos.

Na segunda solicitação, upstream_cache_status é HIT. Como os dados vêm do cache, o aplicativo Ruby não pode adicionar um atraso, e o tempo de resposta é inferior a 2 ms. Os valores vazios de upstream_* também indicam que o servidor upstream não participou dessa resposta.

Saída do Zipkin com cache

A exibição na interface do Zipkin para duas solicitações com o cache habilitado mostra um cenário semelhante:

E, mais uma vez, analisar as duas solicitações em detalhes explica a diferença no tempo de resposta. A resposta não está armazenada em cache para a primeira solicitação (upstream_cache_status é MISS) e o aplicativo Ruby (por coincidência) adiciona o mesmo atraso de 4 segundos do exemplo do Jaeger.

A resposta foi armazenada em cache antes de fazermos a segunda solicitação, portanto, upstream_cache_status é HIT.

Conclusão

O módulo OpenTracing do NGINX permite rastrear solicitações e respostas do NGINX Plus e fornece acesso às variáveis do NGINX Plus usando tags do OpenTracing. Diferentes rastreadores também podem ser usados com esse módulo.

Para mais detalhes sobre o módulo NGINX OpenTracing, acesse o repositório do módulo NGINX OpenTracing no GitHub.

Para experimentar o OpenTracing com o NGINX Plus, comece hoje mesmo sua avaliação gratuita de 30 dias ou entre em contato conosco para discutir seus casos de uso.


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.