...

Serveur de limites de descripteurs de fichiers : Optimiser les limites dans l'hébergement

Je montre comment le Limite de descripteur de fichier sur le serveur limite les connexions, les fichiers et les sockets et détermine ainsi les performances. Avec des étapes claires, j'augmente les limites, je mesure les besoins et j'évite les erreurs EMFILE avant que les services ne tombent en panne sous la charge.

Points centraux

Pour te permettre d'agir rapidement, je vais résumer les principales Levier pour optimiser les limites de la DA :

  • CauseChaque socket, chaque fichier, chaque connexion DB consomme des FD.
  • Symptômes: HTTP 500, messages EMFILE, E/S bloquées, crashs de service.
  • Mesure: ulimit, /proc/limits, file-max et lsof permettent d'y voir plus clair.
  • Optimisation: Augmenter les limites dans limits.conf, systemd et sysctl de manière ciblée.
  • SécuritéAccompagner les limites élevées d'une limitation de taux et d'un monitoring.

Que sont les descripteurs de fichiers et pourquoi les limites comptent-elles ?

Un descripteur de fichier est un simple entier Identificateur, que le noyau utilise pour référencer les fichiers ouverts, les sockets, les pipes ou les périphériques par processus. Chaque processus possède une limite logicielle et une limite matérielle, il existe en outre un maximum global pour l'ensemble du système, qui limite tous les processus ensemble et permet ainsi d'éviter les conflits. Pénurie doit être évitée. Par défaut, il n'y a souvent que 1024 FD disponibles par processus, ce qui devient vite étroit pour les sites web à fort trafic, les passerelles API ou les backends de chat et donc Pics de charge s'intensifie. Si un processus atteint sa limite, les nouvelles connexions échouent, les travailleurs ne peuvent plus ouvrir de fichiers et les logs se remplissent d'EMFILE, ce qui Temps de réponse se prolonge. La situation devient particulièrement critique pour les configurations qui occupent plusieurs handles par requête : PHP-FPM, les backends de cache, les fichiers log et les reverse proxies accumulent des FD jusqu'à ce que la Frontières bloquer.

Reconnaître et mesurer les symptômes

Les premiers signes d'une limite trop serrée se manifestent souvent sous forme de HTTP-500 sans cause claire, des réponses tenaces ou des redémarrages sporadiques de certains services. Des entrées de journal typiques telles que „Too many open files“ indiquent la présence d'EMFILE et signalent un problème immédiat. Nécessité d'agir. Je vérifie d'abord les limites liées au processus et la consommation actuelle afin de distinguer le goulot d'étranglement local du problème à l'échelle du système et ainsi Cause de préciser les choses. Pour une entrée en matière structurée, ce guide compact Guide des limites de serveur, si tu veux avoir une vue d'ensemble sur les leviers de commande, et Étapes de la planification. Ensuite, je mesure avec lsof combien de descripteurs un processus tient vraiment, car les valeurs mesurées battent les hypothèses dès que les profils de charge changer.

# Limite soft et hard du shell actuel
ulimit -n
ulimit -Hn

# Vérifier les limites d'un processus
cat /proc//limits | grep "ouvrir fichiers

# État global du système
cat /proc/sys/fs/file-nr # ouvert | libre | maximum
cat /proc/sys/fs/file-max # maximum global

# Estimer grossièrement la consommation par processus
lsof -p  | wc -l

Contrôler les limites et interpréter les chiffres clés

Je fais une distinction stricte entre les limites liées aux processus et les limites globales afin de pouvoir cibler les goulots d'étranglement. élimine au lieu de simplement les déplacer. La hard-limit fixe la limite supérieure pour les augmentations dans les sessions, tandis que fs.file-max et fs.nr_open définissent le cadre global, et ainsi Capacité de l'hôte. La règle générale qui a fait ses preuves est d'autoriser au moins 65535 FD par processus, dans la mesure où la RAM et la charge de travail le supportent et que tu as Dernier de l'entreprise. Parallèlement, je veille à ce que la somme des travailleurs actifs, des processus enfants et des connexions réseau dans des scénarios réalistes de charge élevée au sein de l'infrastructure globale soit suffisante. Valeurs cadres reste en place. Une vision claire de ces chiffres empêche une augmentation aveugle sans plan et maintient l'intégrité du système. Pression.

