...

Modèles Apache Worker : comparaison entre Prefork, Worker et Event

Modèles Apache Worker déterminent la manière dont le serveur HTTP Apache traite les requêtes en parallèle et utilise les ressources - concrètement via les MPMs Prefork, Worker et Event. Dans cet article, je montre en quoi les trois modèles se distinguent techniquement, quels sont leurs effets sur Performance et la mise à l'échelle et quelle configuration est convaincante dans des scénarios réels.

Points centraux

Les points clés suivants te donnent un aperçu rapide des principales différences et décisions concernant les trois MPM ; ensuite, j'entre dans les détails et je livre Connaissances pratiques.

  • Prefork: Basé sur le processus, isolation élevée, besoin élevé de RAM.
  • Travailleur: threads par processus, bonne mise à l'échelle, sensible au Keep-Alive.
  • événement: Event-Loop découple la connexion et la demande, très efficace.
  • Tuning: StartServers, ThreadsPerChild, MaxRequestWorkers de manière ciblée.
  • HTTP/2: fonctionne judicieusement avec Worker et Event, pas avec Prefork.

Ce que les MPM contrôlent dans Apache

Avec les modules de multitraitement (MPM), je détermine si Apache utilise des processus ou des threads par requête et comment le serveur Parallélisme de l'ordinateur. Prefork génère de nombreux processus avec chacun un thread, Worker quelques processus avec de nombreux threads, Event s'appuie sur Worker et découple les connexions du traitement proprement dit. Ce choix a un impact direct sur la mémoire, l'utilisation du CPU et les latences. C'est pourquoi je tiens toujours compte des sessions, du Keep-Alive, des protocoles comme HTTP/2 et des modules utilisés. Ignorer les MPM, c'est se priver de ressources mesurables. Performance et risque de créer des goulots d'étranglement.

Prefork : Isolation du processus et compatibilité

Prefork s'appuie sur des processus individuels par demande et fournit ainsi de fortes Isolation. Si un processus tombe en panne, les autres ne sont pas affectés - ce qui augmente la tolérance aux erreurs en cas de code malpropre ou d'anciennes extensions. Le prix : chaque processus apporte son propre overhead, de sorte que la consommation de RAM augmente par connexion parallèle. Pour 100 demandes simultanées, il y a 100 processus, ce que je ne trouve acceptable que pour une charge faible à moyenne. J'utilise Prefork surtout lorsque je dois utiliser des modules sans sécurité de thread ou lorsque des scripts CGI hérités nécessitent des performances élevées. Séparation exigent.

Worker : Threads et parallélisme élevé

Dans le modèle Worker, les processus individuels exécutent plusieurs threads, ce qui réduit la quantité de mémoire nécessaire par requête. baisse. Cette architecture permet nettement plus de concourance sur le même matériel et convient à un nombre élevé d'accès. Les longues connexions keep-alive peuvent toutefois lier les threads et ainsi bloquer la capacité. Dans des configurations propres et sûres pour les threads - par exemple avec PHP-FPM - j'obtiens avec Worker de très bonnes valeurs RPS avec une utilisation modérée de RAM. J'utilise Worker lorsque j'ai besoin d'une solution efficace basée sur les threads. Mise à l'échelle et que Keep-Alive soit géré de manière judicieuse.

Événement : stratégie Keep-Alive non bloquante

Event s'appuie sur le modèle Worker, mais remédie à la faiblesse Keep-Alive par une Boucle d'événements. Un thread ne traite que la demande proprement dite ; le maintien de la connexion est assuré par un mécanisme séparé. Les threads restent ainsi libres et la machine traite davantage de sessions simultanées avec une faible latence. Pour les connexions HTTP/2, Event est particulièrement convaincant, car le multiplexage et les longues connexions s'effectuent sans gaspillage de threads. Dans les configurations modernes, je démarre avec Event en tant que Base standard et je ne m'adapte que si des modules ou des exigences héritées s'y opposent.

Comparaison des MPM sous forme de tableau

