Pokazuję, w jaki sposób Limit deskryptora pliku na serwerze ogranicza połączenia, pliki i gniazda, a tym samym określa wydajność. Podejmuję wyraźne kroki w celu zwiększenia limitów, pomiaru zapotrzebowania i zapobiegania błędom EMFILE, zanim usługi ulegną awarii pod obciążeniem.
Punkty centralne
Abyś mógł działać szybko, podsumowałem najważniejsze z nich Dźwignia aby zoptymalizować limity FD:
- PrzyczynaKażde gniazdo, każdy plik, każde połączenie DB zużywa FD.
- ObjawyHTTP 500, komunikaty EMFILE, zablokowane wejścia/wyjścia, awarie usług.
- Pomiarulimit, /proc/limits, file-max i lsof zapewniają przejrzystość.
- OptymalizacjaPodniesienie limitów w limits.conf, systemd i sysctl.
- BezpieczeństwoFlankowanie wysokich limitów z ograniczeniem prędkości i monitorowaniem.
Czym są deskryptory plików i dlaczego liczą się limity?
Deskryptor pliku jest prostą liczbą całkowitą Identyfikator, którego jądro używa do odwoływania się do otwartych plików, gniazd, potoków lub urządzeń na proces. Każdy proces ma miękki i twardy limit, a także globalne maksimum systemowe, które ogranicza wszystkie procesy razem, a tym samym minimalizuje liczbę procesów, które mogą działać. Niedobór należy zapobiegać. Domyślnie, często dostępne są tylko 1024 FD na proces, co szybko staje się ciasne dla witryn o dużym natężeniu ruchu, bram API lub backendów czatu, a więc Szczyty obciążenia jest zintensyfikowana. Jeśli proces osiągnie swój limit, nowe połączenia kończą się niepowodzeniem, pracownicy nie mogą już otwierać plików, a dzienniki zapełniają się EMFILE, co może powodować Czasy reakcji rozszerzony. Staje się to szczególnie krytyczne w przypadku konfiguracji, które zajmują kilka uchwytów na żądanie: PHP-FPM, backendy pamięci podręcznej, pliki dziennika i odwrotne serwery proxy gromadzą FD, dopóki Granice blok.
Rozpoznawanie i mierzenie objawów
Pierwsze oznaki zbyt ciasnego limitu są często widoczne jako HTTP-500 bez wyraźnej przyczyny, powolne odpowiedzi lub sporadyczne restarty poszczególnych usług. Typowe wpisy w dzienniku, takie jak „Zbyt wiele otwartych plików“ wskazują na EMFILE i sygnalizują natychmiastowe uruchomienie usługi. Potrzeba działania. Najpierw sprawdzam limity związane z procesem i zużycie prądu w celu rozróżnienia między lokalnymi wąskimi gardłami a problemami ogólnosystemowymi, a tym samym w celu ustalenia Przyczyna aby być bardziej precyzyjnym. Ten kompaktowy przewodnik nadaje się do ustrukturyzowanego wprowadzenia Przewodnik po ograniczeniach serwera, jeśli chcesz mieć szybki przegląd śrub regulacyjnych i Kroki plan. Następnie używam lsof, aby zmierzyć, ile deskryptorów naprawdę posiada proces, ponieważ zmierzone wartości przewyższają założenia, gdy tylko profile obciążenia zmiana.
# Miękki i twardy limit bieżącej powłoki
ulimit -n
ulimit -Hn
# Sprawdzenie limitów procesu
cat /proc//limits | grep "open files"
# Ogólny status systemu
cat /proc/sys/fs/file-nr # open | free | maximum
cat /proc/sys/fs/file-max # globalne maksimum
# Zgrubne oszacowanie zużycia na proces
lsof -p | wc -l
Sprawdzanie limitów i interpretacja kluczowych danych
Dokonuję ścisłego rozróżnienia między granicami związanymi z procesem i globalnymi, dzięki czemu mogę zidentyfikować wąskie gardła w ukierunkowany sposób. wyeliminować zamiast po prostu go przenosić. Twardy limit określa górną granicę dla wzrostów sesji, podczas gdy fs.file-max i fs.nr_open definiują globalne ramy, a tym samym Pojemność hosta. Wypróbowaną i przetestowaną zasadą jest zezwolenie na co najmniej 65535 FD na proces, pod warunkiem, że pamięć RAM i obciążenie obsługują to i masz Obciążenie wiem. Jednocześnie upewniam się, że suma aktywnych pracowników, procesów potomnych i połączeń sieciowych w realistycznych scenariuszach wysokiego obciążenia w ramach globalnego systemu jest wystarczająca. Wartości ramki pozostaje. Przejrzysty wgląd w te liczby zapobiega wzrostom bez planu i utrzymuje integralność systemu pod kontrolą. Ciśnienie.
| Polecenie/ścieżka | Funkcja | Na co należy zwrócić uwagę |
|---|---|---|
ulimit -n / -Hn | Miękki/twardy limit bieżącej sesji | Twardy limit ustawia górny limit dla Podnoszenie |
/proc//limits | Limity na proces i otwarte pliki | Krytyczne dla demonów takich jak nginx/php-fpm |
/proc/sys/fs/file-max | Globalne maksimum wszystkich FD | Należy dodać do kwoty procesu i RAM dopasowanie |
/proc/sys/fs/plik-nr | Otwarte, bezpłatne, maksymalnie liczne | Trend w testach obciążeniowych i Szczyty czek |
lsof | Pokazuje otwarte uchwyty | Na pracownika/wątek zużyty Pomiar FD |
Dostosuj limity FD tymczasowo i na stałe
Do szybkich testów używam ulimit, aby ustawić wyższą wartość Miękki limit, zanim zdefiniuję stałe reguły i zrestartuję usługi. Następnie piszę odpowiednie wpisy w pliku /etc/security/limits.conf, dodaję nadpisania systemd i weryfikuję zmianę za pomocą ukierunkowanego polecenia Test obciążenia. Ważne: Użytkownik usługi musi być poprawny, w przeciwnym razie zwiększenie nie będzie miało żadnego skutku. Problem pojawia się ponownie pod obciążeniem. Dostosowuję również globalny limit, aby wiele procesów roboczych nie przekraczało razem limitu systemowego. gromadzić się pozostać. Tylko wtedy, gdy strona procesowa i systemowa pasują do siebie, konfiguracja może wytrzymać rzeczywiste scenariusze wysokiego obciążenia i uniknąć EMFILE.
# Tymczasowo (do wylogowania/ponownego uruchomienia)
ulimit -n 65535
# W całym systemie (do ponownego uruchomienia lub na stałe przez sysctl.conf)
sudo sysctl -w fs.file-max=2097152
# Na stałe (przykład dla użytkowników serwera WWW)
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
Usługi systemd # (np. 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
Prawidłowe ustawienie parametrów jądra
Sprawdzam fs.file-max i fs.nr_open razem, aby jądro miało wystarczająco dużo Bufor dla obciążeń szczytowych. Jeśli zwiększysz tylko limit na proces, w przeciwnym razie przekroczysz limit globalny i przesuniesz limit na proces. wąskie gardło na poziomie systemu. Rozsądne jest utrzymywanie luki między typowym obciążeniem szczytowym a wartościami globalnymi, tak aby istniały rezerwy na okna konserwacyjne lub gwałtowny ruch i Szczyty ryzyka mogą być tłumione. Szczegółowe informacje na temat dostrajania całego systemu można znaleźć w artykule na temat Dostrajanie jądra, którego lubię używać jako narzędzia do dogłębnego dostosowywania systemu operacyjnego. Lista kontrolna używać. Po zmianach ponownie ładuję parametry, ponownie sprawdzam plik-nr i weryfikuję, czy wszystkie usługi zostały ponownie uruchomione z nowymi limitami, a wartość Wartości przejąć kontrolę.
# Stałe parametry jądra
sudo bash -c 'cat >> /etc/sysctl.d/99-ulimits.conf <<EOF
fs.file-max = 2097152
fs.nr_open = 2097152
EOF
sudo sysctl --system
# Control
cat /proc/sys/fs/file-max
cat /proc/sys/fs/nr_open || sysctl fs.nr_open
Planowanie wydajności i architektura
Realistyczne planowanie wydajności zaczyna się od pomiarów Profile na żądanie: Ile FD potrzebują łącznie serwer WWW, warstwa aplikacji, baza danych i pamięć podręczna? Na podstawie tych danych obliczam całkowitą liczbę jednocześnie otwartych uchwytów na hosta i planuję bufory dla Szczyty na. Kalkuluj zachowawczo: rotacja dzienników, dodatkowe gniazda, pliki tymczasowe i zadania tworzenia kopii zapasowych zwiększają zapotrzebowanie i pochłaniają zasoby. Rezerwy. Zwracam uwagę na fakt, że poziome skalowanie za pomocą load balancerów zmniejsza obciążenie FD na węzeł, co zmniejsza odporność na awarie i okna zmian. Uproszczony. Tylko dzięki jasnym wartościom limitów dla każdej warstwy można ustawić określone limity i rozsądnie przydzielać przepustowość między usługami. podział.
Dostrajanie serwera WWW i bazy danych
W przypadku serwerów internetowych trzymam się zasady Wątki*4 mniejszy niż limit FD, tak aby istniały rezerwy na połączenia upstream, pliki tymczasowe i dzienniki. W przypadku nginx i Apache w obliczeniach uwzględniam połączenia keep-alive, otwarty dostęp i dzienniki błędów, a także gniazda upstream, dzięki czemu mogę się zabezpieczyć. Bufor. Bazy danych, takie jak MariaDB lub PostgreSQL, otwierają wiele gniazd przed aplikacjami, replikacją i monitorowaniem; ich limity muszą odpowiadać puli połączeń i szczytom ruchu. dopasowanie. Pamięci podręczne (Redis, Memcached) zmniejszają obciążenie bazy danych, ale niekoniecznie zmniejszają liczbę FD, jeśli wielu klientów żąda i łączy się równolegle. trzymać. Dlatego planuję skoordynowane limity wzdłuż łańcucha: frontend, upstream, DB, cache i kolejki wiadomości, tak aby nigdzie nie został przekroczony pierwszy twardy limit. Bariera przejmuje kontrolę.
# Przykład: nginx systemd limit i worker
LimitNOFILE=65536 # systemd
worker_processes auto;
worker_connections 4096; # 4096 * worker <= 65536
# Przykład: PostgreSQL
max_connections = 1000 # FD requirement ~ 1-2 per connection + files/logs
Wydajność stosów WordPress i PHP
Instancje WordPress z wieloma wtyczkami otwierają więcej plików, więcej połączeń sieciowych i więcej Dzienniki. Zmniejszam liczbę niepotrzebnych załączników za pomocą OPCache, zmniejszam obciążenie baz danych za pomocą Redis Object Cache i zlecam statyczne zasoby za pośrednictwem CDN, aby zminimalizować dostęp do plików i Połączenia aby zmniejszyć obciążenie. Jednocześnie specjalnie zwiększyłem limity dla php-fpm i serwera WWW, aby szczyty podczas cronjobs, crawlerów lub kas sklepowych nie stanowiły problemu. Przerwania generować. Czysta obsługa dzienników błędów i rotacji zapobiega sytuacji, w której zapisy dzienników nie napotykają na nic i nie otwierają nowych plików może. W ten sposób łączę redukcję zużycia i zwiększanie limitów, dzięki czemu stos pozostaje przystępny cenowo pod obciążeniem i Przepustowość posiada.
Kontenery i środowiska chmurowe
W Dockerze i Kubernetes procesy często dziedziczą limity FD z Węzły, Dlatego najpierw sprawdzam parametry hosta, a następnie definicje usług. Analogiczne zasady dotyczą systemd-nspawn lub containerd, ale implementacja odbywa się w plikach jednostkowych, PodSpecs lub konfiguracjach demonów za pomocą Zastąpienia. Dokumentuję limity jako kod (IaC) i utrzymuję ich spójność za pomocą playbooków, aby nowe węzły miały identyczne limity. Granice zabrać ze sobą. W Kubernetes sprawdzam również SecurityContexts i ustawiam wymagane możliwości, aby po stronie systemu Ograniczenia zaczynają obowiązywać. Ostatecznie pomiar w klastrze pozostaje ważny, ponieważ planowanie, automatyczne skalowanie i aktualizacje kroczące zmieniają dystrybucję otwartych uchwytów i testują Bufor.
# Przykład: systemd w kontenerze hostów
cat <<'EOF' | sudo tee /etc/systemd/system/myapp.service.d/limits.conf
[Service]
LimitNOFILE=65536
EOF
# Kubernetes: podSpec (obraz kontenera musi przestrzegać ulimit)
# Uwaga: ustawienia rlimit muszą być ustawione w różny sposób w zależności od systemu operacyjnego.
Bezpieczeństwo, ograniczanie prędkości i monitorowanie
Wysokie limity zapewniają przestrzeń do działania, ale zwiększają powierzchnię ataku dla Powodzie, Dlatego ograniczam żądania na brzegu sieci za pomocą ograniczania szybkości i ustawiam limity połączeń na serwerze WWW. Zapora aplikacji internetowej i rozsądne limity czasu zapobiegają trwałemu blokowaniu FD przez bezczynne połączenia. wiązanie. W przypadku powtarzających się testów używam powtarzalnych profili obciążenia i korzystam z Prometheus, Netdata lub Nagios, aby konsekwentnie monitorować metryki związane z otwartymi plikami i Gniazda. W zależności od obciążenia pracą, stopniowo poprawiam wartości graniczne zamiast gwałtownie je zwiększać, aby efekty pozostały wymierne i aby można było je zmierzyć. Demontaż jest łatwe. Jeśli chcesz zagłębić się w wartości graniczne po stronie połączenia, ten kompaktowy artykuł na stronie Limity połączeń, którego używam na granicach sieci jako Przewodnik służy.
Rozwiązywanie problemów za pomocą EMFILE: procedura strukturalna
Zaczynam od spojrzenia na Dziennik i w dziennikach usług, aby zawęzić czas i częstotliwość błędów. Następnie używam lsof do sprawdzenia najwyższego zużycia na proces i zidentyfikowania wzorców, takich jak wycieki, rosnąca liczba logów lub nietypowe błędy. Gniazdo-typów. Następnie porównuję ustalone limity z rzeczywistymi wartościami szczytowymi i najpierw tymczasowo je zwiększam, aby móc zweryfikować przyczynę i skutek w kontrolowanym teście i na tej podstawie określić Ustawienia stałe pochodne. W przypadku wykrycia wycieku, łatam lub wycofuję komponent, ponieważ wyższe limity tylko ukrywają objawy i odsuwają problem w czasie. Problem. Na koniec dokumentuję poprawkę, ustawiam alarmy i planuję nowy test obciążeniowy, aby rozwiązanie było prawidłowe i mogło być ponownie użyte. Zaufanie tworzy.
Realistyczna ocena kosztów zasobów związanych z wysokimi limitami FD
Każdy otwarty plik lub gniazdo kosztuje pamięć jądra. Dlatego należy zaplanować Ślad pamięci RAM W zależności od wersji jądra i architektury, wymagane jest od kilkuset bajtów do kilku kilobajtów na FD (w tym struktury VFS/socket). Przy setkach tysięcy FD, to się sumuje. Wymiaruję globalny file-max w taki sposób, że w najgorszym przypadku wystarczająca ilość pamięci podręcznej stron i pamięci roboczej pozostaje wolna dla aplikacji. Prosta kontrola jest przeprowadzana przez vmstat, free i trend otwartych FD przez file-nr podczas Testy obciążenia szczytowego. Celem jest taka konfiguracja, która nie będzie powodować nadmiernego odzyskiwania lub aktywności OOM.
Pułapki ścieżek dystrybucji i uruchamiania (PAM, systemd, Cron)
To, czy limity mają zastosowanie, zależy od Ścieżka początkowa z. Logowania oparte na PAM (ssh, su, login) odczytują /etc/security/limits.conf, podczas gdy usługi systemd używają głównie swoich parametrów jednostkowych (LimitNOFILE) i nie obowiązkowy PAM. Cron/at mogą mieć własne konteksty. Dlatego sprawdzam poprawność dla każdej usługi:
- Jak rozpoczyna się proces? (status systemctl, ps -ef)
- Które limity naprawdę widzi? (cat /proc//limits)
- Czy PAM działa? (Sprawdź moduły PAM w /etc/pam.d/*)
- Czy istnieją domyślne ustawienia systemowe? (systemd: DefaultLimitNOFILE w system.conf)
W ten sposób zapobiegam otrzymywaniu przez aplikacje różnych limitów FD w zależności od ścieżki startowej i od niespójny reagować.
Praktyczne wymiarowanie z przykładami obliczeń
Liczę na Pracownicy i profile połączeń od tyłu do wymaganej pojemności FD:
- nginx z 8 pracownikami po 4000 połączeń każdy: ~32000 połączeń. Z reguły nginx rezerwuje 1 FD na aktywne połączenie; plus upstream (keep-alive) i logi dodają ~10-20% bufora. Wynik: ~38000 FD dla samego nginx.
- php-fpm ze 150 dziećmi, zwykle 20-40 FD na dziecko (w tym gniazda, dzienniki): konserwatywnie 6000 FD.
- Klienci Redis/DB: 200 równoległych połączeń, 1-2 FD każdy: ~400 FD.
Łącznie na hosta: ~44 tys. FD. Ustawiłem LimitNOFILE dla nginx do 65536, analog php-fpm i samolot Globalny fs.file-max, aby zmieściły się wszystkie usługi plus rezerwa (x1.5-x2). W przypadku kilku mocno wykorzystywanych instancji na host, skaluj globalnie do 1-2 milionów FD, jeśli pamięć RAM i ścieżki I/O są wystarczające. poddanie się.
Głębsza diagnostyka: znajdowanie wycieków i gorących punktów
Jeśli FD stale rosną, używam ukierunkowanych narzędzi, aby znaleźć przyczynę:
# Otwarte uchwyty pogrupowane według typu
lsof -p | awk '{print $5}' | sort | uniq -c | sort -nr
# Tylko gniazda jednego procesu
lsof -Pan -p -i
# Które pliki rosną (logi, temp)
lsof +L1 # Usunięte, ale wciąż otwarte pliki
ls -l /proc//fd
# Widok wywołań systemowych: kto ciągle otwiera pliki?
strace -f -p -e trace=open,openat,close,socket,accept,accept4 -s 0
Szczególnie zdradliwe są Usunięte dzienniki, które są nadal otwarte: Zajmują miejsce i FD, ale nie pojawiają się już w systemie plików. Ponowne uruchomienie lub jawne ponowne otwarcie (np. w przypadku nginx przez USR1) rozwiązuje ten problem. Nieprawidłowo skonfigurowani obserwatorzy/eksporterzy mogą również stale otwierać nowe gniazda - limity szybkości i pooling.
Wyraźne rozgraniczenie Inotify, epoll i EMFILE
Nie każdy limit zasobów jest nazywany limitem FD. W środowiskach programistycznych i CI kompilacje często kończą się niepowodzeniem z ENOSPC w odniesieniu do Inotify (limity obserwatora). Sprawdzam i ustawiam jako uzupełnienie:
Limity # Inotify (dla użytkowników i instancji)
sysctl fs.inotify.max_user_watches
sysctl fs.inotify.max_user_instances
# Przykład zwiększenia
sudo sysctl -w fs.inotify.max_user_watches=524288
sudo sysctl -w fs.inotify.max_user_instances=1024
Podczas gdy epoll działa wewnętrznie z FD, faktycznym wąskim gardłem z masywnymi Długowieczny-Połączenia często przekraczają sam limit FD. Dlatego koreluję dane pętli epoll/event (np. aktywne uchwyty) z zużyciem związanym z plikami i procesami.
Specjalizacje w zakresie języka i środowiska uruchomieniowego (Java, Node.js, Go, Python)
Systemy wykonawcze obsługują FD w różny sposób:
- Java/NettyWiele kanałów NOK na proces, frameworki logowania utrzymują otwarte appendery plików. Ustawiam duże limity i rotuję logi ze strategią ponownego otwierania zamiast zamykania/zastępowania.
- Node.jsEMFILE pojawia się szybko przy dużych obciążeniach systemu plików (np. watcher, build pipelines). Reguluję równoległe operacje fs, zwiększam limity i ustawiam strategie backoff/retry.
- Wejdź na stronęWysoka równoległość poprzez goroutines może otworzyć wiele gniazd. Ograniczam limity czasu wybierania i nagłówka odpowiedzi oraz sprawdzam, czy połączenia są prawidłowo zamykane (IdleConnTimeout).
- Python/uWSGI/GunicornModele Worker/thread zużywają FD na logi, gniazda i pliki tymczasowe; Harmonizuję liczbę pracowników, pule wątków i pliki tymczasowe. nofile-limity.
Wszystkie one mają jedną wspólną cechę: Bez skoordynowanej rotacji logów i niezawodnego Zarządzanie połączeniami FD rosną stopniowo.
Kontenery w konkretnym ujęciu: ustawienia Docker i Kubernetes
Aby upewnić się, że pojemniki faktycznie widzą pożądane limity, ustawiam je konsekwentnie wzdłuż łańcucha:
- Docker Runuruchomić z -ulimit nofile=65535:65535 lub ustawić domyślnie przez demona (np. limity domyślne).
- ObrazySkrypty startowe nie powinny resetować restrykcyjnego limitu ulimit.
- KubernetesW zależności od środowiska uruchomieniowego (containerd, cri-o), ustawienia rlimitów działają inaczej. Testuję w pod poprzez cat /proc/self/limits i dostosowuję domyślne ustawienia węzła/runtime, jeśli specyfika pod nie jest wystarczająca.
Szczególnie w środowiskach z wieloma dzierżawcami zabezpieczam Całkowita kwota przeciwko fs.file-max i odizolować efekty hałaśliwego sąsiada za pomocą oddzielnych zestawów węzłów lub budżetów podów, tak aby poszczególne wdrożenia nie zużywały zarezerwowanych FD hosta.
Wyjaśnienie wskaźników monitorowania i alarmów
Oprócz file-nr i file-max, monitoruję również FD dla poszczególnych procesów i linie trendu:
- W całym systemiePrzydzielone vs. maksymalne, tempo zmian, stosunek szczyt/maksimum.
- Na procesFD na pracownika/wątek, procesy Top-N, anomalie w nocy (wsad/praca).
- JakościoweStopy błędów HTTP, długości kolejek, błędy akceptacji/handshake zsynchronizowane z trendem FD.
Ustawiłem alerty wielopoziomowyOstrzeżenie przy 70-80%, krytyczne od 90% skonfigurowanego limitu, plus Wykrywanie wycieków poprzez rosnące 7-dniowe trendy. Pozwala mi to zareagować w odpowiednim czasie, zanim zaczną obowiązywać twarde bariery.
Instrukcja postępowania w sytuacjach awaryjnych
Kiedy EMFILE uderza ostro, działam w jasnych krokach:
- Zidentyfikuj głównych konsumentów (lsof, /proc//fd, wpisy do dziennika).
- Tymczasowo zwiększ miękki limit (ulimit w sesji lub nadpisanie LimitNOFILE) i uruchom ponownie usługę.
- Jeśli przyczyną są dzienniki: Zatrzymaj rotację, wyzwól ponowne otwarcie, zmniejsz poziom logów.
- Natężenie ruchu na brzegu sieci przepustnica (Zwiększenie lub zaostrzenie limitów stawek/limitów połączeń - w zależności od sytuacji).
- Naprawa przyczyn źródłowych (wyciek, zbyt agresywna równoległość, brak timeoutów) i stałe limity dokręcić.
Ważne są działania następcze: dokumentacja, powtarzane testy obciążeniowe i alarmy ostrzenia, aby ten sam łańcuch został rozpoznany na wczesnym etapie.
Krótkie podsumowanie
Dzięki zwiększonym limitom FD, czysto ustawionym parametrom jądra i przetestowanej architekturze mogę świadczyć usługi moim klientom. Pole manewru pod dużym obciążeniem. Najpierw mierzę, następnie ustawiam odpowiednie wartości graniczne, weryfikuję za pomocą testów obciążeniowych i zabezpieczam wynik za pomocą ograniczania szybkości, monitorowania i czyszczenia Zasady.