Commande/chemin Fonction À quoi faut-il faire attention ?
ulimit -n / -Hn Limite soft/hard de la session en cours Hard-Limit fixe une limite supérieure pour Augmentation
/proc//limits Limites per-process et fichiers ouverts Critique pour les démons comme nginx/php-fpm
/proc/sys/fs/file-max Maximum global de tous les FD Doit être ajouté au montant du procès et RAM correspondent à
/proc/sys/fs/file-nr Ouvert, libre, maximum en chiffres Tendance dans les tests de charge et Peaks vérifier
lsof Affiche les handles ouverts Par travailleur/fil de discussion consommé Mesurer les FD

Adapter les limites FD de manière temporaire et permanente

Pour les tests rapides, je définis une valeur ulimit plus élevée. Limite souple, avant de définir des règles permanentes et de redémarrer les services. Ensuite, j'écris les entrées appropriées dans /etc/security/limits.conf, j'ajoute les overrides systemd et je vérifie le changement avec un Test de charge. Important : l'utilisateur de service doit être correct, sinon l'augmentation n'a aucun effet et le système ne fonctionne pas. Problème réapparaît sous la charge. De plus, j'ajuste la limite globale afin que de nombreux processus de travail ne dépassent pas la limite du système. en cours de la configuration. Ce n'est que lorsque le processus et le système sont compatibles que la configuration résiste à de véritables scénarios de charge élevée et évite les erreurs. EMFILE.

# Temporaire (jusqu'à la déconnexion/redémarrage)
ulimit -n 65535

# Sur tout le système (jusqu'au redémarrage ou de façon permanente via sysctl.conf)
sudo sysctl -w fs.file-max=2097152

# Permanent (exemple pour les utilisateurs de serveur web)
echo -e "www-data soft nofile 65535\nww-data hard nofile 65535\n* soft nofile 65535\n* hard nofile 65535" | sudo tee -a /etc/security/limits.conf

# Services systemd (par ex. nginx)
sudo mkdir -p /etc/systemd/system/nginx.service.d
cat <<'EOF' | sudo tee /etc/systemd/system/nginx.service.d/limits.conf
[Service]
LimitNOFILE=65536
EOF
sudo systemctl daemon-reload && sudo systemctl restart nginx

Définir correctement les paramètres du noyau

Je valide fs.file-max et fs.nr_open ensemble, pour que le noyau ait assez de Tampon pour la charge de pointe. Si l'on n'augmente que la limite par processus, on se heurte à la limite globale et on déplace l'utilisation. goulot d'étranglement au niveau du système. Il est judicieux de prévoir un écart entre la charge de pointe typique et les valeurs globales, de manière à ce qu'il y ait des réserves pour les fenêtres de maintenance ou le trafic en rafale, et que Pics de risque peuvent être atténués. Tu trouveras des détails sur l'harmonisation à l'échelle du système dans l'article sur Réglage du noyau, que j'aime bien utiliser comme un outil pour les modifications profondes de l'OS. Liste de contrôle et les utiliser. Après les modifications, je recharge les paramètres, je vérifie à nouveau file-nr et je vérifie que tous les services ont été redémarrés avec les nouvelles limites et que les Valeurs prendre en charge.

# Paramètres permanents du noyau
sudo bash -c 'cat >> /etc/sysctl.d/99-ulimits.conf <<EOF
fs.file-max = 2097152
fs.nr_open = 2097152
EOF'
sudo sysctl --système

# Contrôle
cat /proc/sys/fs/file-max
cat /proc/sys/fs/nr_open || sysctl fs.nr_open