Le tableau suivant résume les principales différences, afin que je puisse d'un coup d'œil évaluer quel modèle correspond à la charge et à la situation du module. Avant le changement, je vérifie toujours la sécurité des threads de tous les modules et la durée de connexion attendue. Ensuite, j'attribue MaxRequestWorkers, ThreadsPerChild et d'autres limites aux ressources disponibles. Le tableau m'aide à faire les premières hypothèses, mais ne remplace pas les tests de charge en conditions réelles. En particulier pour Event, il vaut la peine d'effectuer des mesures avec de longues phases de keep-alive et HTTP/2 pour Avantages rendre visible.

MPM Processus/threads Consommation de RAM Fiabilité Utilisation typique
Prefork 1 thread par processus Haute Élevé (bonne isolation) Charge faible/moyenne, modules sans sécurité de thread, CGI classique
Travailleur Plusieurs threads par processus Moyens Moyens Charge élevée avec une pile thread-safe, par exemple PHP-FPM
événement Threads + boucle d'événements Faible Haute Charge très élevée, longues connexions, HTTP/2

Je lis dans le tableau : Prefork marque des points à blindage, Worker en cas d'efficacité et Event en cas d'utilisation maximale avec des connexions simultanées. Pour les nouveaux projets, j'utilise Event, à moins que des incompatibilités ne s'y opposent. Pour les piles héritées, Prefork peut encore être utile. Pour ceux qui migrent, Worker permet souvent de faire de nets progrès. Le choix reste en fin de compte un Mise en balance de modules, de profil de trafic et de matériel.

Mesurer les performances : Benchmarks et métriques

Sans mesure, toute décision MPM reste une Présomption. Dans les tests comparatifs, Worker fournit jusqu'à 50 % de requêtes par seconde de plus que Prefork en cas de charge élevée ; Event en fait plus, surtout lors de longues phases de maintien en ligne. En ce qui concerne la mémoire, les différences sont claires : pour environ 1000 connexions simultanées, les configurations Prefork atteignent en gros 2-4 Go de RAM, Worker 1-2 Go, Event généralement moins de 1 Go. Je ne vérifie pas seulement le RPS, mais aussi le Time to First Byte, les 95e/99e percentiles et les taux d'erreur. Le profil de charge de l'application est décisif, car les requêtes courtes et rapides se comportent différemment du streaming ou de l'utilisation de la mémoire. WebSockets.

Paramètres de réglage expliqués : StartServers, ThreadsPerChild, MaxRequestWorkers

Je commence par des valeurs conservatrices et j'augmente l'échelle jusqu'à ce que je trouve la valeur souhaitée. Taux d'occupation de la même manière. Pour Prefork, je fixe MaxRequestWorkers en fonction de la mémoire disponible et de la taille des processus ; pour Worker et Event, je planifie ThreadsPerChild et le nombre de processus de sorte que ThreadsPerChild × Processus = MaxRequestWorkers. Je veille à ce que la mémoire tampon soit suffisante pour que les pics de charge n'entraînent pas d'erreurs 503. Une valeur StartServers propre empêche les forks inutiles dans les conditions de démarrage à froid. Ceux qui souhaitent aller plus loin trouveront des informations de fond sur le Optimisation du pool de threads, qui peut être transféré directement dans les configurations Apache.

# Exemple : événement (Debian/Ubuntu)
a2dismod mpm_prefork mpm_worker
a2enmod mpm_event
systemctl restart apache2

# Exploiter judicieusement le worker-threading
# /etc/apache2/mods-available/mpm_event.conf
ServerLimit 16
StartServers 4
ThreadsPerChild 50
MaxRequestWorkers 800
MaxConnectionsPerChild 0

Je vérifie ensuite l'effet avec des benchmarks et contrôle si le CPU est assez travaillent sans se noyer dans les changements de contexte. En parallèle, j'observe les tendances de la RAM, l'activité de swap et les descripteurs de fichiers ouverts. Si les files d'attente sont visiblement pleines, j'augmente prudemment MaxRequestWorkers ou je réduis les temps de keep-alive. Si tout se passe bien, je sauvegarde la configuration et documente les résultats. Valeurs limites.

