...

Enfileiramento de pedidos PHP e limites de processamento: configuração óptima para servidores estáveis

O enfileiramento de pedidos em PHP limita o número de pedidos que o seu servidor processa ao mesmo tempo e, por conseguinte, determina o tempo de resposta, as taxas de erro e a experiência do utilizador. Vou mostrar-lhe como Limites de processamento e eliminar os estrangulamentos e conseguir uma entrega consistente através de parâmetros harmonizados.

Pontos centrais

Para que possa começar de imediato, vou resumir os parafusos de regulação mais importantes para PHP-FPM juntos.

  • pm.max_childrenCálculo do limite máximo de processos PHP simultâneos para corresponder à RAM.
  • lista.backlogMaximizar a proteção a curto prazo das tentativas de ligação durante os picos de carga.
  • pm.max_requestsRecicle processos regularmente para evitar fugas de memória e inchaço.
  • Intervalos: definir o request_terminate_timeout, o max_execution_time e os tempos limite do servidor Web de forma consistente.
  • Métricasse o número máximo de crianças for atingido, verificar continuamente a fila de escuta e os registos lentos.

Concentro-me em números-chave claros e efeitos mensuráveis, para que todos os ajustamentos ao Limites permanece rastreável. Para cada alteração, monitorizo os registos e os tempos de resposta antes de planear o passo seguinte e aumentar ou diminuir gradualmente os valores. Desta forma, evito efeitos secundários como a troca de memória, que pode Fila de espera dramaticamente mais longos. Com esta abordagem, controlo os picos de carga e mantenho os tempos de resposta estáveis. O objetivo é conseguir uma utilização equilibrada da capacidade que Recursos de forma eficiente sem sobrecarregar o anfitrião.

Como funciona o enfileiramento de pedidos PHP no PHP-FPM

Cada pedido HTTP de entrada requer o seu próprio Trabalhador, e um trabalhador apenas serve um pedido de cada vez. Se todos os processos estiverem ocupados, outras chamadas acabam no Fila de espera e esperar até que um processo fique livre. Se essa fila crescer, os tempos de resposta aumentam e erros como 502/504 ocorrem com mais frequência. Por isso, presto atenção a um rácio sensato entre o número de processos e a memória disponível, em vez de me concentrar cegamente no paralelismo máximo. Desta forma, obtenho uma taxa de transferência constante sem RAM ou a CPU separa-se.

Selecionar modos de gestão de processos de forma limpa

Para além dos valores-limite, o modo pm capacidade de resposta e consumo de recursos:

  • pm = dinâmicoEu defino start_servers, min_spare_servers e max_spare_servers. Este modo é o meu padrão para cargas variáveis porque reage rapidamente a aumentos e mantém os processos quentes prontos.
  • pm = a pedidoOs processos são criados apenas quando necessário e são terminados após process_idle_timeout. Isto poupa RAM para acessos pouco frequentes (admin, staging, cron endpoints), mas pode levar a uma perda de RAM no caso de picos repentinos. Arranques a frio e maior latência. Por isso, utilizo-o de forma selectiva e com uma lista de pendências generosa.
  • pm = estáticoUm número fixo de processos. Ideal se eu tiver um limite superior rígido e latências particularmente previsíveis (por exemplo, proxy L7 em frente de alguns pontos finais críticos). O requisito de RAM é claramente calculável, mas os processos não utilizados ocupam memória.

Eu decido qual o modo mais adequado ao perfil de cada pool. Normalmente, utilizo o dinâmico para frontends com cargas variáveis, o ondemand para pools de utilitários e o estático para serviços dedicados e críticos em termos de latência.

Determinar pm.max_children corretamente

A alavanca mais importante é pm.max_children, porque este valor define o número de pedidos que podem ser executados em simultâneo. Calculo o tamanho inicial usando a regra geral: (RAM livremente disponível - reserva de 2 GB) dividido pela memória média por processo PHP. Como uma suposição aproximada, uso 40-80 MB por processo e inicialmente começo com 200-300 processos em um host de 32 GB. Sob carga real, aumento ou diminuo gradualmente e verifico se o tempo de espera do processo Fila de espera diminui e a taxa de erro diminui. Se quiser aprofundar o assunto, pode encontrar informações de base sobre os valores de início e limite em Otimizar pm.max_children.

Coordenar valores iniciais, sobressalentes e em atraso

