VPN-релей перестає приймати SSH: ліміти файлових дескрипторів
Трафік через тунель триває, а socat-релей за ним відмовляє в нових сеансах. Простежте шлях, потім прочитайте успадкований ліміт на живому PID.
Рукостискання WireGuard усе ще завершується, peer усе ще показує недавній endpoint, і все ж новий сеанс SSH через релей за ним висить без банера. Ця комбінація веде від тунелю до процесу, який приймає socket. Релей на кшталт socat стоїть на шляху застосунку зі своїм бюджетом дескрипторів, своїми дочірніми процесами та своїми успадкованими лімітами. Прогулянка нижче починається біля клієнта і зупиняється на першому компоненті, який не може відкрити ще один socket.
Простежте шлях, перш ніж змінювати число
Простежте один невдалий запит замість міркувань про тунель у цілому. Клієнт пише в тунель, демон VPN розшифровує й маршрутизує, а релей приймає з іншого боку. Кожен крок споживає дескриптори, і той, який зазвичай закінчується, — останній.
Почніть із запиту, який ви можете відтворити, і виміряйте його час. Якщо рукостискання TCP завершується, але банер застосунку не надходить, релей узяв socket і потім застряг у дочірньому процесі або на своїй висхідній нозі. Якщо саме рукостискання ніколи не завершується, причина — маршрутизація, брандмауер або стан слухача, а не стеля дескрипторів. Запишіть, яку з двох форм ви спостерігали, бо вони вказують на різні процеси.
Порахуйте й стрибки, які дублюють роботу. Розгалужуваний слухач передає кожен прийнятий socket дочірньому процесу, який зберігає свою копію, тож реальна сума — властивість усього дерева, а не лише батька.
Прочитайте ліміт, який успадкував релей
Єдиний ліміт, який має значення, належить робочому процесу, і його задало те, що запустило цей процес. Введення ulimit -n у оболонці описує оболонку. Запитайте менеджер служб, що він застосував, потім підтвердьте на PID.
systemctl show -p MainPID -p LimitNOFILE vpn-relay.service
cat /proc/$(systemctl show -p MainPID --value vpn-relay.service)/limits
Файл limits друкує м'яку та жорстку стелі так, як їх бачить процес. Низьке м'яке значення під щедрим жорстким означає, що демону дозволено підняти власну стелю, і деякі роблять це під час запуску; рівні низькі значення означають, що джерелом є файл unit.
Drop-in завантажуються в лексикографічному порядку, і пізніші файли перемагають, тож systemctl cat vpn-relay.service — авторитетний вид того, що застосовується. Редагування файлу, який менеджер ніколи не читає, — найпоширеніша причина того, що підняте число не дає ефекту.
Відокремте стійку паралельність від утримуваного стану
Два процеси можуть упиратися в одну стелю з незв'язаних причин, і засоби різняться. Попит, що відстежує корисні паралельні сеанси, — питання ємності. Зростання, яке триває після завершення роботи, — це витік або набір сеансів, які ніхто не закрив.
Виміряйте в спокої, на звичайному піку і ще раз через кілька хвилин після зупинки навантаження. Підрахунок відкритих записів за допомогою ls /proc/PID/fd | wc -l проти м'якого ліміту показує розрив, а число на один-два нижче стелі — це жорстка зупинка, а не повільний шлях.
Коли число не хоче падати, дивіться на стани socket, а не на суми. Дескриптори, що сидять у CLOSE_WAIT, означають, що peer закрив, а ваш бік — ніколи, і це дефект життєвого циклу застосунку, який більший ліміт лише відкладає. Обмежте й модель дочірніх процесів: розгалужуваний релей без межі паралельних дітей вичерпує дескриптори, слоти процесів і пам'ять разом.
Перевірте нове значення на живому процесі
Після редагування unit перезавантажте менеджер і перезапустіть службу, бо саме перезавантаження ніколи не замінює ліміти, які робочий процес уже успадкував. Перевірте на процесі, який справді обслуговує трафік.
systemctl daemon-reload
systemctl restart vpn-relay.service
awk '/Max open files/ {print}' /proc/$(systemctl show -p MainPID --value vpn-relay.service)/limits
ss -tnp state established '( sport = :2222 )' | wc -l
Рядок awk повертає нову пару; якщо він усе ще показує стару, відредагований вами drop-in — не той, що завантажується. Число ss — ваша перевірка навантаження, тож відкрийте очікувану кількість сеансів і спостерігайте за зростанням. Число, яке продовжує зростати після закриття цих сеансів, означає, що ліміт ніколи не був усією проблемою.
З кожним великим підвищенням пов'язана одна засторога. Застосунки, що опитують через select(), не можуть стежити за дескрипторами вище FD_SETSIZE, що становить 1024 у типових збірках, тож стеля, піднята вище, може давати відмови, які виглядають незв'язаними. Довідка з виконання systemd несе те саме попередження для служб, які вона запускає.
Тримайте перезапуск далеко від доступності тунелю
Перезапуск релею скидає його активні сеанси, і це окрема подія від падіння VPN. Упорядкуйте зміну так, щоб тунель залишався піднятим, поки релей проходить цикл, і попередьте кожного, чий довгий сеанс його перетинає.
Відкат — це попередній файл unit плюс ще один перезапуск, і цей файл залишається на місці, поки нове значення не переживе робочий день. Потім замкніть цикл запитом, який спочатку не вдався: один новий сеанс SSH через релей, одна передача, достатньо довга, щоб мати значення, і число дескрипторів, яке повертається до рівня спокою.