Planification des capacités et architecture

Une planification réaliste des capacités commence par des données mesurées Profils par requête : de combien de FD le serveur web, la couche d'application, la base de données et le cache ont-ils besoin ensemble ? A partir de ces chiffres, je déduis la somme des handles ouverts simultanément par hôte et je prévois des tampons pour Peaks une seule fois. Calcule de manière conservatrice : la rotation des logs, les sockets supplémentaires, les fichiers temporaires et les tâches de sauvegarde augmentent les besoins et dévorent les ressources. Réserves. Je veille à ce que la mise à l'échelle horizontale avec des équilibreurs de charge réduise la charge FD par nœud, ce qui permet d'améliorer la tolérance aux pannes et la fenêtre de changement. simplifié. Ce n'est qu'avec des valeurs limites claires par animal que tu peux fixer des limites de manière ciblée et répartir judicieusement la capacité entre les services. diviser.

Réglage fin du serveur web et de la base de données

Pour les serveurs web, je respecte la règle suivante Fils de discussion*4 inférieure à la limite FD, de sorte qu'il y ait des réserves pour les connexions en amont, les fichiers temporaires et les logs. Pour nginx et Apache, j'inclus dans le calcul le keep-live, les journaux d'accès et d'erreurs ouverts ainsi que les sockets en amont, ce qui me permet de m'assurer que Tampon. Les bases de données telles que MariaDB ou PostgreSQL ouvrent de nombreux sockets vers les applications, la réplication et la surveillance ; leurs limites doivent correspondre au pool de connexions et aux pics de trafic. correspondent à. Les caches (Redis, Memcached) réduisent la charge de la base de données, mais ne réduisent pas nécessairement le nombre de FD, à condition que de nombreux clients effectuent des requêtes et des connexions en parallèle. tiennent. Je prévois donc des limites coordonnées tout au long de la chaîne : front-end, upstream, DB, cache et files de messages, afin que nulle part la première limite dure ne soit atteinte. Barrière s'empare.

# Exemple : limite systemd nginx et worker
LimitNOFILE=65536 # systemd
worker_processes auto ;
worker_connections 4096 ; # 4096 * Worker <= 65536

# Exemple : PostgreSQL
max_connections = 1000 # Besoin FD ~ 1-2 par connexion + fichiers/logs

Garder les piles WordPress et PHP efficaces

Les instances de WordPress avec de nombreux plugins ouvrent plus de fichiers, plus de connexions réseau et plus encore Logs. Je réduis le nombre d'inclusions inutiles grâce à OPCache, j'allège les bases de données avec Redis Object Cache et j'externalise les actifs statiques via un CDN afin de réduire les accès aux fichiers et les coûts. Connexions de réduire le nombre de connexions. En même temps, j'augmente de manière ciblée les limites pour php-fpm et le serveur web, afin que les pics lors des cronjobs, des crawlers ou des checkouts de la boutique ne soient pas difficiles à gérer. interruptions créer. Une gestion propre des logs d'erreur et des rotations évite que les logwriters ne tournent à vide et n'ouvrent pas de nouveaux fichiers. ne doivent pas. Je combine ainsi la réduction de la consommation et l'augmentation de la limite, afin que la pile reste abordable en charge, et Débit tient.

Conteneurs et environnements en nuage

Dans Docker et Kubernetes, les processus héritent souvent des limites FD du nœuds, C'est pourquoi je vérifie d'abord les paramètres de l'hôte et ensuite les définitions du service. Des principes analogues s'appliquent à systemd-nspawn ou containerd, mais la mise en œuvre se fait dans des fichiers unitaires, des PodSpecs ou des configurations de démon avec Overrides. Je documente les limites sous forme de code (IaC) et les maintiens cohérentes via des playbooks, afin que les nouveaux nœuds aient des limites identiques. Frontières et de la sécurité. Dans le cas de Kubernetes, je vérifie en outre les SecurityContexts et définis les capabilities nécessaires pour que les systèmes puissent fonctionner correctement. Limites de l'action. L'important reste à la fin la mesure dans le cluster, car l'ordonnancement, l'autoscaling et les rolling updates modifient la répartition des handles ouverts et testent ton Tampon.

