Maximizando o desempenho do Python com o NGINX, Parte 1: disponibilização de conteúdo web e cache

NGINX | 31 de março de 2016

Introdução – Como o NGINX é usado com Python

O Python é famoso por ser fácil e divertido de usar, por facilitar o desenvolvimento de software e por apresentar um desempenho em tempo de execução que, segundo dizem, supera o de outras linguagens de script. (Embora a versão mais recente do PHP, o PHP 7, possa competir de igual para igual com o Python.)

Todos querem que seu site e aplicativo sejam mais rápidos. Além disso, todo site com tráfego crescente ou picos acentuados de tráfego está sujeito a problemas de desempenho e indisponibilidade, que muitas vezes ocorrem nos piores momentos — ou seja, nos horários de maior movimento. Da mesma forma, quase todos os sites enfrentam problemas de desempenho e indisponibilidade, seja quando o volume de tráfego cresce de forma constante, seja quando há picos acentuados de uso.

É aí que entram o NGINX e o NGINX Plus. Eles melhoram o desempenho dos sites de três maneiras diferentes:

  1. Como servidor web – O NGINX foi originalmente desenvolvido para resolver o problema C10K – ou seja, para comportar facilmente 10.000 conexões simultâneas ou mais. Usar o NGINX como servidor web para seu aplicativo Python torna seu site mais rápido, mesmo com baixos níveis de tráfego. Quando há muitos milhares de usuários, é praticamente certo que ele proporcionará um desempenho muito superior, menos falhas e menos tempo de inatividade. Você também pode armazenar arquivos estáticos em cache ou usar microcache no servidor web NGINX, embora ambos funcionem melhor quando executados em um servidor proxy reverso NGINX separado (consulte o próximo parágrafo).
  2. Como servidor proxy reverso – Você pode simplesmente inserir o NGINX como um servidor proxy reverso à frente da configuração atual do seu servidor de aplicações. O NGINX recebe as solicitações da Web e as encaminha ao servidor de aplicações. Esse “truque simples” torna seu site mais rápido, reduz o tempo de inatividade, consome menos recursos do servidor e melhora a segurança. Você também pode armazenar arquivos estáticos em cache no servidor proxy reverso (o que é muito eficiente), adicionar microcache de conteúdo dinâmico para reduzir a carga sobre a própria aplicação e muito mais.
  3. Como balanceador de carga para vários servidores de aplicativos – Comece implantando um servidor proxy reverso. Em seguida, escale horizontalmente executando vários servidores de aplicativos em paralelo e usando o NGINX ou o NGINX Plus para balancear a carga do tráfego entre eles. Com esse tipo de implantação, você pode dimensionar facilmente o desempenho do seu site de acordo com os requisitos de tráfego, aumentando a confiabilidade e o tempo de atividade. Se precisar que uma determinada sessão de usuário permaneça no mesmo servidor, configure o balanceador de carga para oferecer suporte à persistência de sessão.

O NGINX e o NGINX Plus oferecem vantagens, seja quando usados como servidor web para seu aplicativo Python, como servidor proxy reverso, como balanceador de carga ou para as três finalidades.

Neste primeiro artigo de uma série de duas partes, apresentamos cinco dicas para melhorar o desempenho dos seus aplicativos Python, incluindo o uso do NGINX e do NGINX Plus como servidor web, a implementação do cache de arquivos estáticos e do microcache de arquivos gerados pelo aplicativo. Na Parte 2, descreveremos como usar o NGINX e o NGINX Plus como servidor proxy reverso e balanceador de carga para vários servidores de aplicativos.

Dica 1 – Identifique os gargalos de desempenho do Python

Há duas situações muito distintas em que o desempenho da sua aplicação Python é importante: primeiro, com uma quantidade cotidiana e “razoável” de usuários; segundo, sob cargas intensas. Muitos proprietários de sites se preocupam muito pouco com o desempenho sob cargas leves, quando — em nossa humilde opinião — deveriam se preocupar com cada décimo de segundo no tempo de resposta. Reduzir milissegundos dos tempos de resposta é um trabalho difícil e pouco reconhecido, mas deixa os usuários mais satisfeitos e melhora os resultados do negócio.

No entanto, este post do blog e a Parte 2 que o acompanha se concentram no cenário que realmente preocupa a todos: problemas de desempenho que ocorrem quando um site recebe muito tráfego, como grandes quedas de desempenho e falhas. Além disso, muitos ataques de hackers imitam os efeitos de aumentos repentinos no número de usuários, e melhorar o desempenho do site costuma ser uma etapa importante para combater ataques também.

