Encontrando afunilamento Nginx / PHP-FPM que está causando erros aleatórios no gateway 502

3

Eu trabalho para um site bastante ocupado, que geralmente recebe picos muito grandes de tráfego. Durante esses picos, centenas de páginas por segundo são solicitadas e isso produz erros aleatórios no gateway 502.

Agora executamos o Nginx (1.0.10) e o PHP-FPM em uma máquina com 4 unidades SAS 15k (raid10) com uma CPU de 16 núcleos e 24 GB de memória RAM DDR3. Também fazemos uso da versão mais recente do Xcache. O DB está localizado em outra máquina, mas a carga dessa máquina é muito baixa e não tem problemas.

Sob carga normal, tudo funciona perfeitamente, a carga do sistema está abaixo de 1 e o relatório de status do PHP-FPM nunca mostra mais do que 10 processos ativos ao mesmo tempo. Há sempre cerca de 10 GB de RAM ainda disponíveis. Sob carga normal, a máquina processa cerca de 100 visualizações de páginas por segundo.

O problema surge quando grandes picos de tráfego chegam e centenas de visualizações de páginas por segundo são solicitadas da máquina. Percebo que o relatório de status do FPM mostra até 50 processos ativos, mas ainda está muito abaixo das 300 conexões máximas que configuramos. Durante esses picos, o status do Nginx informa até 5000 conexões ativas, em vez da média normal de 1.000.

Informações do sistema operacional: versão CentOS 5.7 (final)

CPU: CPU Intel (R) Xeon (R) E5620 @ 2.40GH (16 núcleos)

php-fpm.conf

daemonize = yes
listen = /tmp/fpm.sock
pm = static
pm.max_children = 300
pm.max_requests = 1000

Eu não configurei o rlimit_files, porque, até onde eu sei, ele deve usar o padrão do sistema se você não o fizer.

fastcgi_params (somente valores adicionados ao arquivo padrão)

fastcgi_connect_timeout 60;
fastcgi_send_timeout 180;
fastcgi_read_timeout 180;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
fastcgi_intercept_errors on;

fastcgi_pass            unix:/tmp/fpm.sock;

nginx.conf

worker_processes        8;
worker_connections      16384;
sendfile                on;
tcp_nopush              on;
keepalive_timeout       4;

O Nginx se conecta ao FPM por meio do Unix Socket.

sysctl.conf

net.ipv4.ip_forward = 0
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.default.accept_source_route = 0
kernel.sysrq = 1
kernel.core_uses_pid = 1
net.ipv4.tcp_syncookies = 1
kernel.msgmnb = 65536
kernel.msgmax = 65536
kernel.shmmax = 68719476736
kernel.shmall = 4294967296
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.tcp_timestamps = 0
net.ipv4.conf.all.rp_filter=1
net.ipv4.conf.default.rp_filter=1
net.ipv4.conf.eth0.rp_filter=1
net.ipv4.conf.lo.rp_filter=1
net.ipv4.ip_conntrack_max = 100000

limits.conf

* soft nofile 65536
* hard nofile 65536

Estes são os resultados dos seguintes comandos:

ulimit -n
65536

ulimit -Sn
65536

ulimit -Hn
65536

cat /proc/sys/fs/file-max
2390143

Pergunta: Se o PHP-FPM não está ficando sem conexões, a carga ainda é baixa, e há muita RAM disponível, o gargalo pode estar causando esses erros aleatórios do gateway 502 durante o tráfego intenso ?

Observação: por padrão, o ulimit dessa máquina era 1024, já que eu mudei para 65536 Eu não reiniciei totalmente a máquina, já que é uma máquina de produção e isso significaria muito tempo de inatividade.

    
por Mr.Boon 07.01.2012 / 18:08

2 respostas

1

Recomendação oficial: worker_processes = número de núcleos de CPU

defina worker_processes 16;

    
por 07.01.2012 / 18:20
2

Erros esporádicos do 502 de balanceadores de carga, como HAProxy e nginx, geralmente são causados por algo que é cortado no meio do fluxo entre o LB e o servidor da Web.

Tente executar um dos seus servidores da Web, ou uma cópia de teste dele, através do GDB e veja se você vê uma falha de segmentação ao gerar tráfego de teste (use ab ou jMeter ou similar para simular o tráfego).

Eu tive que resolver um cenário / problema muito similar recentemente. Eu excluí recursos etc causando o problema como eu tinha um monitoramento bastante abrangente que estava me ajudando lá. No final, descobri que o erro 502 estava vindo do servidor web por trás do balanceador de carga, retornando respostas HTTP inválidas (neste caso vazias) para o LB.

Eu peguei um dos servidores da web e parei o servidor da web, depois o iniciei novamente pelo gdb e naveguei pelo sited. Eventualmente, depois de alguns cliques, vi uma falha de segmentação acontecer e isso causou um erro 502 visível. Eu peguei o backtrace do GDB e enviei-o para a equipe do PHP como um bug, mas a única correção para mim foi mudar a distribuição para contornar o bug do PHP que estava lá.

O segfault estava fazendo com que o servidor web enviasse conteúdo inválido para o LB, e o LB estava exibindo um erro 502 porque, no que diz respeito ao servidor web, ele desapareceu "mid flow".

Eu sei que isso não responde diretamente à sua pergunta, mas é um lugar para começar a procurar. Supondo que você veja um segfault, você pode obter o rastreamento de pilha do GDB, então você pode trabalhar para trás e descobrir qual função está causando a falha de segmentação.

    
por 07.01.2012 / 18:19