# Exemple : systemd dans les hôtes de conteneurs
cat <<'EOF' | sudo tee /etc/systemd/system/myapp.service.d/limits.conf
[Service]
LimitNOFILE=65536
EOF

# Kubernetes : podSpec (l'image du conteneur doit respecter ulimit)
# Remarque : les paramètres rlimit doivent être définis différemment en fonction du runtime/OS

Sécurité, limitation de taux et surveillance

Des limites élevées donnent de l'air, mais elles augmentent la surface d'attaque en cas de Inondations, C'est pourquoi je limite les requêtes à la périphérie avec le Rate-Limiting et je fixe des limites de connexion dans le serveur web. Un pare-feu pour les applications web et des délais d'attente raisonnables empêchent les connexions inactives d'endommager durablement les FD. lier. Pour les tests récurrents, j'utilise des profils de charge reproductibles et j'utilise Prometheus, Netdata ou Nagios pour observer de manière cohérente les métriques autour des fichiers ouverts et des Prises. En fonction de la charge de travail, je corrige progressivement les valeurs limites au lieu de les augmenter brusquement, afin que les effets restent mesurables et que l'on puisse les évaluer. Déconstruction est facile à comprendre. Ceux qui souhaitent approfondir les valeurs limites du côté de la connexion peuvent s'orienter grâce à cette contribution compacte sur Limites de connexion, qui m'a servi de Guide sert.

Dépannage d'EMFILE : procédure structurée

Je commence par jeter un coup d'œil au Journal et dans les logs de service pour délimiter proprement le moment et la fréquence des erreurs. Ensuite, je vérifie avec lsof la consommation maximale par processus et j'identifie des modèles tels que les fuites, l'augmentation de la journalisation ou les erreurs inhabituelles. prise-de types de limites. Ensuite, je compare les limites fixées avec les pics réels et j'augmente d'abord temporairement, afin de valider la cause et l'effet dans un test contrôlé et d'en tirer des conclusions. Réglages permanents de l'application. Si une fuite est détectée, je corrige ou redéploie le composant, car des limites plus élevées ne font que masquer les symptômes et déplacer le problème. Problème. Enfin, je documente la correction, j'établis des alarmes et je planifie un nouveau test de charge pour m'assurer que la solution tient la route et que les résultats sont satisfaisants. Confiance crée.

Évaluer de manière réaliste les coûts des ressources des limites élevées de DA

Chaque fichier ouvert ou chaque socket consomme de la mémoire du noyau. Prévois donc le Empreinte de la RAM par FD, selon la version du noyau et l'architecture, il y a entre quelques centaines d'octets et quelques kilo-octets (y compris les structures VFS/socket). Avec des centaines de milliers de FD, cela s'additionne. Je dimensionne le file-max global de manière à ce que, dans le pire des cas, il reste encore suffisamment de cache de pages et de mémoire vive pour les applications. Une simple vérification croisée s'effectue via vmstat, free et la tendance des FDs ouverts via file-nr pendant un Tests de charge de pointe. L'objectif est d'obtenir une configuration qui ne bascule pas dans le swap en cas de pic de charge et qui ne déclenche pas d'activité de recouvrement ou d'OOM excessive.

Pièges de la distribution et du chemin de démarrage (PAM, systemd, Cron)