Keep-Alive, HTTP/2 et contention des threads

Keep-Alive réduit les handshakes TCP, mais peut lier les threads - en particulier avec le Worker-MPM, qui place les connexions directement sur les threads. Event résout précisément cet effet en faisant passer la connexion par une boucle d'événement déroule et n'utilise les threads que pour le travail actif. Pour HTTP/2, j'utilise donc Worker ou Event, car le multiplexage est sinon freiné. Dans la pratique, j'aime observer la longueur des files d'attente et vérifier si la „contention des threads“ se fait sentir. J'ai donné des conseils à ce sujet dans l'article sur Contenu du fil de discussion que j'utilise pour des analyses plus approfondies.

J'adapte également KeepAliveTimeout à l'application, afin que les connexions inactives ne Capacité ne pas se lier. Le réglage idéal diffère selon qu'il s'agit d'API, de pages LAMP classiques ou de frontaux basés sur HTTP/2 avec de nombreux assets. S'il y a beaucoup de temps mort, j'abaisse le timeout et j'augmente légèrement MaxRequestWorkers. Si j'attends beaucoup de requêtes courtes, je maintiens Keep-Alive à un niveau modéré afin d'économiser le TCP overhead. Si des temps d'attente surviennent, je passe à Event ou j'installe des Instances après

Scénarios pratiques et choix du bon modèle

Pour les applications héritées avec des modules à risque, j'utilise Prefork et je profite d'une grande blindage. Pour les architectures PHP-FPM modernes avec de nombreuses connexions simultanées, Worker donne déjà de très bons résultats. Event réduit encore plus la latence et s'adapte proprement aux longues sessions, aux WebSockets et à HTTP/2. Sur les hébergements partagés ou lorsque l'état du code n'est pas clair, je suis plus sûr de Prefork, tandis que sur les VPS et le matériel dédié, je préfère généralement Event. Pour ceux qui envisagent des alternatives à Apache, vous trouverez des informations dans le compact Comparaison des serveurs web des aides à la décision supplémentaires sur Nginx et LiteSpeed, que j'examine en fonction de la situation.

En cas de pics de trafic à caractère de burst, l'événement est payant, car les threads ne sont pas laissés au repos. persistent. Pour les applications gourmandes en CPU, je limite MaxRequestWorkers afin de ne pas surcharger la machine. S'il n'y a pas assez de RAM, je bannis Prefork et donne la priorité aux Worker/Event. Dans les environnements multi-locataires, les conteneurs ou les cgroups séparent les services, de sorte que Worker/Event déploient leur potentiel. Au final, la mesure confirme quel modèle est le moins gourmand en ressources dans sa propre pile. Latence fournit.

Configuration sur Ubuntu/Debian en pratique

J'active et désactive les MPM de manière ciblée, je teste l'impact et je garde des options de rollback prêt. Sous Debian/Ubuntu, j'utilise les commandes connues et je vérifie ensuite la sortie d'état. Ensuite, je modifie les fichiers mpm_*.conf et j'enregistre les modifications sous forme de version. Avant la mise en service, je fais simuler des pics de charge afin de détecter rapidement les blocages ou les goulots d'étranglement de la mémoire. Ce n'est que lorsque les compteurs d'erreurs et les centiles sont corrects que je reprends les Valeurs en production.

# Activer la préforce
a2dismod mpm_worker mpm_event
a2enmod mpm_prefork
systemctl restart apache2

# Activer le worker
a2dismod mpm_prefork mpm_event
a2enmod mpm_worker
systemctl restart apache2

# Activer l'événement
a2dismod mpm_prefork mpm_worker
a2enmod mpm_event
systemctl restart apache2

# Surveillance
apachectl statut
htop
journalctl -u apache2 -f

