Mostro come il Limite del descrittore di file sul server limita le connessioni, i file e i socket e quindi determina le prestazioni. Prendo misure chiare per aumentare i limiti, misurare la domanda e prevenire gli errori EMFILE prima che i servizi falliscano sotto carico.
Punti centrali
Affinché possiate agire rapidamente, ho riassunto i punti più importanti Leva per ottimizzare i limiti FD:
- CausaOgni socket, ogni file, ogni connessione DB consuma FD.
- SintomiHTTP 500, messaggi EMFILE, I/O bloccato, arresti anomali del servizio.
- Misurazione: ulimit, /proc/limits, file-max e lsof forniscono chiarezza.
- OttimizzazioneAumentare i limiti in limits.conf, systemd e sysctl in particolare.
- SicurezzaAffiancare i limiti elevati con la limitazione e il monitoraggio dei tassi.
Cosa sono i descrittori di file e perché i limiti contano
Un descrittore di file è un semplice intero Identificatore, che il kernel utilizza per fare riferimento a file, socket, pipe o dispositivi aperti per ogni processo. Ogni processo ha un limite morbido e uno rigido, e c'è anche un massimo globale a livello di sistema che limita tutti i processi insieme, riducendo così al minimo il numero di processi che possono essere eseguiti. Scarsità dovrebbe essere impedito. Per impostazione predefinita, spesso sono disponibili solo 1024 FD per processo, il che diventa rapidamente un problema per i siti web ad alto traffico, i gateway API o i backend di chat e così via. Picchi di carico è intensificato. Se un processo raggiunge il suo limite, le nuove connessioni falliscono, i lavoratori non possono più aprire i file e i registri si riempiono di EMFILE, il che può causare il blocco del processo. Tempi di risposta esteso. Diventa particolarmente critico con le configurazioni che occupano diversi handle per ogni richiesta: PHP-FPM, backend di cache, file di log e reverse proxy accumulano FD fino a quando non viene raggiunto l'obiettivo. Confini blocco.
Riconoscere e misurare i sintomi
Spesso i primi segni di un limite troppo stretto si manifestano come HTTP-500 senza una causa chiara, risposte lente o riavvii sporadici di singoli servizi. Voci di registro tipiche come „Troppi file aperti“ indicano EMFILE e segnalano un'immediata Necessità di azione. Per prima cosa verifico i limiti e il consumo di corrente relativi al processo, per distinguere tra colli di bottiglia locali e problemi a livello di sistema, e quindi per determinare l'entità del problema. Causa per essere più precisi. Questa guida compatta è adatta per un'introduzione strutturata Guida ai limiti del server, se si desidera avere una rapida panoramica delle viti di regolazione e delle Passi piano. Uso poi lsof per misurare quanti descrittori contiene realmente un processo, perché i valori misurati battono le supposizioni non appena i profili di carico cambiamento.
# Limite morbido e rigido della shell corrente
ulimit -n
ulimit -Hn
# Controllare i limiti di un processo
cat /proc//limiti | grep "file aperti"
# Stato generale del sistema
cat /proc/sys/fs/file-nr # aperto | libero | massimo
cat /proc/sys/fs/file-max # massimo globale
# Stima approssimativa del consumo per processo
lsof -p | wc -l
Controllo dei limiti e interpretazione delle cifre chiave
Faccio una distinzione rigorosa tra i confini del processo e quelli globali, in modo da poter identificare i colli di bottiglia in modo mirato. eliminare invece di spostarlo semplicemente. L'hard limit stabilisce il limite superiore per gli aumenti delle sessioni, mentre fs.file-max e fs.nr_open definiscono il frame globale e quindi il Capacità dell'host. Una regola empirica e collaudata è quella di consentire almeno 65535 FD per processo, a condizione che la RAM e il carico di lavoro lo supportino e che si disponga della capacità di gestire il processo. Carico so. Allo stesso tempo, mi assicuro che la somma dei lavoratori attivi, dei processi figli e delle connessioni di rete in scenari realistici ad alto carico all'interno del sistema globale di gestione delle risorse. Valori del telaio rimane. Una visione chiara di queste cifre impedisce aumenti ciechi senza un piano e tiene sotto controllo l'integrità del sistema. Pressione.
| Comando/Percorso | Funzione | A cosa prestare attenzione |
|---|---|---|
ulimit -n / -Hn | Limite morbido/duro della sessione corrente | Hard limit imposta il limite massimo per Innalzamento |
/proc//limiti | Limiti per processo e file aperti | Critico per i demoni come nginx/php-fpm |
/proc/sys/fs/file-max | Massimo globale di tutti gli FD | Deve essere aggiunto all'importo del processo e RAM in forma |
/proc/sys/fs/file-nr | Aperta, gratuita, massimamente numerosa | Andamento dei test di carico e Picchi controllo |
lsof | Mostra le maniglie aperte | Per lavoratore/thread consumato Misurare le FD |
Regolare i limiti della FD in modo temporaneo e permanente
Per i test veloci, uso ulimit per impostare un valore più alto di Limite morbido, prima di definire regole permanenti e riavviare i servizi. Quindi scrivo le voci appropriate in /etc/security/limits.conf, aggiungo le sovrascritture di systemd e verifico la modifica con un'analisi mirata di Prova di carico. Importante: l'utente del servizio deve essere corretto, altrimenti l'aumento non avrà alcun effetto e la Problema riappare sotto carico. Regolo anche il limite globale in modo che molti processi worker non superino insieme il limite del sistema. accumulare lasciare. Solo quando i lati del processo e del sistema si adattano tra loro, la configurazione può resistere a scenari reali di carico elevato ed evitare EMFILE.
# Temporaneo (fino al logout/riavvio)
ulimit -n 65535
# A livello di sistema (fino al riavvio o in modo permanente tramite sysctl.conf)
sudo sysctl -w fs.file-max=2097152
# Permanente (esempio per gli utenti del server 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
# servizi systemd (ad es. nginx)
sudo mkdir -p /etc/systemd/system/nginx.service.d
cat <<'EOF' | sudo tee /etc/systemd/system/nginx.service.d/limits.conf
[Servizio]
LimitNOFILE=65536
EOF
sudo systemctl daemon-reload && sudo systemctl restart nginx
Impostare correttamente i parametri del kernel
Convalido fs.file-max e fs.nr_open insieme in modo che il kernel abbia abbastanza Buffer per i picchi di carico. Se si aumenta solo il limite per processo, altrimenti si colpisce il limite globale e si sposta la colli di bottiglia a livello di sistema. È ragionevole mantenere uno scarto tra il carico di picco tipico e i valori globali, in modo da avere riserve per le finestre di manutenzione o per il traffico a raffica e per le operazioni di manutenzione. Picchi di rischio può essere smorzato. Per maggiori dettagli sulla messa a punto dell'intero sistema, consultare l'articolo su Messa a punto del kernel, che mi piace usare come strumento per le personalizzazioni approfondite del sistema operativo. Lista di controllo utilizzo. Dopo aver apportato le modifiche, ricarico i parametri, controllo nuovamente il file-nr e verifico che tutti i servizi siano stati riavviati con i nuovi limiti e che il file-nr sia stato riavviato. Valori prendere il sopravvento.
# Parametri permanenti del kernel
sudo bash -c 'cat >> /etc/sysctl.d/99-ulimits.conf <<EOF
fs.file-max = 2097152
fs.nr_open = 2097152
EOF'
sudo sysctl --system
Controllo #
cat /proc/sys/fs/file-max
cat /proc/sys/fs/nr_open || sysctl fs.nr_open
Pianificazione e architettura della capacità
Una pianificazione realistica della capacità inizia con la misurazione Profili per richiesta: di quanti FD hanno bisogno complessivamente il server web, il livello app, il database e la cache? Da questi dati, ricavo il numero totale di handle aperti simultaneamente per host e pianifico i buffer per Picchi on. Fate un calcolo prudente: la rotazione dei log, i socket aggiuntivi, i file temporanei e i lavori di backup aumentano la domanda e consumano risorse. Riserve. Presto attenzione al fatto che lo scaling orizzontale con i bilanciatori di carico riduce il carico FD per nodo, riducendo la tolleranza ai guasti e le finestre di modifica. Semplificato. Solo con valori limite chiari per livello è possibile impostare limiti specifici e allocare in modo sensato la capacità tra i servizi. dividere.
Messa a punto del server web e del database
Per i server web, mi attengo alla regola Fili*4 più piccolo del limite FD, in modo che ci siano riserve per le connessioni upstream, i file temporanei e i log. Per nginx e Apache, includo nel calcolo i log di keep-alive, di accesso aperto e di errore, così come i socket upstream, assicurandomi in questo modo Buffer. I database come MariaDB o PostgreSQL aprono molti socket contro le applicazioni, la replica e il monitoraggio; i loro limiti devono corrispondere al pool di connessioni e ai picchi di traffico. in forma. Le cache (Redis, Memcached) riducono il carico del DB, ma non riducono necessariamente il numero di FD se molti client richiedono e si connettono in parallelo. tenere. Sto quindi pianificando limiti coordinati lungo la catena: frontend, upstream, DB, cache e code di messaggi, in modo che non venga superato il primo limite rigido. Barriera raggiunge.
# Esempio: limite e lavoratore del sistema nginx
LimitNOFILE=65536 # systemd
worker_processes auto;
worker_connections 4096; # 4096 * Worker <= 65536
# Esempio: PostgreSQL
max_connessioni = 1000 # Requisiti FD ~ 1-2 per connessione + file/log
Mantenere efficienti gli stack WordPress e PHP
Le istanze di WordPress con molti plugin aprono un maggior numero di file, di connessioni di rete e di Registri. Riduco il numero di inclusioni non necessarie con OPCache, riduco il carico sui database con Redis Object Cache ed esternalizzo le risorse statiche tramite una CDN per ridurre al minimo gli accessi ai file e le risorse statiche. Connessioni per ridurre il carico. Allo stesso tempo, ho aumentato in modo specifico i limiti di php-fpm e del server web, in modo che i picchi durante i cronjob, i crawler o i checkout del negozio non siano un problema. interruzioni generare. Una gestione pulita dei registri degli errori e delle rotazioni evita che gli autori dei registri si imbattano nel nulla e non aprano nuovi file. può. Questo è il modo in cui combino la riduzione dei consumi e l'aumento dei limiti, in modo che lo stack rimanga conveniente anche sotto carico e Produttività stive.
Contenitori e ambienti cloud
In Docker e Kubernetes, i processi spesso ereditano i limiti di FD del sistema di gestione delle risorse. Nodi, per questo motivo controllo prima i parametri dell'host e poi le definizioni dei servizi. Principi analoghi si applicano a systemd-nspawn o containerd, ma l'implementazione avviene in file di unità, PodSpec o configurazioni di demoni con Sovrascritte. Documento i limiti come codice (IaC) e li mantengo coerenti tramite i playbook in modo che i nuovi nodi abbiano limiti identici. Confini portare con sé. Con Kubernetes, verifico anche i SecurityContext e imposto le capacità richieste in modo che il lato sistema Limiti hanno effetto. Alla fine, la misurazione nel cluster rimane importante, perché lo scheduling, l'autoscaling e gli aggiornamenti rolling modificano la distribuzione degli handle aperti e mettono alla prova la vostra Buffer.
# Esempio: systemd in host container
cat <<'EOF' | sudo tee /etc/systemd/system/myapp.service.d/limits.conf
[Servizio]
LimitNOFILE=65536
EOF
# Kubernetes: podSpec (l'immagine del contenitore deve rispettare ulimit)
# Nota: le impostazioni di rlimit devono essere impostate in modo diverso a seconda del runtime/OS
Sicurezza, limitazione della velocità e monitoraggio
I limiti elevati offrono un po' di respiro, ma aumentano la superficie di attacco per Alluvioni, Pertanto, limito le richieste ai bordi con il rate limiting e imposto limiti di connessione nel server web. Un firewall per applicazioni web e timeout ragionevoli impediscono che le connessioni inattive blocchino in modo permanente le FD. legare. Per i test ricorrenti, utilizzo profili di carico riproducibili e mi avvalgo di Prometheus, Netdata o Nagios per monitorare in modo coerente le metriche relative ai file aperti e ai file di memoria. Prese. A seconda del carico di lavoro, correggo i valori limite gradualmente invece di aumentarli bruscamente, in modo che gli effetti rimangano misurabili e Smontaggio è facile. Se volete approfondire i valori limite sul lato delle connessioni, questo articolo compatto su Limiti di connessione, che uso ai confini della rete come Guida serve.
Risoluzione dei problemi con EMFILE: procedura strutturata
Inizio con uno sguardo al Diario e nei registri di servizio per restringere il tempo e la frequenza degli errori. Uso poi lsof per controllare il consumo massimo per processo e identificare schemi come perdite, aumento dei log o anomalie. Presa-tipi. Successivamente, confronto i limiti impostati con i picchi reali e li aumento temporaneamente in un primo momento, in modo da poter convalidare la causa e l'effetto in un test controllato e, da questo, determinare Impostazioni permanenti derivare. Se si riscontra una perdita, si applica una patch o un rollback al componente, perché limiti più elevati nascondono solo i sintomi e rimandano il problema. Problema. Infine, documento la correzione, imposto gli allarmi e pianifico un nuovo test di carico in modo che la soluzione sia valida e possa essere utilizzata di nuovo. Fiducia crea.
Valutare in modo realistico i costi delle risorse per limiti elevati di FD.
Ogni file o socket aperto costa memoria al kernel. Pertanto, pianificare la Ingombro della RAM A seconda della versione del kernel e dell'architettura, sono necessarie da poche centinaia di byte a qualche kilobyte per ogni FD (comprese le strutture VFS/socket). Con centinaia di migliaia di FD, i conti tornano. Ho dimensionato il file-max globale in modo tale che, nel peggiore dei casi, la cache delle pagine e la memoria di lavoro rimangano libere per le applicazioni. Una semplice verifica viene effettuata tramite vmstat, free e l'andamento degli FD aperti tramite file-nr durante una Test di carico di picco. L'obiettivo è una configurazione che non si trasformi in swap durante i picchi di carico e che non inneschi un'eccessiva attività di recupero o di OOM.
Trappole per la distribuzione e l'avvio del percorso (PAM, systemd, Cron)
L'applicazione dei limiti dipende dalla Percorso iniziale da. I login basati su PAM (ssh, su, login) leggono /etc/security/limits.conf, mentre i servizi systemd usano principalmente i loro parametri di unità (LimitNOFILE) e non PAM obbligatorio. Cron/at possono avere i propri contesti. Pertanto, convalido per ogni servizio:
- Come si avvia il processo? (systemctl status, ps -ef)
- Quali limiti vede realmente? (cat /proc//limiti)
- PAM funziona? (Controllare i moduli PAM in /etc/pam.d/*)
- Esistono valori predefiniti a livello di sistema? (systemd: DefaultLimitNOFILE in system.conf)
In questo modo, impedisco alle applicazioni di ricevere limiti FD diversi a seconda del percorso di avvio e di incoerente reagire.
Dimensionamento pratico con esempi di calcolo
Conto sul Lavoratori e i profili di connessione da quelli arretrati alla capacità FD richiesta:
- nginx con 8 lavoratori con 4000 connessioni ciascuno: ~32000 connessioni. Di norma, nginx riserva 1 FD per ogni connessione attiva; più upstream (keep-alive) e log aggiungono ~10-20% di buffer. Risultato: ~38000 FD solo per nginx.
- php-fpm con 150 bambini, in genere 20-40 FD per bambino (include, socket, log): prudenzialmente 6000 FD.
- Client Redis/DB: 200 connessioni parallele, 1-2 FD ciascuno: ~400 FD.
Totale per host: ~44k FD. Ho impostato LimiteNOFILE per nginx a 65536, php-fpm analogo, e plane globale fs.file-max in modo che tutti i servizi più la riserva (x1,5-x2) siano compatibili. Per diverse istanze molto utilizzate per host, scalare globalmente a 1-2 milioni di FD se la RAM e i percorsi di I/O sono sufficienti. arrendersi.
Diagnosi più approfondita: trovare perdite e punti caldi
Se le FD aumentano continuamente, utilizzo strumenti mirati per trovarne la causa:
# Maniglie aperte raggruppate per tipo
lsof -p | awk '{print $5}' | sort | uniq -c | sort -nr
# Solo i socket di un processo
lsof -Pan -p -i
# Quali sono i file in crescita (log, temp)?
lsof +L1 # File cancellati ma ancora aperti
ls -l /proc//fd
# Vista della Syscall: chi apre costantemente?
strace -f -p -e trace=open,openat,close,socket,accept,accept4 -s 0
Particolarmente insidiosi sono Registri cancellati, che sono ancora aperti: Occupano spazio e FD, ma non appaiono più nel file system. Il riavvio o una riapertura esplicita (ad esempio con nginx tramite USR1) risolve questo problema in modo pulito. Anche i watcher/exporter configurati in modo errato possono aprire continuamente nuovi socket - i limiti di velocità e i pooling.
Delimitare chiaramente Inotify, epoll ed EMFILE
Non tutti i limiti di risorse sono chiamati limiti FD. Negli ambienti di sviluppo e CI, le build spesso falliscono con ENOSPC in relazione a Inotify (limiti di watcher). Io controllo e imposto come supplemento:
# Limiti di Inotify (a livello di utente e di istanze)
sysctl fs.inotify.max_user_watches
sysctl fs.inotify.max_user_instances
# Esempio di aumento
sudo sysctl -w fs.inotify.max_user_watches=524288
sudo sysctl -w fs.inotify.max_user_instances=1024
Sebbene epoll funzioni internamente con gli FD, il vero collo di bottiglia con le massicce A lungo termine-Le connessioni spesso superano il limite FD stesso. Pertanto, metto in relazione i dati di epoll/event loop (ad esempio, gli handle attivi) con il consumo di file-nr e di processi.
Specialità di linguaggio e runtime (Java, Node.js, Go, Python)
I runtime gestiscono gli FD in modo diverso:
- Java/NettyMolti canali NOK per processo, i framework di registrazione mantengono aperti i file appender. Impongo limiti generosi e faccio ruotare i log con una strategia di riapertura invece che di chiusura/sostituzione.
- Nodo.jsEMFILE si verifica rapidamente con carichi di lavoro pesanti per il file system (ad esempio, watcher, pipeline di compilazione). Regolo le operazioni fs parallele, aumento i limiti e imposto strategie di backoff/retry.
- Vai aUn elevato parallelismo attraverso le goroutine può aprire molti socket. Limito i timeout delle intestazioni di chiamata e di risposta e controllo che le connessioni siano chiuse correttamente (IdleConnTimeout).
- Python/uWSGI/GunicornI modelli worker/thread consumano FD per i log, i socket e i file temporanei; armonizzo il numero di worker, i pool di thread e i file temporanei. nofile-Limiti.
Hanno tutti una cosa in comune: Senza una rotazione coordinata dei registri e un'affidabile Gestione delle connessioni Gli FD aumentano gradualmente.
Contenitori in termini concreti: impostazioni di Docker e Kubernetes
Per garantire che i contenitori vedano effettivamente i limiti desiderati, li imposto in modo coerente lungo la catena:
- Esecuzione di Dockeravviare con -ulimit nofile=65535:65535 o impostare il demone come predefinito (ad esempio, limiti predefiniti).
- ImmaginiGli script di avvio non devono reimpostare un ulimit restrittivo.
- KubernetesA seconda del runtime (containerd, cri-o), le impostazioni dei limiti hanno effetto in modo diverso. Faccio dei test nel pod tramite cat /proc/self/limits e regolo i valori predefiniti di node/runtime se le specifiche del pod non sono sufficienti.
Soprattutto negli ambienti multi-tenant, proteggo il Importo totale contro fs.file-max e isolare gli effetti dei vicini rumorosi usando nodi separati o pod budget in modo che le singole distribuzioni non consumino gli FD riservati all'host.
Chiarire le metriche di monitoraggio e gli allarmi
Oltre a file-nr e file-max, monitoro anche le FD per processo e le linee di tendenza:
- A livello di sistemaAllocazione vs. massimo, tasso di variazione, rapporto picco/massimo.
- Per processoFD per worker/thread, processi Top-N, anomalie notturne (batch/job).
- QualitativoTassi di errore HTTP, lunghezza delle code, errori di accettazione/handshake sincronizzati con l'andamento dell'FD.
Ho impostato gli avvisi multilivelloAvvertenza a 70-80%, Critico da 90% del limite configurato, più Rilevamento delle perdite attraverso le tendenze ascendenti a 7 giorni. Questo mi permette di reagire per tempo, prima che entrino in vigore le barriere più dure.
Libro di bordo per le emergenze
Quando l'EMFILE colpisce in modo acuto, agisco per gradi:
- Identificare i principali consumatori (lsof, /proc//fd, voci del diario).
- Aumentare temporaneamente il soft limit (ulimit in sessione o LimitNOFILE override) e riavviare il servizio.
- Se il motivo sono i registri: Interrompere la rotazione, attivare la riapertura, ridurre il livello dei log.
- Traffico intenso ai margini acceleratore (Aumentare o restringere i limiti di tariffa/connessione, a seconda della situazione).
- Correzione della causa principale (perdita, parallelismo troppo aggressivo, timeout mancanti) e limiti permanenti stringere.
Il follow-up è importante: documentazione, prove di carico ripetute e allarmi di affilatura in modo da riconoscere tempestivamente la stessa catena.
Riassumendo brevemente
Con limiti FD aumentati, parametri del kernel impostati in modo pulito e un'architettura testata, posso fornire servizi ai miei clienti. Spazio di manovra sotto carico elevato. Prima misuro, poi imposto valori limite appropriati, verifico con test di carico e assicuro il risultato con la limitazione della velocità, il monitoraggio e la cancellazione. Regole.