Em um sistema que aloca uma determinada quantidade de memória por usuário, como o Apache HTTP Server, a adição de usuários sobrecarrega a memória física à medida que mais e mais usuários acessam o sistema. O servidor começa a usar o disco como memória de troca, o desempenho despenca e, como consequência, ocorrem problemas de desempenho e falhas. Migrar para o NGINX, conforme descrito nesta publicação do blog, ajuda a resolver esse problema.

O Python é particularmente suscetível a problemas de desempenho relacionados à memória, pois geralmente usa mais memória para realizar suas tarefas do que outras linguagens de script (e, como resultado, as executa mais rapidamente). Portanto, em condições equivalentes, seu aplicativo baseado em Python pode “parar de funcionar” com uma carga de usuários menor do que um aplicativo escrito em outra linguagem.

Otimizar seu aplicativo pode ajudar até certo ponto, mas geralmente essa não é a melhor nem a maneira mais rápida de resolver problemas de desempenho do site relacionados ao tráfego. As etapas apresentadas nesta publicação do blog e na Parte 2 que a acompanha são as melhores e mais rápidas maneiras de lidar com problemas de desempenho relacionados ao tráfego. Depois de seguir as etapas descritas aqui, fique à vontade para voltar e aprimorar seu aplicativo ou reescrevê-lo para usar uma arquitetura de microsserviços.

Dica 2 – Escolha uma implantação em servidor único ou em vários servidores

Sites pequenos funcionam bem quando implantados em um único servidor. Sites grandes exigem vários servidores. Mas, se você estiver em uma situação intermediária — ou se o seu site estiver crescendo e deixando de ser pequeno para se tornar grande —, terá algumas decisões interessantes a tomar.

Se você tiver uma implantação em um único servidor, estará sujeito a riscos significativos caso ocorram picos de tráfego ou um rápido crescimento do tráfego geral. Sua escalabilidade é limitada, e as possíveis soluções incluem aprimorar seu aplicativo, migrar seu servidor web para o NGINX, adquirir um servidor maior e mais rápido ou transferir o armazenamento para uma rede de distribuição de conteúdo (CDN). Cada uma dessas opções leva tempo para ser implementada, envolve custos e pode introduzir bugs ou problemas durante a implementação.

Além disso, com uma implantação em um único servidor, seu site tem, por definição, um único ponto de falha — e muitos dos problemas que podem tirá-lo do ar não têm soluções rápidas ou simples.

NGINX e Python trabalham juntos para oferecer alto desempenho por meio dos recursos do NGINX para servir conteúdo web, balancear carga e armazenar dados em cache
“Colocando o NGINX na frente dos” servidores de aplicações

Se você mudar seu servidor para o NGINX em uma implantação com um único servidor, poderá escolher livremente entre o NGINX Open Source e o NGINX Plus. O NGINX Plus inclui suporte de nível empresarial e recursos adicionais. Alguns dos recursos adicionais, como o monitoramento de atividades em tempo real, são relevantes para uma implantação com um único servidor, enquanto outros, como o balanceamento de carga e a persistência de sessão, entram em ação quando você usa o NGINX Plus como servidor proxy reverso em uma implantação com vários servidores.

Considerando todos os fatores, a menos que você tenha certeza de que seu site permanecerá pequeno por muito tempo e que a indisponibilidade não seja uma grande preocupação, a implantação em um único servidor apresenta alguns riscos. A implantação em vários servidores oferece escalabilidade praticamente ilimitada: é possível eliminar pontos únicos de falha e alcançar o nível de desempenho desejado, com a capacidade de adicionar recursos rapidamente.

Dica 3 – Mude seu servidor web para o NGINX

Nos primórdios da Web, o nome “Apache” era sinônimo de “servidor web”. Mas o NGINX foi desenvolvido no início dos anos 2000 e vem ganhando popularidade de forma constante; ele já é o servidor web nº 1 entre os 1.000, 10.000, 100.000 e [ngx_snippet name=’proportion-top-sites’] maiores sites do mundo.

O NGINX foi desenvolvido para solucionar o problema C10K – ou seja, para lidar com mais de 10.000 conexões simultâneas dentro de um determinado limite de memória. Outros servidores web precisam de um bloco de memória para cada conexão, por isso ficam sem memória física e apresentam lentidão ou falham quando milhares de usuários tentam acessar um site ao mesmo tempo. O NGINX processa cada solicitação separadamente e pode ser dimensionado de forma eficiente para atender a um número muito maior de usuários. (Ele também é excelente para outras finalidades, como descreveremos abaixo.)

