Ajuste do php-fpm decide quantos processos PHP-FPM podem ser executados simultaneamente, a rapidez com que novos processos são iniciados e por quanto tempo eles atendem às solicitações. Vou mostrar-lhe como pm.max_children, pm, pm.start_servers, pm.min_spare_servers, pm.max_spare_servers e pm.max_requests de forma a que a sua aplicação responda rapidamente sob carga e o servidor não entre em swapping.
Pontos centrais
- modo pm: escolha corretamente entre estático, dinâmico ou sob demanda, para que os processos estejam disponíveis de acordo com o seu tráfego.
- pm.max_children: Alinhar o número de processos PHP simultâneos na RAM com o consumo real do processo.
- Valores iniciais/de reserva: equilibrar adequadamente pm.start_servers, pm.min_spare_servers, pm.max_spare_servers.
- Reciclagem: Amortecer fugas de memória com pm.max_requests, sem criar sobrecarga desnecessária.
- Monitorização: Monitorize os registos, o estado e a RAM e, em seguida, faça ajustes graduais.
Por que a gestão de processos é importante
Eu participo PHP-FPM a execução de cada script PHP como um processo separado, e cada solicitação paralela precisa do seu próprio trabalhador. Sem limites adequados, as solicitações ficam bloqueadas em filas, o que leva a Intervalos e erros. Se eu definir limites máximos muito altos, o pool de processos consome a memória e o kernel começa a trocar. Esse equilíbrio não é uma questão de adivinhação: eu me baseio em valores reais e mantenho uma margem de segurança. Assim, a latência permanece baixa e a taxa de transferência estável, mesmo quando a carga oscila.
Para mim, é importante ter uma valor-alvo: Quantas execuções PHP simultâneas pretendo permitir sem esgotar a RAM? Ao mesmo tempo, verifico se os gargalos ocorrem mais na Base de dados, em APIs externas ou no servidor web. Só quando conheço o gargalo é que escolho os valores corretos para pm, pm.max_children e outros. Começo de forma conservadora, avalio e depois aumento gradualmente. Assim evito reinicializações bruscas e falhas inesperadas.
Os três modos pm: static, dynamic, ondemand
O modo estático mantém sempre exatamente pm.max_children processos disponíveis. Isso proporciona latências muito previsíveis, pois não é necessário nenhum processo de inicialização. Eu uso static quando a carga é muito uniforme e há RAM suficiente disponível. No entanto, quando a demanda varia, eu desperdiço facilmente em static. Memória. Por isso, utilizo static especificamente onde preciso de uma execução constante.
Com dinâmico Eu inicio uma quantidade inicial e deixo o tamanho do pool oscilar entre min_spare e max_spare. Este modo é adequado para tráfego com picos, porque os trabalhadores são criados e encerrados conforme necessário. Eu mantenho sempre processos ociosos suficientes para lidar com picos sem tempo de espera. No entanto, muitos trabalhadores ociosos ocupam recursos desnecessariamente. RAM, por isso mantenho a margem de poupança reduzida. Assim, a piscina permanece flexível, sem inchar.
No modo a pedido Inicialmente, não existem trabalhadores, o PHP-FPM só os inicia quando há solicitações. Isso economiza memória em períodos de inatividade, mas o primeiro acesso tem um pouco de latência. Eu escolho ondemand para pools raramente acessados, ferramentas administrativas ou pontos finais cron. Para sites muito frequentados, ondemand geralmente oferece tempos de resposta piores. Nesses casos, eu prefiro claramente dynamic com valores de reserva bem definidos.
Dimensionar corretamente o pm.max_children
Penso que sim pm.max_children da RAM disponível para PHP e da memória média por trabalhador. Para isso, primeiro reservo memória para o sistema, servidor web, base de dados e caches, para que o sistema não entre em Externalização funciona. Divido a RAM restante pelo consumo real medido do processo. Da teoria, retiro uma margem de segurança de 20–30 % para compensar valores atípicos e picos de carga. Utilizo o resultado como valor inicial e, em seguida, observo o efeito.
Eu determino o consumo médio do processo com ferramentas como ps, top ou htop e vejo RSS/RES. Importante: eu faço a medição sob carga típica, não em modo inativo. Quando carrego muitos plugins, frameworks ou bibliotecas grandes, o consumo por trabalhador aumenta significativamente. Além disso, a CPU limita a curva: mais processos não ajudam quando um Rosca simples-Desempenho da CPU limitado por solicitação. Quem quiser aprofundar-se nas características da CPU encontrará informações sobre Desempenho de thread único.
Mantenho as minhas suposições transparentes: quanta RAM está realmente disponível para o PHP? Qual é o tamanho de um trabalhador em pedidos típicos? Quais são os picos que ocorrem? Se as respostas estiverem corretas, defino pm.max_children, faço uma recarga suave e controlo a RAM, os tempos de resposta e as taxas de erro. Só depois disso é que continuo a subir ou descer em pequenos passos.
Valores de referência de acordo com o tamanho do servidor
A tabela seguinte fornece-me Valores iniciais à mão. Não substitui a medição, mas fornece uma orientação sólida para as primeiras configurações. Eu ajusto os valores para cada aplicação e verifico-os com monitorização. Se as reservas permanecerem inutilizadas, eu aumento cuidadosamente. Se o servidor atingir o limite da RAM, eu reduzo os valores.
| RAM do servidor | RAM para PHP | Ø MB/Trabalhador | pm.max_children (Início) | Utilização |
|---|---|---|---|---|
| 1–2 GB | ~1 GB | 50–60 | 15–20 | Pequenos sites, blogs |
| 4–8 GB | ~4–6 GB | 60–80 | 30–80 | Negócios, pequenas lojas |
| 16+ GB | ~10–12 GB | 70–90 | 100–160 | Alta carga, API, lojas |
Eu leio a tabela da direita para a esquerda: O Utilização Para o projeto, verifico se a RAM está reservada de forma realista para o PHP. Em seguida, seleciono um tamanho de worker adequado à base de código e às extensões. Depois, defino o pm.max_children e observo o efeito em tempo real. A taxa de acerto e a estabilidade aumentam quando documento estas etapas de forma clara.
Definir valores iniciais, de reserva e de pedidos
Com pm.iniciar_servidores Eu defino quantos processos estão imediatamente disponíveis. Um número muito baixo gera arranques a frio sob carga, um número muito alto ocupa RAM desnecessariamente. Costumo usar 15–30 % de pm.max_children e arredondo quando a carga começa mais calma. Em picos de tráfego, escolho uma quantidade inicial um pouco maior para que as solicitações não cheguem antes que haja trabalhadores suficientes à espera. Esse ajuste fino reduz significativamente o tempo de resposta inicial.
Os valores pm.min_servidores_sobressalentes e pm.max_spare_servers definem o intervalo de inatividade. Eu mantenho tantos trabalhadores livres que novas solicitações tenham acesso direto, mas não tantos a ponto de os processos ociosos desperdiçarem memória. Para lojas, gosto de definir uma janela mais restrita para suavizar picos. Com pm.max_requests Eu reciclo processos após algumas centenas de solicitações para limitar o desvio de memória. Para aplicações discretas, eu escolho 500–800, mas se houver suspeita de vazamentos, eu deliberadamente escolho um número menor.
Monitorização e resolução de problemas
Verifico regularmente Registos, páginas de estado e RAM. Avisos sobre limites pm.max_children atingidos são para mim um sinal claro para aumentar o limite máximo ou otimizar o código/banco de dados. Se os erros 502/504 se acumulam, eu verifico os registos do servidor web e as filas. Flutuações significativas na latência indicam poucos processos, I/O bloqueado ou custos de processo demasiado elevados. Primeiro, analiso os factos concretos e, em seguida, reajo com pequenos passos, nunca com saltos XXL.
Consigo identificar os pontos críticos mais rapidamente quando utilizo o Tempos de espera Ao longo de toda a cadeia: servidor web, PHP-FPM, base de dados, serviços externos. Se o tempo de backend aumentar apenas em determinadas rotas, isolo as causas através de profiling. Se os tempos de espera ocorrerem em todos os locais, intervenho no tamanho do servidor e do pool. Também é útil dar uma olhada nas filas de trabalho e nos processos no status D. Só quando eu entendo a situação é que altero os limites – e documento cada alteração de forma clara.
Servidor web e PHP-FPM em interação
Certifico-me de que Servidor Web-Limites e PHP-FPM harmonizam-se. Demasiadas ligações simultâneas no servidor web com poucos trabalhadores causam filas de espera e tempos de espera. Se os trabalhadores forem aumentados, mas o servidor web limitar a aceitação, o desempenho fica aquém. Parâmetros como worker_connections, event-Loop e Keep-Alive afetam diretamente a carga do PHP. Uma introdução prática ao ajuste fino é fornecida por dicas sobre Threadpools no servidor web.
Eu fico com Manter em permanência-Janela de tempo em vista, para que as ligações ociosas não bloqueiem desnecessariamente os trabalhadores. Para ativos estáticos, defino um cache agressivo antes do PHP, para manter a carga de trabalho longe do pool. Os caches de proxy reverso ajudam adicionalmente quando respostas idênticas são frequentemente solicitadas. Assim, posso manter o pm.max_children mais baixo e ainda assim entregar mais rapidamente. Menos trabalho por solicitação é frequentemente o ajuste mais eficaz.
Parafusos de ajuste finos em php-fpm.conf
Vou além dos valores fundamentais e ajusto os Parâmetros da piscina Ótimo. Com pm.max_spawn_rate limito a velocidade com que novos trabalhadores podem ser criados, para que o servidor não inicie processos de forma demasiado agressiva durante picos de carga e entre em CPU thrashing. Para ondemand, defino com pm.process_idle_timeout é importante determinar a rapidez com que os trabalhadores não utilizados desaparecem – se for muito curto, gera sobrecarga inicial; se for muito longo, ocupa RAM. No caso do ouvir-Socket, decido entre Unix-Socket e TCP. Um Unix-Socket economiza sobrecarga e oferece uma atribuição de direitos clara através de proprietário da lista, listen.group e modo de escuta. Para ambas as variantes, eu defino lista.backlog suficientemente alto para que os bursts que chegam sejam armazenados no buffer do kernel, em vez de serem imediatamente rejeitados. Com rlimit_files Se necessário, aumento o número de ficheiros abertos por trabalhador, o que proporciona estabilidade quando há muitos uploads e downloads simultâneos. E, se for necessário estabelecer prioridades, utilizo prioridade do processo, para tratar os pools menos críticos de forma um pouco secundária em termos de CPU.
Slowlog e proteção contra travamentos
Para tornar visíveis os pedidos difíceis, ativo o Slowlog. Com request_slowlog_timeout defino o limite (por exemplo, 2–3 s) a partir do qual um rastreio de pilha é enviado para o registo lento escrito. Assim, encontro I/O bloqueantes, loops dispendiosos ou bloqueios inesperados. Contra bloqueios reais, utilizo request_terminate_timeout, que é interrompido abruptamente quando um pedido demora demasiado tempo. Considero estes intervalos de tempo consistentes com tempo_de_execução_máx do PHP e dos tempos limite do servidor web, para que uma camada não seja interrompida antes da outra. Na prática, começo de forma conservadora, analiso os slowlogs sob carga e ajusto os limites gradualmente até que os sinais sejam significativos, sem sobrecarregar o log.
Opcache, memory_limit e a sua influência no tamanho dos trabalhadores
Eu recebo o Cache no meu planeamento de RAM. A sua área de memória partilhada não é contabilizada por trabalhador, mas é utilizada em conjunto por todos os processos. Tamanho e fragmentação (opcache.memory_consumption, buffer_de_strings_internas) influenciam significativamente o tempo de aquecimento e a taxa de acertos. Um Opcache bem dimensionado reduz a pressão sobre a CPU e a RAM por solicitação, pois menos código é recompilado. Ao mesmo tempo, observo que memory_limit: Um valor elevado protege contra a falta de memória em casos isolados, mas aumenta o orçamento teórico para o pior cenário por trabalhador. Por isso, planeio com a média medida mais uma margem, e não com o memory_limit puro. Funcionalidades como pré-carregamento ou JIT aumentam a necessidade de memória – testo-as especificamente e calculo o consumo adicional na conta pm.max_children.
Separar e priorizar pools
Eu divido as aplicações em várias piscinas quando os perfis de carga diferem significativamente. Um pool para tráfego front-end, outro para administração/back-end e um terceiro para cron/uploads: assim, isolo os picos e atribuo limites diferenciados. Para pontos finais raramente frequentados, defino a pedido com um pequeno tempo limite de inatividade, para o front-end dinâmico com margem de manobra reduzida. Sobre utilizador/grupo e, se necessário,. chroot Eu garanto um isolamento limpo, enquanto os direitos de socket regulam qual processo do servidor web pode aceder. Quando são necessárias prioridades, o frontend recebe mais pm.max_children e, se necessário, uma neutra prioridade do processo, enquanto Cron/Reports são executados com um orçamento menor e prioridade mais baixa. Assim, a interface do utilizador permanece responsiva, mesmo quando tarefas pesadas estão a ser executadas em segundo plano.
Utilizar os pontos finais de estado de forma adequada
Para o diagnóstico de tempo de execução, ativo pm.status_path e opcionalmente ping.path por pool. No estado, vejo trabalhadores ativos/inativos que Fila de listas, contadores relacionados ao rendimento e métricas de pedidos lentos. Uma fila de lista em constante crescimento ou trabalhadores ociosos constantemente são sinais de alarme para mim. Eu protejo esses pontos finais atrás de autenticação e uma rede interna para que nenhum detalhe operacional seja divulgado externamente. Além disso, eu ativo capturar_saída_dos_trabalhadores, se eu quiser recolher rapidamente stdout/stderr dos trabalhadores – por exemplo, em caso de erros difíceis de reproduzir. Combino esses sinais com métricas do sistema (RAM, CPU, I/O) para decidir se aumento pm.max_children, atualizo valores de reserva ou ajusto a aplicação.
Particularidades em contentores e VMs
Em Container e pequenas VMs, tenho em conta os limites do cgroup e o risco do OOM-Killer. Defino o pm.max_children estritamente de acordo com o Limite de memória do contentor e testo picos de carga para garantir que nenhum trabalhador seja encerrado. Sem swap em contentores, a margem de segurança é particularmente importante. Para quotas de CPU, escalo o número de trabalhadores para o número de vCPU disponível: se a aplicação estiver limitada pela CPU, mais paralelismo trará filas em vez de rendimento. As cargas de trabalho limitadas pela E/S suportam mais processos, desde que o orçamento de RAM seja suficiente. Além disso, defino limiar_de_reinício_de_emergência e intervalo de reinício de emergência para o processo mestre, a fim de evitar uma espiral de falhas, caso um bug raro afete vários filhos em um curto espaço de tempo. Assim, o serviço permanece disponível enquanto analiso a causa.
Implementações e recargas sem falhas e sem interrupções
Estou a planear Recargas de modo que as solicitações em andamento sejam concluídas corretamente. Um recarregamento gracioso (por exemplo, via systemd reload) adota novas configurações sem encerrar conexões abertas. Eu mantenho o caminho do soquete estável para que o servidor web não veja nenhuma interrupção na conexão. Em mudanças de versão que invalidam muito o Opcache, eu pré-carrego o cache (pré-carregamento/solicitações de aquecimento) para limitar os picos de latência logo após a implementação. Testo primeiro as alterações maiores num conjunto menor ou numa instância Canary com configuração idêntica, antes de implementar os valores em toda a área. Cada ajuste é registado com carimbo de data/hora e capturas de ecrã de métricas no meu registo de alterações – isso reduz o tempo de pesquisa de erros, caso haja efeitos colaterais inesperados.
Comportamento de picos e filas de espera
Eu suavizo os picos de carga com um Design de filas de espera ab. Eu coloco lista.backlog tão alto que o kernel pode armazenar temporariamente mais tentativas de conexão. No lado do servidor web, limito o número máximo de conexões FastCGI simultâneas por pool de forma que elas cheguem a pm.max_children é adequado. Assim, os picos de tráfego acumulam-se preferencialmente no servidor web (barato) do que no PHP (caro). Eu meço o Fila de listas no estado FPM: se aumentar regularmente, eu aumento o número de trabalhadores, otimizo as taxas de acertos do cache ou reduzo os valores agressivos de keep-alive. O objetivo é, em picos, o Tempo até ao primeiro byte manter estável, em vez de deixar as solicitações ficarem presas em filas intermináveis.
Fluxo de trabalho prático para ajustes
Começo com um Auditoria: Orçamento de RAM, tamanho do processo, perfis de E/S. Em seguida, defino valores iniciais conservadores para pm.max_children e o modo pm. Depois, realizo testes de carga ou observo os picos reais. Registo todas as alterações, incluindo métricas e intervalos de tempo. Após cada ajuste, verifico a RAM, a latência P50/P95 e as taxas de erro – só então passo para a próxima etapa.
Quando chego repetidamente ao limite, não escalo imediatamente a situação. Trabalhador-Número. Primeiro, otimizo consultas, taxas de acertos de cache e funções dispendiosas. Desvio trabalhos com grande carga de IO para filas e encurto os caminhos de resposta. Só quando a aplicação funciona de forma eficiente é que aumento o tamanho do pool. Este processo poupa recursos e evita danos consequentes noutros locais.
Cenários típicos: valores exemplificativos
Num servidor virtual de 2 GB, reservo cerca de 1 GB para PHP-FPM e defino um consumo de trabalho de cerca de 50-60 MB. Assim, começo com pm.max_children em 15-20 e uso dynamic com uma quantidade inicial pequena. Mantenho min_spare em 2-3 e max_spare em 5-6. Defino pm.max_requests para 500, para que os processos sejam trocados regularmente. Estas configurações proporcionam tempos de resposta estáveis para projetos pequenos.
Com 8 GB de RAM, geralmente planeio 4–6 GB para PHP e defino tamanhos de trabalho de 60–80 MB. Isso resulta em 30–80 processos filhos como área inicial. pm.start_servers está entre 15 e 20, min_spare entre 10 e 15, max_spare entre 25 e 30. Escolho pm.max_requests entre 500 e 800. Sob carga, verifico se o pico de RAM deixa margem e, em seguida, aumento cuidadosamente.
Em configurações de alta carga com 16+ GB de RAM, reservo 10–12 GB para FPM. Com 70–90 MB por trabalhador, chego rapidamente a 100–160 processos. Se estático ou dinâmico faz sentido depende do tipo de carga. Para uma utilização elevada permanente, o estático é mais adequado, para uma procura ondulante, o dinâmico. Em ambos os casos, a monitorização consistente continua a ser obrigatória.
Evitar obstáculos e definir prioridades
Não confundo o número de Visitantes com o número de scripts PHP simultâneos. Muitas visualizações de páginas atingem caches, fornecem ficheiros estáticos ou bloqueiam fora do PHP. Por isso, dimensiono o pm.max_children de acordo com o tempo PHP medido, e não com as sessões. Se os processos forem definidos de forma demasiado parcimoniosa, vejo pedidos em espera e taxas de erro crescentes. Se os valores forem demasiado elevados, a memória transita para o swap e tudo fica mais lento.
Um erro comum: mais processos significam mais Velocidade. Na verdade, o que conta é o equilíbrio entre CPU, IO e RAM. Se a CPU atingir 100 % e a latência disparar, mais trabalhadores dificilmente ajudarão. É melhor eliminar o verdadeiro gargalo ou reduzir a carga através da cache. O guia explica por que os trabalhadores são frequentemente o gargalo. PHP Worker como gargalo.
Brevemente resumido
Primeiro, determino o valor real RAM-Consumo por trabalhador e defino pm.max_children com buffer. Em seguida, seleciono o modo pm adequado ao tipo de carga e equilibro os valores iniciais e de reserva. Com pm.max_requests, mantenho os processos atualizados, sem sobrecarga desnecessária. Encaminho logs, status e métricas para um monitoramento limpo, para que cada alteração permaneça mensurável. Assim, obtenho tempos de resposta curtos, pools estáveis e uma carga de servidor com reservas para picos.