Eu fixo pm.iniciar_servidores para cerca de 15-30 por cento de pm.max_children, de modo a que estejam disponíveis processos suficientes no início e não haja arranques a frio. Com pm.min_spare_servers e pm.max_spare_servers, defino uma janela razoável para os processos livres, de modo a que os novos pedidos não fiquem à espera e, ao mesmo tempo, nenhum tempo ocioso desnecessário ocupe a memória. Listen.backlog é particularmente importante: Este buffer do kernel guarda brevemente tentativas de conexão adicionais quando todos os workers estão ocupados. Para picos de carga, eu defino valores altos (por exemplo, 65535) para que o fila de espera não pára antes do pool FPM. Informações mais aprofundadas sobre a interação entre o servidor Web, o upstream e os buffers podem ser encontradas na síntese de Enfileiramento de servidores Web.

Limitar os tempos de execução dos pedidos e reciclar os processos

Evito os surtos de memória com pm.max_requests, que reinicia todos os processos após X pedidos. Aplicações discretas geralmente funcionam bem com 500-800, se houver suspeita de vazamento de memória eu reduzo para 100-200 e observo o efeito. Além disso, request_terminate_timeout encapsula os outliers, terminando pedidos extremamente longos após um tempo fixo. A consistência é importante: eu mantenho o max_execution_time do PHP e os timeouts do servidor web no mesmo corredor para que uma camada não termine antes da outra. Esta interação mantém o Trabalhador livre e protege a piscina do congestionamento.

Tornar as filas visíveis: Registos e métricas

Leio regularmente os registos do FPM e presto atenção a máximo de crianças alcançadas, porque esta entrada indica que o limite superior dos processos foi atingido. Ao mesmo tempo, monitorizo a fila de escuta, que revela um atraso crescente no buffer de entrada. Em combinação com request_slowlog_timeout, obtenho traços de pilha para pontos lentos no código e isolo os travões da base de dados ou da API. Correlaciono o upstream_response_time dos registos do servidor Web com o request_time e os códigos de estado para identificar a origem dos longos tempos de resposta. Isto permite-me reconhecer se o estrangulamento no PHP-FPM, o Base de dados ou a rede a montante.

Perfis de carga de trabalho: Limitado à CPU vs. Limitado à IO

Para processos com muita CPU, eu dimensiono o Paralelismo Eu sou cauteloso e oriento-me de perto para o número de vCPU, porque os processos adicionais dificilmente trazem qualquer rendimento. Se se tratar principalmente de uma carga de IO com acessos a bases de dados ou APIs externas, posso permitir mais processos, desde que o orçamento de RAM seja suficiente. Os checkouts de comércio eletrónico beneficiam de timeouts mais longos (por exemplo, 300 s) para completar os métodos de pagamento sem cancelamentos. Intercepto as vendas rápidas definindo o listen.backlog como elevado e aumentando a janela de reserva. As informações sobre o equilíbrio entre o número de processos e o desempenho do anfitrião estão incluídas no guia para PHP-Workers como um estrangulamento.

Cálculos e dimensionamento de amostras

Começo por calcular a memória por processo e depois obtenho uma Limite superior off. Em seguida, testo sob carga real e observo se a fila diminui e a taxa de transferência aumenta. Valores iniciais conservadores reduzem o risco de troca e mantêm o tempo de resposta uniforme. De seguida, refino em pequenos passos para ter a certeza de que não se notam quaisquer efeitos secundários. A tabela a seguir fornece orientações sobre os valores iniciais e os efeitos sobre o Fila de espera.

Parâmetros Efeito Valor inicial (exemplo) Nota
pm.max_children Máx. simultâneo Processos 200-300 (com 32 GB) Comparar com o orçamento de RAM e o tamanho do processo
pm.iniciar_servidores Número inicial de trabalhadores 15-30 % de max_children Evitar arranques a frio, mas manter a marcha lenta ao mínimo
pm.min_servidores_sobressalentes Grátis Trabalhador Mínimo z. B. 20 Inclusão direta de novos pedidos
pm.max_spare_servers Trabalhador livre Máximo z. B. 40 Limitar o consumo de RAM dos processos inactivos
lista.backlog Memória intermédia do kernel para tentativas de ligação 65535 Amortecer os picos de carga e reduzir as interrupções de ligação
pm.max_requests Reciclagem Intervalo 500-800, com fugas de 100-200 Minimizar o inchaço da memória e as interrupções
request_terminate_timeout Limite rígido de pedidos 300-600 s Consistente com os tempos limite do PHP e do servidor Web

Modelos práticos para pools PHP FPM

Para uma loja com muitos acessos de leitura, defino Números do processo e aumentar a janela de reserva para que as solicitações não fiquem em fila de espera. Para páginas de conteúdo com armazenamento em cache, um número significativamente menor de trabalhadores costuma ser suficiente, desde que o NGINX ou o Apache forneçam conteúdo estático com eficiência. Separo as configurações de vários pools de acordo com as partes da aplicação que têm perfis de memória diferentes, para que nenhum pool pesado substitua os outros. Defino pools separados com suas próprias regras de tempo limite para cron ou queue workers. É assim que mantenho o sistema interativo Tráfego gratuito e não atrasa nenhuma ação do utilizador.