Uma visão geral de alto nível da arquitetura do NGINX é apresentada abaixo.

Arquitetura para orientações de configuração do Python usando os recursos do NGINX para servir conteúdo web, balancear carga e armazenar dados em cache
Arquitetura do NGINX, extraída de A Arquitetura de Aplicações de Código Aberto, Volume II

No diagrama, um servidor de aplicações Python se encaixa no bloco Servidor de aplicações no backend e é mostrado sendo acessado via FastCGI. O NGINX não “sabe” como executar Python, por isso precisa de um gateway para um ambiente que saiba. FastCGI é uma interface amplamente utilizada para PHP, Python e outras linguagens.

No entanto, uma opção mais popular para a comunicação entre Python e NGINX é a Web Server Gateway Interface (WSGI). A WSGI funciona em ambientes multithread e multiprocesso, portanto, oferece boa escalabilidade em todas as opções de implantação mencionadas nesta publicação do blog.

Se você migrar para o NGINX como seu servidor web, há muito material disponível para ajudar em cada etapa do processo:

Este trecho mostra como você pode configurar o NGINX para uso com o uWSGI – neste caso, em um projeto que usa o framework Python Django:

http {    # ...
    upstream django {
       server 127.0.0.1:29000;
    }

    server {
        listen 80;
        server_name myapp.example.com;

        root /var/www/myapp/html;

        location / {
            index index.html;
        }

        location /static/  {
            alias /var/django/projects/myapp/static/;
        }

        location /main {
            include /etc/nginx/uwsgi_params;
            uwsgi_pass django;

            uwsgi_param Host $host;
            uwsgi_param X-Real-IP $remote_addr;
            uwsgi_param X-Forwarded-For $proxy_add_x_forwarded_for;
            uwsgi_param X-Forwarded-Proto $http_x_forwarded_proto;
        }
    }
}

Dica 4 – Implemente o cache de arquivos estáticos

O cache de conteúdo estático consiste em manter uma cópia de arquivos que não mudam com tanta frequência — o que pode significar a cada poucas horas ou nunca — em um local diferente do servidor de aplicações. Um exemplo típico de conteúdo estático é uma imagem JPEG exibida como parte de uma página da web.

O cache de arquivos estáticos é uma forma comum de melhorar o desempenho de aplicações e, na prática, ocorre em vários níveis:

  • No navegador do usuário
  • Nos provedores de Internet em vários níveis – desde a rede interna de uma empresa até um provedor de serviços de Internet (ISP)
  • Em um servidor web, como descreveremos aqui

Implementar o cache de arquivos estáticos no servidor web oferece dois benefícios:

  • Entrega mais rápida ao usuário – O NGINX é otimizado para o armazenamento em cache de arquivos estáticos e processa solicitações de conteúdo estático muito mais rapidamente do que um servidor de aplicações.
  • Redução da carga no servidor de aplicações – O servidor de aplicações nem sequer recebe as solicitações de arquivos estáticos armazenados em cache, pois elas são atendidas pelo servidor web.

O cache de arquivos estáticos funciona bem em uma implementação com um único servidor, mas o hardware subjacente ainda é compartilhado pelo servidor web e pelo servidor de aplicações. Se o servidor web estiver usando o hardware para recuperar um arquivo armazenado em cache – mesmo que de forma muito eficiente – esses recursos de hardware não estarão disponíveis para a aplicação, o que pode deixá-la um pouco mais lenta.

Para oferecer suporte ao cache do navegador, configure corretamente os cabeçalhos HTTP para arquivos estáticos. Considere o cabeçalho HTTP Cache-Control (e, em particular, sua configuração max-age), o cabeçalho Expires e as tags Entity. Para uma boa introdução ao assunto, consulte Como usar o NGINX e o NGINX Plus como gateway de aplicações com uWSGI e Django no Guia de Administração do NGINX Plus.

O código a seguir configura o NGINX para armazenar arquivos estáticos em cache, incluindo arquivos JPEG, GIF, PNG, vídeos MP4, arquivos do PowerPoint e muitos outros. Substitua www.example.com pela URL do seu servidor web.