Je surveille en parallèle les journaux d'erreurs afin d'identifier rapidement les problèmes de sécurité des threads. trouver. Pour HTTP/2, je vérifie si le protocole est correctement négocié et si la configuration TLS est adaptée. Si les latences sont flagrantes, je compare Prefork/Worker/Event en alternance et je garde un œil sur l'évolution de la RAM. Si l'équilibre n'est pas bon, j'adapte KeepAlive, le nombre de threads et les limites. J'obtiens ainsi des temps de réponse fiables sans Surréservation.

Sécurité des threads et compatibilité des modules

Le contrôle préalable le plus important avant de passer de Prefork à Worker/Event est la Sécurité des fils de discussion de tous les modules. Classique : mod_php est historiquement étroitement lié à Prefork ; dans les piles modernes, j'utilise à la place PHP-FPM via proxy_fcgi, afin qu'Apache puisse lui-même s'adapter en fonction des threads. Les modules de filtrage et d'authentification, les modules écrits par l'utilisateur ou les intégrations (par exemple le traitement d'images) doivent également être considérés comme „thread safe“. Je vérifie les modules chargés, j'évalue les notes de mise à jour et j'effectue un test de crash et de race condition sous charge. Pour HTTP/2 : avec Prefork, ce n'est pratiquement pas une option - Worker/Event sont les Condition préalable, Le système d'information de l'entreprise doit être en mesure d'assurer le multiplexage et la priorisation.

Planification de la capacité : calculer le budget de stockage de manière réaliste

Je ne dimensionne pas MaxRequestWorkers de manière „ressentie“, mais à l'aide de tailles de processus et de threads mesurables. Procédure :

  • Faire tourner la charge de test, puis mesurer la taille du set résident (RSS) par processus Apache.
  • Pour Worker/Event, tenir compte de l'overhead supplémentaire par thread.
  • Prévoir des tampons pour le noyau, le cache de page, le cache de session TLS, les tampons de logs et les upstreams.
# Estimer la taille du processus (exemple)
ps -ylC apache2 --sort:rss | awk '{sum+=$8} END {print "Total RSS (kB) :",sum}'
ps -L -p  -o pid,tid,psr,stat,rss,cmd
pmap -x  | tail -n 1 # Total par processus

Exemple de calcul : un processus d'événement occupe 25 Mo, les threads ont besoin en moyenne de 1 Mo. Pour 16 processus et 50 threads, cela donne en gros 16 × 25 Mo + 800 × 1 Mo ≈ 1,2 Go. Je définis MaxRequestWorkers = 800, je laisse 30-40 % de RAM libre et j'augmente l'échelle en fonction des mesures. Ceux qui utilisent Prefork calculent simplement „taille du processus × MaxRequestWorkers“ et restent conservateur.

Limites du système d'exploitation, backlogs et descripteurs

Apache ne peut être aussi rapide que la plate-forme sous-jacente. Je vérifie régulièrement trois points :

  • Descripteurs de fichiers : Un thread/processus ouvre des sockets, des fichiers et des pipes. J'augmente LimitNOFILE via systemd et je vérifie la prise en charge.
  • Backlog d'acceptation : Pour les bursts de connexion, j'augmente ListenBacklog et je veille à ce que les backlogs du noyau soient adaptés.
  • Réglage du socket/timeout : Définir de manière ciblée le RequestReadTimeout, le Timeout et le KeepAliveTimeout afin de désamorcer les „clients lents“.
# override systemd
systemctl edit apache2
[Service]
LimitNOFILE=65536

# Paramètres du noyau (temporaire)
sysctl -w net.core.somaxconn=4096

# Apache : backlog et timeouts
Listes 0.0.0.0:443
ListenBacklog 1024
Timeout 60
RequestReadTimeout header=10-20,MinRate=1 body=10,MinRate=500
KeepAliveTimeout 5
MaxKeepAliveRequests 100

Je préfère respecter les délais de manière plus stricte et observer les taux d'erreur. Si de longs téléchargements légitimes sont attendus, j'ajuste les valeurs de manière ciblée par VirtualHost sur.

Rechargements, déploiements et conteneurs Graceful Reloads