L'efficacité des limites dépend du Chemin de départ à partir de . Les connexions basées sur PAM (ssh, su, login) lisent /etc/security/limits.conf, alors que les services systemd utilisent principalement leurs paramètres d'unité (LimitNOFILE) et pas obligatoirement PAM. Cron/at peut avoir ses propres contextes. Je valide donc par service :

  • Comment le processus démarre-t-il ? (systemctl status, ps -ef)
  • Quelles sont les limites qu'il voit vraiment ? (cat /proc//limits)
  • Est-ce que PAM fonctionne ? (Vérifier les modules PAM dans /etc/pam.d/*)
  • Existe-t-il des valeurs par défaut pour tout le système ? (systemd : DefaultLimitNOFILE dans system.conf)

J'évite ainsi que les applications reçoivent des limites FD différentes selon le chemin de démarrage et que, sous charge incohérent réagir.

Dimensionnement pratique avec exemples de calcul

Je compte sur les Workern et des profils de liaison à partir de l'arrière vers la capacité FD nécessaire :

  • nginx avec 8 workers à 4000 connexions : ~32000 connexions. Par connexion active, nginx réserve en général 1 FD ; plus l'upstream (Keep-Alive) et les logs ajoutent ~10-20% de tampons. Résultat : ~38000 FDs rien que pour nginx.
  • php-fpm avec 150 enfants, par enfant 20-40 FDs typiques (Includes, Sockets, Logs) : conservativement 6000 FDs.
  • Clients Redis/DB : 200 connexions parallèles, 1-2 FDs chacune : ~400 FDs.

Total par hôte : ~44k FDs. Je mets LimitNOFILE pour nginx à 65536, php-fpm analogue, et plane global fs.file-max de manière à ce que tous les services plus la réserve (x1,5-x2) puissent y tenir. Pour plusieurs instances très sollicitées par hôte, s'adapter globalement à 1-2 millions de FDs si la RAM et les chemins d'E/S le permettent. donner.

Diagnostic plus approfondi : trouver les fuites et les zones sensibles

Si les DA augmentent continuellement, j'en recherche la cause avec des outils ciblés :

# Manuels ouverts regroupés par type
lsof -p  | awk '{print $5}' | sort | uniq -c | sort -nr

# Uniquement les sockets d'un processus
lsof -Pan -p  -i

# Quels fichiers croissent (logs, temp)
lsof +L1 # Fichiers supprimés, mais toujours ouverts
ls -l /proc//fd

# vue syscall : qui ouvre en permanence ?
strace -f -p  -e trace=open,openat,close,socket,accept,accept4 -s 0

Les plus insidieux sont logs supprimés, qui restent ouverts : Ils occupent de l'espace et des FD, mais n'apparaissent plus dans le système de fichiers. Un redémarrage ou une réouverture explicite (par ex. pour nginx via USR1) résout le problème proprement. Des watcher/exportateurs mal configurés peuvent également ouvrir en permanence de nouveaux sockets - des limites de taux et des mise en commun.

Délimiter proprement Inotify, epoll et EMFILE

Toutes les limites de ressources ne sont pas appelées limites FD. Dans les environnements de développement et de CI, les builds échouent souvent avec ENOSPC en ce qui concerne Inotify (limites de watcher). Je vérifie et je fixe des limites complémentaires :

# Limites d'inotify (à l'échelle de l'utilisateur et des instances)
sysctl fs.inotify.max_user_watches
sysctl fs.inotify.max_user_instances

# Exemple d'augmentation
sudo sysctl -w fs.inotify.max_user_watches=524288
sudo sysctl -w fs.inotify.max_user_instances=1024

Alors qu'epoll travaille en interne avec des FD, le véritable goulot d'étranglement se situe au niveau de la formation massive de la population. Long-Lived-Les connexions FD ont souvent une limite. C'est pourquoi je corrèle les données epoll/event loop (par ex. handles actifs) avec file-nr et la consommation liée au processus.

Spécificités du langage et du runtime (Java, Node.js, Go, Python)

Les runtimes gèrent les FD de manière différente :

  • Java/NettyBeaucoup de canaux NIO par processus, les frameworks de logging maintiennent les appenders de fichiers ouverts. Je fixe des limites généreuses et fais tourner les logs avec une stratégie Reopen plutôt que Close/Replace.
  • Node.jsEMFILE apparaît rapidement dans les charges de travail lourdes du système de fichiers (par ex. watcher, pipelines de construction). Je régule les opérations fs parallèles, j'augmente les limites et je mets en place des stratégies de backoff/retry.
  • Allez surUn parallélisme élevé grâce aux goroutines peut ouvrir de nombreux sockets. Je limite les timeouts d'en-tête de numérotation et de réponse et je vérifie que les connexions sont fermées proprement (IdleConnTimeout).
  • Python/uWSGI/Gunicorn: les modèles worker/thread consomment des FD pour les logs, les sockets et les fichiers temporaires ; j'harmonise le nombre de worker, les pools de threads et les nofile-limites.

Tous ont un point commun : Sans une rotation coordonnée des logs et un système fiable de gestion des logs, il n'est pas possible d'obtenir des résultats. Gestion des connexions les DA augmentent insidieusement.

Les conteneurs concrètement : les réglages de Docker et Kubernetes

Pour que les conteneurs voient vraiment les limites souhaitées, je les place de manière cohérente le long de la chaîne :

  • Exécution de Docker: démarrer avec -ulimit nofile=65535:65535 ou définir par défaut le daemon (par ex. Ulimits par défaut).
  • Images: Les scripts de démarrage ne devraient pas réinitialiser une ulimit restrictive.
  • KubernetesSelon le runtime (containerd, cri-o), les réglages de rlimit ont des effets différents. Je teste dans le pod via cat /proc/self/limits et j'adapte les defaults du node/runtime si les spécificités du pod ne suffisent pas.

En particulier dans les environnements multi-locataires, je sécurise les Somme totale contre fs.file-max et isole les effets de voisinage bruyants en séparant les nodesets ou les PodBudgets, afin que les déploiements individuels ne consomment pas les FD réservés à l'hôte.

Préciser les métriques de surveillance et les alarmes

Outre file-nr et file-max, j'observe également les FD par processus et les lignes de tendance :

  • À l'échelle du système: Allocated vs. Maximum, Rate of Change, Ratio Peak/Maximum.
  • Par processus: FDs par worker/thread, processus Top-N, anomalies pendant la nuit (batch/jobs).
  • Qualitativement: taux d'erreurs HTTP, longueurs de files d'attente, erreurs d'acceptation/de handshake synchronisées avec la tendance FD.

Je mets des alertes à plusieurs niveaux: avertissement à 70-80%, critique à partir de 90% de la limite configurée, plus Détection des fuites sur les tendances à la hausse sur 7 jours. Je réagis ainsi à temps, avant que des barrières sévères ne s'appliquent.

Runbook pour les urgences

Quand EMFILE frappe de manière aiguë, j'agis par étapes claires :

  1. Identifier les principaux consommateurs (lsof, /proc//fd, entrées de journal).
  2. Augmenter temporairement la soft-limit (ulimit dans la session ou LimitNOFILE-Override) et redémarrer le service.
  3. Si les logs en sont la cause : Arrêter la rotation, déclencher le redémarrage, réduire le niveau des logs.
  4. Trafic en rafale à l'Edge étrangler (augmenter ou renforcer les limites de taux/connexion - selon la situation).
  5. Corriger la cause racine (fuite, parallélisme trop agressif, manque de timeouts) et les limites permanentes traîner.

Le suivi est important : documentation, tests de charge répétés, et aiguiser les alarmes de manière à ce que la même chaîne soit détectée à temps.

En bref

Avec des limites FD plus élevées, des paramètres de noyau bien définis et une architecture testée, je peux fournir aux services un accès à l'information plus facile. Salle de jeux sous une charge élevée. Je mesure d'abord, je fixe ensuite des valeurs limites appropriées, je vérifie avec des tests de charge et j'assure le résultat avec le Rate-Limiting, le monitoring et des informations claires. Règles.

Derniers articles