Tempo limite do servidor Web, upstream e sockets

Considero os tempos limite do FastCGI e do proxy de Nginx ou Apache na mesma janela que os timeouts do FPM para que nenhuma camada termine muito cedo. Prefiro sockets Unix a TCP se ambos os serviços estiverem a correr na mesma máquina, porque a latência permanece mínima. Para configurações distribuídas, eu uso TCP com valores estáveis de keepalive e um pool de conexões suficientemente grande. Para alto paralelismo, o nginx sincroniza worker_connections e os valores de backlog do FPM. Isso garante que os redireccionamentos permaneçam rápidos e evito o tempo de inatividade devido a ligações demasiado apertadas. A montante-limites.

Caching, OPCache e base de dados como alavancas

Resolvo muitos problemas dos servidores reduzindo as operações dispendiosas e minimizando os custos de Tempo de resposta inferior. Ativo a OPCache, aumento o limite de memória da cache de forma sensata e asseguro uma elevada taxa de acerto da cache. Para obter resultados recorrentes, utilizo a cache da aplicação para que os processos PHP sejam concluídos mais rapidamente. Do lado da base de dados, optimizo as consultas lentas e ativo as caches de consulta adequadas ao sistema utilizado. Cada milissegundo poupado reduz a carga sobre o Fila de espera e aumenta o rendimento por trabalhador.

Mecanismos de emergência e reinícios seguros

Eu ativo limiar_de_reinício_de_emergência e emergency_restart_interval para que o FPM master reinicie se demasiados filhos falharem numa sucessão rápida. Esse reinício controlado evita reações em cadeia e mantém o serviço disponível. Ao mesmo tempo, defino limites claros para a memória e o número de processos para evitar escalonamentos. As verificações de integridade no lado upstream removem automaticamente backends defeituosos do pool e reduzem as taxas de erro. Isso mantém o Disponibilidade enquanto eu investigo a causa real.

Ajuste fino dos limites do sistema operativo e do systemd

Portanto, isso lista.backlog realmente tem efeito, eu ajusto os limites do kernel. O valor do SO net.core.somaxconn deve ser pelo menos tão alto quanto o backlog definido, caso contrário o sistema corta a fila. Também verifico o número de descritores de ficheiros permitidos: No pool FPM posso definir rlimit_files, ao nível do serviço asseguro LimitNOFILE (systemd) e ao nível do kernel fs.file-max. O servidor web precisa de reservas semelhantes para não atingir os seus limites mais cedo.

Para latências mais estáveis, reduzo vm.swappiness, para que o kernel não desloque prematuramente as páginas de memória ativamente utilizadas. Em configurações críticas de latência, eu desativo o Páginas enormes transparentes, para evitar falhas de página longas. Se o FPM for executado via TCP, eu também sincronizo os parâmetros net.ipv4.tcp_max_syn_backlog e reuse/keepalive. Esses detalhes do SO parecem imperceptíveis, mas eles decidem se as filas suave expiram ou se as ligações já foram rejeitadas antes do FPM.

Medir a carga de memória por processo

Em vez de fazer estimativas generalizadas, meço os Consumo real por trabalhador sob carga real. Utilizo ferramentas como ps, smem ou pmap, filtro os filhos do php-fpm e faço a média dos valores RSS enquanto os pedidos estão a decorrer. É importante ter em conta a utilização da OPCache partilhada: a memória partilhada não é contada várias vezes. Derivo o pm.max_children do valor médio e também planeio uma reserva para que a máquina não se depare com um estrangulamento mesmo durante os picos. Troca inclina-se.

Repito esta medição após alterações de funções ou de versões. Novas funcionalidades, mais dependências ou alterações nas estruturas podem aumentar significativamente a pegada por processo. Isto mantém o número de processos realista e a fila de espera curta.

Estado do PHP FPM, ping e métricas em tempo real

Para uma avaliação rápida da situação, ativo pm.status_path e um Ponto de extremidade de ping (ping.path/ping.response). Acima disto, posso ver valores-chave como a ligação aceite, o comprimento da fila de escuta, os processos inactivos/ocupados, o número máximo de crianças atingidas e a sua progressão. Leio estes valores periodicamente e defino valores limite: se a fila de escuta aumenta permanentemente, aumento os processos ou elimino a causa dos pedidos lentos. Se o número máximo de filhos alcançados aumentar enquanto o tempo ocioso permanecer baixo, o pool é muito pequeno ou está bloqueado por corredores longos.

