Modelos do Apache Worker determinam como o Servidor HTTP Apache processa os pedidos em paralelo e utiliza os recursos - especificamente através dos MPMs Prefork, Worker e Event. Neste artigo, mostrarei como os três modelos diferem tecnicamente, quais os efeitos que têm sobre Desempenho e escalonamento e que configuração é convincente em cenários reais.
Pontos centrais
Os pontos-chave que se seguem dar-lhe-ão uma visão rápida das diferenças e decisões mais importantes em torno das três MPM; em seguida, entrarei em mais pormenores e fornecerei Conhecimentos práticos.
- Pré-forquilhaBaseado em processos, com elevado isolamento e requisitos elevados de RAM.
- TrabalhadorThreads por processo, bom escalonamento, sensível ao keep-alive.
- EventoO ciclo de eventos separa a ligação e o pedido, o que é muito eficiente.
- AfinaçãoStartServers, ThreadsPerChild, MaxRequestWorkers especificamente.
- HTTP/2Funciona sensatamente com Worker e Event, mas não com Prefork.
O que os MPMs controlam no Apache
Utilizo os módulos de multiprocessamento (MPMs) para determinar se o Apache utiliza processos ou threads para cada pedido e como o servidor Paralelismo fornece. O Prefork cria muitos processos com um thread cada, o Worker cria alguns processos com muitos threads, o Event baseia-se no Worker e desacopla as conexões do processamento real. Esta escolha tem um efeito direto na memória, na utilização da CPU e nas latências. Por isso, tenho sempre em conta as sessões, o keep-alive, os protocolos como o HTTP/2 e os módulos utilizados. Se ignorarmos os MPMs, estamos a dar um passo em falso Desempenho e riscos de estrangulamento.
Prefork: Isolamento do processo e compatibilidade
A Prefork concentra-se em processos individuais para cada consulta e, por conseguinte, proporciona uma forte Isolamento. Se um processo falhar, os outros não são afectados - isto aumenta a tolerância a falhas para código sujo ou extensões antigas. O preço: Cada processo traz a sua própria sobrecarga, pelo que o consumo de RAM por ligação paralela aumenta. Com 100 pedidos simultâneos, são criados 100 processos, o que só considero aceitável com uma carga baixa a média. Utilizo o Prefork principalmente quando tenho de utilizar módulos sem segurança de threads ou quando os scripts CGI antigos requerem uma utilização elevada de memória. Separação requerer.
Worker: Threads e alto paralelismo
No modelo worker, os processos individuais executam vários threads, o que reduz o requisito de memória por pedido. diminuições. Esta arquitetura permite uma concorrência significativamente maior no mesmo hardware e é adequada para números de acesso elevados. No entanto, conexões longas de keep-alive podem amarrar threads e, portanto, bloquear a capacidade. Em configurações limpas e seguras para threads - por exemplo, com PHP-FPM - eu consigo valores de RPS muito bons com o Worker com uso moderado de RAM. Eu uso o Worker quando preciso de um sistema eficiente, baseado em threads Escalonamento e o keep-alive é controlado de forma sensata.
Evento: Estratégia keep-alive não bloqueante
O evento é baseado no modelo worker, mas elimina a fraqueza do keep-alive com um Ciclo de eventos. Um thread processa apenas o pedido efetivo; um mecanismo separado é responsável pela manutenção da ligação. Isso deixa os threads livres e a máquina processa mais sessões simultâneas com baixa latência. O Event é particularmente impressionante para conexões HTTP/2, pois a multiplexação e as conexões longas são executadas sem desperdiçar threads. Em configurações modernas, eu começo com Event como Base standard e só se adaptam se os módulos ou os requisitos herdados entrarem em conflito com isso.
Comparação tabular das MPM
O quadro seguinte resume as principais diferenças para que possa ver rapidamente avaliar qual o modelo adequado à carga e à situação do módulo. Antes de mudar, verifico sempre a segurança dos segmentos de todos os módulos e a duração prevista da ligação. Em seguida, atribuo MaxRequestWorkers, ThreadsPerChild e outros limites aos recursos disponíveis. A tabela ajuda-me a fazer suposições iniciais, mas não substitui os testes de carga em condições reais. Para eventos em particular, vale a pena medir com fases longas de keep-alive e HTTP/2 para determinar o Vantagens visível.
| MPM | Processos/Threads | Consumo de RAM | fiabilidade | Utilização típica |
|---|---|---|---|---|
| Pré-forquilha | 1 thread por processo | Elevado | Elevado (bom isolamento) | Carga baixa/média, módulos sem segurança de linha, CGI clássico |
| Trabalhador | Múltiplos threads por processo | Médio | Médio | Carga elevada com pilha segura para threads, por exemplo, PHP-FPM |
| Evento | Tópicos + ciclo de eventos | Baixa | Elevado | Carga muito elevada, ligações longas, HTTP/2 |
Li na tabela: Prefork pontua com blindagem, Worker para eficiência e Event para utilização máxima com ligações simultâneas. Eu uso o Event para novos projectos, desde que não haja incompatibilidades. Prefork ainda pode ser útil para pilhas legadas estáveis. Aqueles que estão apenas a migrar conseguem frequentemente progressos significativos com o Worker. No final, a escolha continua a ser Pesagem de módulos, perfil de tráfego e hardware.
Medição do desempenho: Critérios de referência e métricas
Sem medição, cada decisão MPM continua a ser uma Pressuposto. Em testes comparativos, o Worker fornece até cerca de 50 % mais pedidos por segundo do que o Prefork sob carga elevada; o Event também aumenta, especialmente durante as longas fases de keep-alive. Existem diferenças claras em termos de memória: com cerca de 1000 conexões simultâneas, as configurações do Prefork acabam com cerca de 2-4 GB de RAM, o Worker com 1-2 GB e o Event geralmente com menos de 1 GB. Verifico não só o RPS, mas também o tempo até ao primeiro byte, os percentis 95/99 e as taxas de erro. O perfil de carga da aplicação é crucial, porque solicitações curtas e rápidas se comportam de maneira diferente de streaming ou WebSockets.
Explicação dos parâmetros de afinação: StartServers, ThreadsPerChild, MaxRequestWorkers
Começo com valores conservadores e vou aumentando até atingir o valor pretendido. Utilização conhecer. Para o Prefork, defino MaxRequestWorkers com base na memória disponível e no tamanho do processo; para Worker e Event, planeio ThreadsPerChild e o número de processos de modo a que ThreadsPerChild × Processos = MaxRequestWorkers. Certifico-me de que há buffer suficiente para que os picos de carga não levem a erros 503. Um valor StartServers limpo evita bifurcações desnecessárias em condições de arranque a frio. Se quiser aprofundar o assunto, pode encontrar conhecimentos de base na secção Otimização do pool de threads, que podem ser transferidos diretamente para as configurações do Apache.
# Exemplo: Evento (Debian/Ubuntu)
a2dismod mpm_prefork mpm_worker
a2enmod mpm_event
systemctl restart apache2
# Utilizar o worker threading de forma sensata
# /etc/apache2/mods-available/mpm_event.conf
ServerLimit 16
StartServers 4
ThreadsPerChild 50
MaxRequestWorkers 800
MaxConnectionsPerChild 0
Em seguida, verifico o efeito com benchmarks e verifico se a CPU é suficientemente trabalho sem me afogar em trocas de contexto. Ao mesmo tempo, monitorizo as tendências da RAM, a atividade de swap e os descritores de ficheiros abertos. Se as filas ficarem visivelmente cheias, aumento cuidadosamente o MaxRequestWorkers ou reduzo os tempos de espera. Se tudo estiver a correr bem, faço uma cópia de segurança da configuração e documento o Valores-limite.
Keep-Alive, HTTP/2 e Thread-Contention
O Keep-Alive reduz os handshakes TCP, mas pode vincular threads - especialmente com o Worker-MPM, que coloca as conexões diretamente nas threads. Event resolve precisamente este efeito usando um loop de eventos para estabelecer a conexão. desenrola e threads apenas para trabalho ativo. Para HTTP/2, eu uso trabalhadores ou eventos, porque de outra forma a multiplexação é mais lenta. Na prática, gosto de monitorizar o comprimento da fila e verificar se a „retenção de threads“ é percetível. Tenho dicas sobre isso no artigo sobre Contenção de fios que utilizo para análises mais aprofundadas.
Também personalizo o KeepAliveTimeout para a aplicação, de modo a que as ligações inactivas não afectem o Capacidade não se ligam. A configuração ideal difere entre APIs, páginas LAMP clássicas e frontends baseados em HTTP/2 com muitos recursos. Se houver muito tempo ocioso, reduzo o tempo limite e aumento ligeiramente o MaxRequestWorkers. Se eu esperar muitas solicitações curtas, mantenho o Keep-Alive moderado para economizar a sobrecarga do TCP. Se ocorrerem tempos de espera, mudo para Event ou configuro Instâncias para.
Cenários práticos e escolha do modelo correto
Para aplicações antigas com módulos de risco, utilizo o Prefork e beneficio de uma elevada blindagem. Com a moderna arquitetura PHP-FPM com muitas ligações simultâneas, o Worker já apresenta resultados muito bons. O Event reduz ainda mais a latência e é dimensionado de forma limpa com sessões longas, WebSockets e HTTP/2. Em alojamentos partilhados ou com estado de código pouco claro, estou mais seguro com o Prefork, enquanto prefiro normalmente o Event em VPS e hardware dedicado. Se estiver a considerar alternativas ao Apache, pode encontrar mais informações no documento compacto Comparação de servidores Web auxiliares de decisão adicionais para o Nginx e o LiteSpeed, que verifico consoante a situação.
O evento compensa durante os picos de tráfego com carácter de explosão, uma vez que os segmentos não estão inactivos. persistir. Para aplicativos com muita CPU, eu limito MaxRequestWorkers para não sobrecarregar a máquina. Se a RAM é escassa, eu bani o Prefork e priorizo Workers/Event. Em ambientes multi-tenant, os contentores ou cgroups separam os serviços para que os workers/events possam realizar o seu potencial. No final, a medição confirma qual modelo da sua própria pilha tem o menor Latência fornecimentos.
Configuração no Ubuntu/Debian na prática
Ativo e desativo os MPM especificamente, testo o efeito e mantenho as opções de reversão pronto. No Debian/Ubuntu, uso os comandos conhecidos e verifico a saída de estado. Em seguida, ajusto os ficheiros mpm_*.conf e registo as alterações de versão. Antes do go-live, eu simulo picos de carga para reconhecer deadlocks ou gargalos de memória logo no início. Só quando os contadores de erros e percentis estão corretos é que assumo o controlo do Valores em produção.
# Ativar o prefork
a2dismod mpm_worker mpm_event
a2enmod mpm_prefork
systemctl restart apache2
Ativar o # Worker
a2dismod mpm_prefork mpm_event
a2enmod mpm_worker
systemctl restart apache2
# Ligar evento
a2dismod mpm_prefork mpm_worker
a2enmod mpm_event
systemctl restart apache2
# Monitorização
apachectl status
htop
journalctl -u apache2 -f
Monitorizo os registos de erros em paralelo para identificar rapidamente os problemas de segurança do segmento. Encontrar. Para HTTP/2, verifico se o protocolo é negociado corretamente e se a configuração do TLS está correta. Se houver latências perceptíveis, comparo prefork/worker/event alternadamente e fico de olho no desenvolvimento da RAM. Se o equilíbrio não estiver correto, ajusto o KeepAlive, o número de threads e os limites. Isto permite-me atingir tempos de resposta fiáveis sem Sobre-reserva.
Segurança da linha e compatibilidade do módulo
A verificação preliminar mais importante antes de passar de Prefork para Worker/Event é a Segurança da linha de todos os módulos. Clássico: mod_php é historicamente muito ligado ao Prefork; em pilhas modernas eu uso PHP-FPM via proxy_fcgi, para que o próprio Apache possa escalar baseado em threads. Módulos de filtragem e autenticação, módulos auto-escritos ou integrações (por exemplo, processamento de imagem) também devem ser considerados „thread safe“. Verifico os módulos carregados, analiso as notas de lançamento e efectuo um teste de colisão e de condições de corrida sob carga. O seguinte aplica-se ao HTTP/2: Com o Prefork, não é praticamente uma opção - os trabalhadores/eventos são os Pré-requisito, para que a multiplexagem e a definição de prioridades funcionem.
Planeamento da capacidade: calcular de forma realista o orçamento de armazenamento
Não dimensiono os MaxRequestWorkers „pelo tato“, mas com base em processos mensuráveis e tamanhos de rosca. Procedimento:
- Execute a carga de teste e, em seguida, meça o tamanho do conjunto residente (RSS) por processo Apache.
- Considere a sobrecarga adicional por thread para trabalhadores/eventos.
- Programar buffers para o kernel, cache de página, cache de sessão TLS, buffer de registo e upstreams.
# Estimar o tamanho do processo (exemplo)
ps -ylC apache2 --sort:rss | awk '{sum+=$8} END {print "RSS (kB) total:",sum}'
ps -L -p -o pid,tid,psr,stat,rss,cmd
pmap -x | tail -n 1 # Soma total por processo
Exemplo de cálculo: Um processo de evento ocupa 25 MB, os threads requerem uma média de 1 MB. Com 16 processos e 50 threads, isso resulta aproximadamente em 16 × 25 MB + 800 × 1 MB ≈ 1,2 GB. Eu defino MaxRequestWorkers = 800, deixo 30-40 % RAM livres e aumento a escala após a medição. Se utilizar o Prefork, basta calcular „Tamanho do processo × MaxRequestWorkers“ e manter Conservador.
Limites, atrasos e descritores do sistema operativo
O Apache só pode ser tão rápido quanto a plataforma subjacente. Verifico regularmente três pontos:
- Descritores de ficheiros: Uma thread/processo abre sockets, ficheiros e pipes. Eu aumento o LimitNOFILE via systemd e verifico a transferência.
- Aceitar o atraso: Para picos de ligação, aumento o ListenBacklog e forneço atrasos adequados do kernel.
- Ajuste de soquete/tempo limite: Defina RequestReadTimeout, Timeout e KeepAliveTimeout especificamente para mitigar „clientes lentos“.
# substituição do systemd
systemctl edit apache2
[Serviço]
LimitNOFILE=65536
# Parâmetros do kernel (temporário)
sysctl -w net.core.somaxconn=4096
# Apache: Backlog e timeouts
Escuta 0.0.0.0:443
EscutaBacklog 1024
Tempo limite 60
RequestReadTimeout cabeçalho=10-20,MinRate=1 corpo=10,MinRate=500
KeepAliveTimeout 5
MaxKeepAliveRequests 100
Prefiro manter os tempos limite um pouco mais rigorosos e monitorizar as taxas de erro. Se forem esperados carregamentos legitimamente longos, ajusto os valores especificamente por VirtualHost ...ligado.
Recarregamentos, implementações e contentores graciosos
Em funcionamento, prefiro os recarregamentos sem quebrar as ligações existentes. apachectl -k graceful ou systemctl reload recarrega as configurações, mas permite que os pedidos em execução expirem de forma limpa - para prefork por processo, para worker/event por thread. Em ambientes de container, eu planejo ServerLimit/ThreadsPerChild menores para que os pods possam ser início e sair. Eu presto atenção às cotas do cgroup: se o tempo de CPU ou a RAM forem limitados, MaxRequestWorkers deve ser correspondentemente menor, caso contrário a latência muda para o percentil 95/99.
Dimensionar corretamente as configurações de proxy/upstream
Muitas instâncias do Apache terminam o TLS e, em seguida, fazem proxy para PHP-FPM, servidores de aplicativos ou microsserviços. Eu vinculo a capacidade do frontend (MaxRequestWorkers) com os pools upstream: Para o PHP-FPM, pm.max_children e pm.max_requests são o limite superior rígido. Eu mantenho a proporção de forma que o Apache não aceite significativamente mais solicitações simultâneas do que os upstreams podem suportar - caso contrário, filas e Intervalos. Defino tempos limite explícitos para proxy_fcgi e proxy_http e verifico se o keep-alive é útil para o upstream ou se apenas consome recursos.
Monitorização e diagnóstico com o painel de avaliação
A saída mod_status revela o quão bem o MPM selecionado está a funcionar. Eu presto atenção nas proporções dos seguintes status: Leitura (cabeçalhos de entrada), Envio (a resposta é transmitida), Manter vivo (ligação aberta sem mão de obra), Em espera (livre). Elevadas proporções de Manter vivo no Worker indicam threads vinculadas - Event elimina exatamente isso. Permanente Leitura pode dever-se a clientes lentos ou a uma RequestReadTimeout-valores. Muitos Encerramento/regado de registo-Os estados sob pico de carga indicam pools de threads que são muito pequenos ou gargalos de E/S no registo.
Segurança e robustez: Slowloris & Co.
A combinação de Event-MPM, KeepAliveTimeouts apertados e RequestReadTimeout ajuda contra padrões de ataque do tipo „Slowloris“. Embora o Prefork proteja contra falhas no módulo através do isolamento do processo, ele permanece suscetível à RAMExaustão com muitas conexões. Combino limites ao nível do servidor Web com limites de taxa/ WAF a montante, para que o Apache não seja confrontado com milhões de sessões semi-abertas. Analiso os registos para os percentis 95/99, porque os ataques inflacionam as caudas da distribuição.
Padrões de distribuição e obstáculos típicos
Event é agora standard em muitas instalações Debian/Ubuntu. No entanto, os valores padrão são frequentemente conservadores (por exemplo, ThreadsPerChild 25-50). Eu só aumento estes valores após a medição. Erros frequentes:
- MaxRequestWorkers superior ao número de descritores de ficheiros disponíveis.
- Limites não sincronizados entre os servidores Apache e PHP-FPM/App.
- KeepAliveTimeout demasiado elevado para trabalhadores com muitos clientes móveis.
- Buffer em falta para E/S do registo - trabalhos de rotação de blocos de curto prazo.
Eu documento os valores alvo (utilização da CPU, RAM, RPS, P95) e guardo uma versão da configuração de trabalho. Só depois é que o Desdobramento.
Brevemente resumido
O Prefork apresenta-se forte Isolamento para pilhas antigas, mas custa muita memória. O Worker oferece um bom centro com threads por processo e escala de forma limpa, desde que o Keep-Alive não se torne desnecessário. O Event separa conexão e processamento, aumenta a utilização e mostra sua força com HTTP/2 e sessões longas. Meço sistematicamente, ajusto os limites e selecciono o MPM que se adequa ao código, ao perfil de tráfego e ao hardware. Com uma afinação limpa, objectivos de medição claros e monitorização focada, o Apache tira o máximo partido de cada um dos três modelos. Desempenho fora.