Dans l'entreprise, je préfère les reloads sans rupture des connexions existantes. apachectl -k graceful ou systemctl reload recharge les configurations, mais laisse les requêtes en cours expirer proprement - par processus pour les prefork, par thread pour les worker/event. Dans les environnements de conteneurs, je prévois des ServerLimit/ThreadsPerChild plus petits, afin que les pods soient rapidement démarrer et terminer. Je fais attention aux quotas cgroup : si le temps CPU ou la RAM sont coupés, MaxRequestWorkers doit être inférieur en conséquence, sinon la latence se déplace vers le 95e/99e percentile.

Dimensionner correctement les configurations proxy/upstream

De nombreuses instances Apache terminent TLS et proxient ensuite vers PHP-FPM, App-Server ou Microservices. Ce faisant, je relie la capacité frontale (MaxRequestWorkers) aux pools en amont : Pour PHP-FPM, pm.max_children et pm.max_requests sont la limite supérieure dure. Je maintiens le rapport de telle sorte qu'Apache n'accepte pas beaucoup plus de requêtes simultanées que les upstreams ne peuvent en traiter - sinon, des files d'attente et des Timeouts. Pour proxy_fcgi et proxy_http, je définis explicitement des délais d'attente et je vérifie si le maintien de la connexion en amont est judicieux ou s'il ne fait que mobiliser des ressources.

Suivi et diagnostic avec le tableau de bord

La sortie mod_status révèle le bon fonctionnement du MPM choisi. Je fais attention aux proportions des états suivants : Lecture (en-têtes entrants), Envoyer (la réponse est transmise), Keepalive (connexion ouverte sans travail), Waiting (libre). Proportions élevées de Keepalive chez Worker indiquent des threads liés - Event élimine exactement cela. Permanent Lecture peut être dû à des clients lents ou à des RequestReadTimeout-de l'eau. Beaucoup de Fermeture/enregistrement-Les états en charge de pointe indiquent des pools de threads trop petits ou des goulots d'étranglement d'E/S dans la journalisation.

Sécurité et robustesse : Slowloris & Co.

La combinaison d'Event-MPM, de KeepAliveTimeouts serrés et de RequestReadTimeout permet de lutter contre les modèles d'attaque de type „Slowloris“. Prefork protège certes contre les crashs de modules grâce à l'isolation des processus, mais reste vulnérable aux attaques de la RAM.Épuisement pour de nombreuses connexions. Je combine des limites au niveau du serveur web avec des limites WAF/de débit en amont, afin qu'Apache ne soit pas confronté à des millions de sessions semi-ouvertes. J'évalue les logs aux percentiles 95/99, car les attaques gonflent les queues de distribution.

Défauts de distribution et écueils typiques

Sur de nombreuses installations Debian/Ubuntu, Event est aujourd'hui un standard. Malgré cela, les valeurs par défaut sont souvent conservatrices (par ex. ThreadsPerChild 25-50). Je ne les augmente qu'après les avoir mesurées. Erreurs fréquentes :

  • MaxRequestWorkers plus élevé que les descripteurs de fichiers disponibles.
  • Limites non synchronisées entre Apache et les serveurs PHP-FPM/App.
  • KeepAliveTimeout trop élevé pour les travailleurs ayant de nombreux clients mobiles.
  • Absence de tampon pour les E/S log - Bloquer les tâches de rotation à court terme.

Je documente les valeurs cibles (utilisation du CPU, RAM, RPS, P95) et sauvegarde la configuration fonctionnelle sous forme de version. Ce n'est qu'ensuite que la Déroulement.

En bref

Prefork fournit de solides Isolation pour les piles héritées, mais coûte beaucoup de mémoire. Worker offre un bon équilibre avec des threads par processus et s'adapte proprement tant que Keep-Alive n'est pas inutilement contraignant. Event sépare la connexion et le traitement, augmente l'utilisation et montre sa force avec HTTP/2 et les longues sessions. Je mesure systématiquement, j'adapte les limites et je choisis le MPM qui convient au code, au profil de trafic et au matériel. Avec un réglage propre, des objectifs de mesure clairs et une surveillance ciblée, Apache tire de chacun des trois modèles Performance dehors.

Derniers articles