Também separo os pools com perfis diferentes para que os picos numa área (por exemplo, importações de API) não façam com que o tráfego interativo fique de rastos. Para casos de diagnóstico, aumento temporariamente o log_level e deixo o slowlog capturar mais amostras, mas depois reduzo-o novamente para manter a carga de E/S baixa.

Uploads, buffering e corpos de pedidos grandes

Grandes uploads podem sobrecarregar os trabalhadores desnecessariamente se o PHP tiver que ler o corpo do pedido primeiro. Eu me certifico de que o servidor web amortecedores (por exemplo, fastcgi_request_buffering para NGINX), para que o FPM só inicie quando o corpo estiver completo. Isso significa que nenhum trabalhador bloqueia durante o upload. Utilizo client_max_body_size, post_max_size e max_input_time para controlar o tamanho e a duração dos pedidos sem comprometer os endpoints. Se houver ficheiros pelo meio, atribuo uma memória temporária (SSD) suficientemente rápida para evitar bloqueios de buffer.

Para pontos de extremidade com corpos muito grandes (por exemplo, exportações/importações), defino pools dedicados com seus próprios tempos limite e menos paralelismo. Isto deixa os trabalhadores padrão livres e o Fila de espera das acções importantes do utilizador.

Ligações à base de dados e limites do grupo

Mesmo a melhor definição de FPM é inútil se o Base de dados anteriormente limitado. Alinho o número máximo de processos PHP simultâneos com a capacidade real disponível da BD. Para ligações persistentes ou pools de ligações, certifico-me de que a soma de todos os pools é em max_connections permanece. Se existirem muitas consultas curtas, ajuda limitar moderadamente o paralelismo do PHP para que a base de dados não se desloque entre milhares de sessões.

As transacções lentas provocam rapidamente um atraso na fila de espera do FPM. Por isso, analiso os tempos de espera dos bloqueios, a utilização de índices e os planos de consulta. Cada redução no tempo de execução do BD reduz diretamente o PHPDuração do documento e reduz os comprimentos das filas de espera.

Lançamentos e implementações sem picos

Ao lançar novas versões, evito caches frias e tempestades de processos. Utilizo recarregar em vez de reiniciar o sistema, para que os pedidos dos trabalhadores existentes terminem de forma limpa (note process_control_timeout). Eu aqueço o OPCache em um estágio inicial, executando caminhos críticos uma vez antes de mudar ou trabalhando com pré-carregamento. Isso evita que muitos workers analisem arquivos de classe ao mesmo tempo e o Tempo de resposta aumenta a passos largos.

Com as estratégias azul/verde ou canário, aumento gradualmente a carga e monitorizo as páginas de estado. Só quando a fila de espera, a taxa de erro e as latências se mantêm estáveis é que aumento a proporção de tráfego. Esta abordagem controlada protege contra picos de carga durante a implementação.

Especialidades de contentores e VM

Nos contentores, a perceção Volume total de armazenamento muitas vezes inferior aos relatórios do anfitrião. Eu alinho o pm.max_children estritamente com o limite do cgroup e planeio uma reserva contra o OOM killer. Os limites de memória no PHP (memory_limit) e o footprint por processo devem corresponder, caso contrário, um único outlier é suficiente para encerrar o container.

Se não houver swap no contentor, é mais provável que ocorram cancelamentos forçados. É por isso que mantenho os processos conservadores, ativo a reciclagem e monitorizo os picos de RSS na carga de produção. Vários pools enxutos são geralmente mais robustos aqui do que um pool grande e monolítico.

Degradação e contrapressão controláveis

Se o Fila de espera Baseio-me numa degradação controlada: entrego deliberadamente o 503 com tentativas posteriores para pontos de extremidade não críticos em caso de sobrecarga, reduzo as funcionalidades dispendiosas (por exemplo, pesquisas em direto) e limito o acesso paralelo aos pontos de acesso. Desta forma, o sistema mantém-se recetivo enquanto eu corrijo a causa, em vez de todos os utilizadores ficarem sem tempo.

Brevemente resumido

Eu trago Enfileiramento de pedidos PHP sob controlo, combinando inteligentemente o número de processos simultâneos com o orçamento de RAM e o tipo de carga. Os valores elevados de backlog amortecem os picos, os tempos limite a todos os níveis encaixam-se perfeitamente e a reciclagem elimina os problemas de memória. Os registos e as métricas mostram-me se a fila está a crescer, onde os pedidos estão bloqueados e quando devo apertar o passo. Com ajustes cuidadosos e caching direcionado, reduzo o tempo de processamento por pedido e aumento o rendimento. Desta forma, os servidores fornecem de forma consistente e evitam custos elevados. Intervalos na vida quotidiana.

Artigos actuais