server {    # substitute your web server's URL for "www.example.com"
    server_name www.example.com;
    root /var/www/example.com/htdocs;
    index index.php;
    access_log /var/log/nginx/example.com.access.log;
    error_log /var/log/nginx/example.com.error.log;

   location / {
        try_files $uri $uri/ /index.php?$args;
    }

   location ~ .php$ {
        try_files $uri =404;
        include fastcgi_params;
        # substitute the socket, or address and port, of your Python server
        fastcgi_pass unix:/var/run/php5-fpm.sock;
        #fastcgi_pass 127.0.0.1:9000;
 	}  

   location ~* .(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|css|rss|atom|js|jpg
                  |jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid
                  |midi|wav|bmp|rtf)$ {
        expires max;
        log_not_found off;
        access_log off;
    }
}

Dica 5 – Implemente o microcache

O microcache aproveita uma grande oportunidade para melhorar o desempenho de servidores de aplicações que executam Python, PHP e outras linguagens. Para fins de cache, existem três tipos de páginas da web:

  • Arquivos estáticos – Eles podem ser armazenados em cache, conforme descrito na Dica 4.
  • Páginas não personalizadas geradas pelo aplicativo – Geralmente, não faz sentido armazená-las em cache, pois elas precisam estar atualizadas. Um exemplo é uma página exibida para um usuário de comércio eletrônico que não está conectado (consulte o próximo ponto) – os produtos disponíveis, as recomendações de produtos semelhantes e assim por diante podem mudar constantemente, por isso é importante fornecer uma página atualizada. No entanto, se outro usuário acessar, digamos, um décimo de segundo depois, pode ser perfeitamente aceitável mostrar a ele a mesma página exibida ao usuário anterior.
  • Páginas personalizadas geradas pelo aplicativo – Não é útil armazená-las em cache, pois são específicas de cada usuário, e é improvável que o mesmo usuário veja a mesma página personalizada duas vezes. Um exemplo é uma página de comércio eletrônico para um usuário conectado; essa mesma página não pode ser exibida a outros usuários.

Arquivos estáticos e arquivos não personalizados gerados por aplicativos podem ser armazenados em cache

O microcache é útil para o segundo tipo de página descrito acima: páginas geradas pelo aplicativo e não personalizadas. “Micro” refere-se a um curto período. Quando seu site gera a mesma página várias vezes por segundo, armazená-la em cache por um segundo pode não comprometer muito a atualização do conteúdo. Ainda assim, esse breve período de armazenamento em cache pode reduzir enormemente a carga do servidor de aplicativos, especialmente durante picos de tráfego. Em vez de gerar 10, 20 ou 100 páginas (com o mesmo conteúdo) durante o período de expiração do cache, ele gera uma determinada página apenas uma vez; em seguida, a página é armazenada em cache e disponibilizada a muitos usuários a partir dele.

O efeito é quase milagroso. Um servidor que fica lento ao processar dezenas de solicitações por segundo torna-se bastante rápido ao processar apenas uma. (Além, é claro, de quaisquer páginas personalizadas.) Owen Garrett, da nossa equipe, publicou um post no blog que explica em detalhes os benefícios do microcache, incluindo o código de configuração. A principal alteração — configurar um cache de proxy com um tempo limite de um segundo — requer apenas algumas linhas de código de configuração.

proxy_cache_path /tmp/cache keys_zone=cache:10m levels=1:2 inactive=600s max_size=100m;server {
    proxy_cache cache;
    proxy_cache_valid 200 1s;
    # ...
}

Para ver mais exemplos de configuração, consulte o blog de Tyler Hicks‑Wright sobre Python e uWSGI com NGINX.

Conclusão

Na Parte I, abordamos soluções para aumentar o desempenho de uma implementação Python em um único servidor, bem como o uso de cache, que pode ser implantado nessa mesma implementação ou executado em um servidor proxy reverso ou em um servidor de cache separado. (O cache funciona melhor em um servidor separado.) A próxima parte, Parte 2, descreve soluções de desempenho que exigem dois ou mais servidores.

Se você quiser explorar os recursos avançados do NGINX Plus para sua aplicação, como suporte, monitoramento de atividades em tempo real e reconfiguração dinâmica, inicie hoje mesmo sua avaliação gratuita de 30 dias ou entre em contato conosco para discutir seus casos de uso.


Compartilhar

Sobre o autor

Floyd Smith
Floyd SmithDiretor de Marketing de Conteúdo

Mais publicações de Floyd Smith

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.