Помилка з’являється у найгірший момент: при деплої, бекапах, CI-завданнях, інцидентних дзвінках, коли всі наполягають, що «нічого не міняли».
Ваш процес намагається прочитати файл, а ядро відповідає з плечима: Stale file handle.
На Ubuntu 24.04 у цьому немає нічого «нового» — але комбінації, що її викликають, продовжують еволюціонувати: контейнерні бінд-монти шляхів, systemd automount,
агресивні зміни експорту, відмови NAS, а також «оптимізації» розкладок серед зручного робочого дня. Тож ставимо це як баг у продакшні:
зрозуміти механізм, ізолювати режим відмови й усунути його за допомогою нудних, відтворюваних практик.
Що фактично означає «Stale file handle»
У Linux «Stale file handle» відповідає ESTALE. У термінах NFS це означає, що клієнт каже:
«Я тримаю посилання на файл/каталог, яке сервер більше не розпізнає».
Це посилання — file handle — непрозорі байти, які повертає NFS-сервер і які унікально ідентифікують щось на сервері, схоже на inode.
Клієнт кешує ці хендли, бо запитувати сервер для повторного резольвінгу шляху для кожної операції — це катастрофа для продуктивності.
Коли сервер пізніше не може розпізнати хендл, ви отримуєте ESTALE.
Важливо: це не помилка прав доступу і не просто «мережеві глюки». Це невідповідність між тим, що клієнт думає,
що існує, і тим, що сервер може відобразити назад на об’єкт. Іноді це викликано реальним видаленням об’єкта. Частіше — серверною зміною ідентичності, коли ви цього не очікували.
Під час інциденту повідомлення ядра дуже відверте: сервер каже «не чули про цей хендл», і ваш процес не може продовжити роботу.
Якщо ваше навантаження — збірка, рантайм контейнера або база даних, яка очікує консистентної поведінки файлової системи, ви побачите помилки,
що виглядають випадковими, поки ви не скорелюєте їх із подіями топології NFS.
Чому це відбувається (реальні причини)
Файлові хендли — це ідентичності, а не шляхи
NFS переважно розглядає файли як об’єкти. Шляхи резольвляться в file handles, а операції виконуються за хендлами.
Ось чому файл можна перейменувати, поки він відкритий, і все ще читати локально — Linux відстежує inode. З NFS клієнт відстежує ідентичність, видану сервером.
Основний тригер: сервер не може більше відобразити хендл
Це трапляється коли:
- Підлягаючий об’єкт файлової системи реально зник (видалення, відтворення файлової системи, відкат снапшота тощо).
- Сервер змінив уявлення про ідентичність (експорт переміщено, fsid змінився, файлову систему перемонтували по-іншому, відбувся failover на інший бекенд).
- Кешований хендл клієнта відноситься до іншої файлової системи, ніж та, яку сервер тепер експонує за цим шляхом (класична помилка при зміні експорту).
Поширені серверні події, що інвалідизують хендли
- Переконфігурація експорту: зміни в /etc/exports, переміщення експортів, перехід від експорту каталогу до експорту батька тощо.
- Заміна файлової системи: форматування, відновлення з бекапу, відтворення датасету, створення дерева каталогів наново.
- Відкат снапшота на сервері: шлях існує, але ідентичності об’єктів були «відмотані» назад.
- Failover на інший вузол: кластери HA, де новий вузол обслуговує «той самий шлях», але не ті самі ID об’єктів.
- Перетин монтажних точок у експорті: експорт шляху, що містить інші mounт-пойнти, і подальші зміни цих mount-ів.
Клієнтські фактори, що сприяють (зазвичай не корінь, але посилюють проблему)
- Довгоживучі процеси, які тримають дескриптори каталогів і вважають їх валідними вічно (CI-ра-нери, шипери логів, language servers).
- Контейнери, що бінд-монтують NFS-шляхи; контейнер живе, поки під ним змінюється ідентичність NFS.
- Автомаунтери, які приховують churn монтів до тих пір, поки фонове завдання не натрапить на stale FD.
- Агресивні припущення кешування (attribute caching, lookup caching), які роблять поведінку «липкою».
NFSv3 vs NFSv4: міф про «становість»
NFSv4 є stateful у способах, у яких NFSv3 не є (локи, делегації, сесії), але file handles все ще можуть застаріти.
Протокол може координувати багато речей, але він не може відновити ідентичність, яку сервер більше не може відобразити на об’єкт.
Один вислів, який операційні команди вчать з болем: «Усе ламається, весь час»
— Werner Vogels.
Це різко, але не цинічно. Проектуйте з урахуванням цього.
Дві жарти, бо люди цього потребують
Жарт №1: Файлові хендли NFS схожі на корпоративні бейджі — як тільки безпека скасує ваш, ви все ще знаєте коридор, але не увійдете.
Жарт №2: Якщо ви «виправили» stale file handle перезавантаженням клієнтів, вітаю: ви винайшли найдорожчу стратегію інвалідації кешу.
Цікаві факти й історичний контекст (коротко, конкретно)
- NFS виник у Sun Microsystems у 1980-х; основна ідея була «мережна прозорість» для Unix-файлів.
- NFSv2 використовував 32-бітні розміри файлів; великі файли підштовхнули еволюцію до NFSv3 і далі.
- NFSv3 є переважно безстанним на сервері, що спростило відновлення, але поклало більше зусиль на клієнтів і file handles.
- NFSv4 ввів псевдо-root і сильнішу модель простору імен; експорти поводяться інакше, ніж у v3 «просто експортуй каталог».
- ESTALE існує ще до NFS як Unix-помилка для застарілих віддалених посилань, але NFS зробив її загальновідомою в операх.
- File handles навмисно непрозорі, щоб сервер міг змінювати внутрішні відображення inode без повідомлення клієнтів — поки сервер не зможе відобразити їх назад.
- Деякі NAS-вендори кодують ID файлової системи у хендли; якщо ці ID змінюються під час failover, хендли помирають, навіть якщо шляхи виглядають однаково.
- Subtree checking (функція сервера) історично викликала дивні випадки з хендлами при перейменуваннях; багато адміністраторів вимикають це для передбачуваності.
- Клієнти Linux агресивно кешують dentries; це добре для продуктивності і жахливо для дебагу, коли під ними змінюються ідентичності.
Швидкий план діагностики (перші кроки)
Ви на чергуванні. На філософський семінар про розподілені файлові системи часу немає. Ось найкоротший шлях до істини.
Перше: підтвердьте, що це ESTALE, і визначте масштаб
- Це на одному хості чи на багатьох?
- Один монтувальний пункт чи всі NFS-монти?
- Один підкаталог чи випадкові файли по всій системі?
Друге: з’ясуйте, чи змінилася серверна ідентичність
- Чи змінювали експорти?
- Чи було перемонтовано, замінено, відмовлено або відкотено файлову систему?
- Чи хтось «перебудував шарінг», лишивши той самий шлях?
Третє: вирішіть стратегію відновлення за ризиками навантаження
- Якщо навантаження — читально-домінуюче: часто достатньо ремонту.
- Якщо це інтенсивні записи або є локи (БД, кеші збірок): зупиніть додаток акуратно, потім ремонтуйте і перезапустіть. Уникайте напівзаходів.
- Якщо це багато клієнтів одночасно: ставте до події сервера/експорту, а не «флікання клієнта». Спочатку виправляйте серверну ідентичність.
Далі: запобігання повторенню
- Припиніть змінювати експорти на ходу під час робочого часу.
- Забезпечте стабільні ідентичності файлових систем (стратегія fsid, стабільні бекенди).
- Використовуйте systemd automount обережно, а не як чарівний килимок над churn-ом.
Практичні завдання: команди, виводи, рішення (12+)
Це реальні перевірки, які ви можете виконати на клієнтах і серверах Ubuntu 24.04. Кожне завдання містить: команду, типовий вивід, що це означає
і яке рішення прийняти.
Завдання 1: Переконайтеся, що це дійсно ESTALE (клієнт)
cr0x@server:~$ dmesg -T | tail -n 20
[Mon Dec 29 11:02:14 2025] NFS: stale file handle
[Mon Dec 29 11:02:14 2025] NFS: v4 server nfs01 returned a stale file handle
Значення: NFS-клієнт ядра отримав ESTALE від сервера. Це не виняток на рівні додатка; це шар файлової системи.
Рішення: Розглядайте це як проблему консистентності/ідентичності. Почніть перевіряти події на сервері/експорті, а не лише затримки мережі.
Завдання 2: Визначте, який монтувальний пункт постраждав (клієнт)
cr0x@server:~$ findmnt -t nfs,nfs4 -o TARGET,SOURCE,FSTYPE,OPTIONS
TARGET SOURCE FSTYPE OPTIONS
/mnt/build nfs01:/exports/build nfs4 rw,relatime,vers=4.1,hard,timeo=600,retrans=2
/mnt/archive nfs02:/exports/archive nfs4 ro,relatime,vers=4.2,hard,timeo=600,retrans=2
Значення: Показує точний server:path і опції. Рядок джерела важливий при кореляції зі змінами експорту.
Рішення: Якщо лише один монтувальний пункт уражений — фокусуйтеся на бекенді цього експорту. Якщо декілька — підозрюйте подію на рівні сервера або failover.
Завдання 3: Відтворіть і зафіксуйте шлях, що падає (клієнт)
cr0x@server:~$ ls -la /mnt/build/workdir
ls: cannot access '/mnt/build/workdir/.': Stale file handle
total 0
Значення: Хендл каталогу застарів. Часто вказує на перейменування/переміщення/ремап експорту або заміну файлової системи під цим каталогом.
Рішення: Не перезапускайте додатки навмання. Зберіть докази: який каталог, який монтувальний пункт і чи працюють інші шляхи.
Завдання 4: Перевірте доступність і відповідь NFS-сервера (клієнт)
cr0x@server:~$ rpcinfo -t nfs01 nfs 4
program 100003 version 4 ready and waiting
Значення: Базова RPC-доступність. Це не доводить, що ваш експорт у порядку, але виключає «сервер упав».
Рішення: Якщо це падає — розглядайте як проблему з підключенням/фаєрволом/RPC-сервісом. ESTALE може бути вторинним шумом.
Завдання 5: Перелічіть експорти з точки зору сервера (клієнт)
cr0x@server:~$ showmount -e nfs01
Export list for nfs01:
/exports/build 10.20.0.0/16
/exports/shared 10.20.0.0/16
Значення: Підтверджує, що сервер стверджує, що експортує (особливо корисно для NFSv3; все ще корисно для саніті-чеків).
Рішення: Якщо експорт зник або змінився — у вас явна підозра: клієнт монтується за старою припущенням.
Завдання 6: Підтвердіть версію NFS і параметри (клієнт)
cr0x@server:~$ nfsstat -m
/mnt/build from nfs01:/exports/build
Flags: rw,relatime,vers=4.1,rsize=1048576,wsize=1048576,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=10.20.3.41,local_lock=none
Значення: Показує погоджені параметри монтирования. Це допомагає помітити «soft» монти, дивні таймаути або застарілі версії.
Рішення: Якщо ви бачите soft для критичних даних — плануйте зміну. Soft-mounts можуть перетворювати транзієнтні проблеми на часткові записи чи пошкодження даних.
Завдання 7: Визначте, чи проблема обмежена одним піддеревом (клієнт)
cr0x@server:~$ (cd /mnt/build && ls -la . && ls -la ./workdir) 2>&1 | sed -n '1,6p'
total 8
drwxr-xr-x 4 root root 4096 Dec 29 10:58 .
drwxr-xr-x 3 root root 4096 Dec 29 10:58 ..
ls: cannot access './workdir': Stale file handle
Значення: Корінь монтованого шляху в порядку; один підкаталог має застарілий хендл. Часто викликано перейменуванням, відкатом снапшота або заміною цього піддерева.
Рішення: Ескалюйте до власника сервера/стореджу: «Ідентичність цього каталогу змінилася.» Ремонт через remount може допомогти; але також шукайте серверну подію.
Завдання 8: Знайдіть процеси, що тримають FD на застарілому шляху (клієнт)
cr0x@server:~$ sudo lsof +D /mnt/build/workdir 2>/dev/null | head
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
python3 4112 ci cwd DIR 0,1234 0 862 /mnt/build/workdir (stale)
make 4188 ci cwd DIR 0,1234 0 862 /mnt/build/workdir (stale)
Значення: Ці процеси мають поточний робочий каталог або відкритий FD, що вказує на застарілий каталог.
Рішення: Для безпечного відновлення зупиніть ці процеси перед ремонтом. Інакше вони продовжуватимуть помилитись або гальмувати конвеєри.
Завдання 9: Спробуйте акуратний ремонт на клієнті (клієнт)
cr0x@server:~$ sudo umount /mnt/build
umount: /mnt/build: target is busy.
Значення: Щось тримає монтувальний пункт зайнятим (відкриті файли, cwd, bind-монти в контейнерах).
Рішення: Не тисніть примусово без розуміння. Знайдіть утримувачів (наступне завдання) і зупиніть їх, або використайте lazy unmount лише як тактичний крок.
Завдання 10: Знайдіть, хто тримає монтувальний пункт зайнятим (клієнт)
cr0x@server:~$ sudo fuser -vm /mnt/build
USER PID ACCESS COMMAND
/mnt/build: root kernel mount /mnt/build
ci 4112 ..c.. python3
ci 4188 ..c.. make
Значення: Показує процеси, що використовують монтувальний пункт. Прапорці ACCESS вказують, як саме вони його торкаються (cwd, відкритий файл тощо).
Рішення: Зупиніть/загробіть винуватців або координуйтеся з власниками навантажень. Якщо це спільний хост збірки, культурний дренаж кращий за несподіване вбивство процесів.
Завдання 11: Використайте lazy unmount, коли потрібно (клієнт)
cr0x@server:~$ sudo umount -l /mnt/build
Значення: Від’єднує монтування від простору імен; існуючі посилання залишаються до тих пір, поки процеси їх не звільнять.
Рішення: Використовуйте це тільки в режимі інциденту, коли потрібно екстрено відновити сервіс. Після цього перезапустіть уражені служби, щоб збросити stale FD.
Завдання 12: Перемонтуйте з явними опціями й протестуйте (клієнт)
cr0x@server:~$ sudo mount -t nfs4 -o vers=4.1,hard,timeo=600,retrans=2 nfs01:/exports/build /mnt/build
cr0x@server:~$ stat /mnt/build/workdir
File: /mnt/build/workdir
Size: 4096 Blocks: 8 IO Block: 1048576 directory
Device: 0,1234 Inode: 862 Links: 12
Значення: Якщо stat знову працює, відновлення на клієнті вдалося. Якщо помилка лишається — сервер все ще показує іншу ідентичність або експортує пошкоджено.
Рішення: Якщо ремонт виправив — заплануйте заходи з профілактики. Ремонт — це відновлення, а не лікування.
Завдання 13: Перевірте конфігурацію експорту і події перезавантаження (сервер)
cr0x@server:~$ sudo exportfs -v
/exports/build 10.20.0.0/16(rw,wdelay,root_squash,no_subtree_check,sec=sys,fsid=101)
/exports/shared 10.20.0.0/16(rw,wdelay,root_squash,no_subtree_check,sec=sys,fsid=102)
Значення: Показує ефективні опції експорту. Зверніть увагу на наявність fsid — стабільність важлива, особливо з NFSv4 і HA.
Рішення: Якщо fsid відсутній або змінився недавно — розгляньте фіксацію його значення. Якщо шляхи експорту змінилися — очікуйте stale handles, поки клієнти не перемонтуються.
Завдання 14: Перегляньте логи сервера на предмет перезапусків/реекспорту/подій ФС (сервер)
cr0x@server:~$ sudo journalctl -u nfs-server -u rpcbind -u nfs-idmapd --since "2 hours ago" | tail -n 25
Dec 29 10:41:08 nfs01 systemd[1]: Stopped NFS server and services.
Dec 29 10:41:08 nfs01 systemd[1]: Starting NFS server and services...
Dec 29 10:41:09 nfs01 exportfs[2143]: exporting 10.20.0.0/16:/exports/build
Dec 29 10:41:09 nfs01 systemd[1]: Started NFS server and services.
Значення: Підтверджує перезапуски сервісів і перезавантаження експорту. Самі перезапуски не завжди призводять до ESTALE, але корелюють із перемонтами бекенду і failover-діями.
Рішення: Якщо ви бачите перезапуски під час інциденту — шукайте, що їх викликало: технічне обслуговування, CM, оновлення пакетів, скрипти failover.
Завдання 15: Підтвердіть, що експортований шлях — це та ФС, яку ви очікуєте (сервер)
cr0x@server:~$ findmnt -T /exports/build -o TARGET,SOURCE,FSTYPE,OPTIONS
TARGET SOURCE FSTYPE OPTIONS
/exports/build /dev/sdb1 ext4 rw,relatime
Значення: Перевіряє, що під експортом знаходиться. Якщо джерело або датасет змінилися з вчора — хендли можуть застаріти, навіть якщо шлях лишився тим самим.
Рішення: Якщо бекенд ФС змінився — розглядайте подію як руйнівну. Повідомте власників клієнтів і заплануйте вікно для ремонту/перезапуску.
Завдання 16: Виявити підказки про відкат снапшота чи відтворення датасету (сервер)
cr0x@server:~$ sudo tune2fs -l /dev/sdb1 | sed -n '1,12p'
tune2fs 1.47.0 (5-Feb-2023)
Filesystem volume name: builddata
Filesystem UUID: 6f8f2b7f-7c3f-4b0e-9b8b-3a8e5f7e0c2a
Filesystem magic number: 0xEF53
Filesystem revision #: 1 (dynamic)
Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent 64bit
Значення: Зміни UUID — вагома підказка, що файлову систему пересоздавали. Відкат може не змінити UUID, але пересоздання зазвичай робить це.
Рішення: Якщо UUID змінився — припиніть сперечатися про «жодних змін». Щось замінили. Очікуйте stale handles, поки клієнти не перемонтуються і додатки не відкриють шляхи заново.
Завдання 17: Перевірте RPC-статистику клієнта на предмет шумної мережі (клієнт)
cr0x@server:~$ nfsstat -rc
Client rpc stats:
calls retrans authrefrsh
153209 18 153227
Значення: Висока кількість retrans може вказувати на втрату пакетів або затори. Це напряму не викликає ESTALE, але сповільнює відновлення і ускладнює симптоматику.
Рішення: Якщо retrans високі — у вас дві проблеми: проблема ідентичності і проблема транспорту. Спочатку виправте ідентичність, потім стабілізуйте мережу.
Завдання 18: Якщо задіяний systemd automount — перевірте стан unit-а (клієнт)
cr0x@server:~$ systemctl status mnt-build.automount --no-pager
● mnt-build.automount - Automount mnt-build
Loaded: loaded (/etc/systemd/system/mnt-build.automount; enabled; preset: enabled)
Active: active (waiting) since Mon 2025-12-29 10:12:10 UTC; 51min ago
Where: /mnt/build
Значення: Automount може відмонтувати при просте і перемонтувати пізніше. Це нормально — доки щось не тримає stale FD під час заміни монту.
Рішення: Якщо ви бачите часті цикли монтів — перегляньте, чи сумісне ваше навантаження. Довготривалі демони + automount — погане поєднання.
Поширені помилки: симптом → корінь → виправлення
«Тільки один каталог помилюється; решта шару в порядку»
Симптом: ls працює в корені монту, але конкретний підкаталог дає «Stale file handle».
Корінь: Це піддерево перейменовано, замінено, відкотжено снапшотом або є mountpoint-ом, що змінився під експортованим батьком.
Виправлення: Перемонтуйте клієнт, щоб почистити хендли. Якщо повторюється — припиніть експортувати шляхи, що містять нестабільні mountpoints; експортуйте стабільні межі ФС.
«Сталося одразу після того, як ми «почистили» /etc/exports»
Симптом: Багато клієнтів бачать ESTALE незабаром після зміни експорту.
Корінь: Зміни семантики експорту (батько vs дитина, перетин mount-ів, зміни fsid). Клієнти тримають хендли на об’єктах, що обслуговувалися за старим відображенням експорту.
Виправлення: Розглядайте зміни експорту як руйнівні. Координуйте вікно ремонту/перезапуску для клієнтів. Зафіксуйте значення fsid і зберігайте топологію експорту стабільною.
«Ребут сервера NFS виправив на якийсь час, але потім повернулося»
Симптом: Тимчасове полегшення, потім повторні stale handles.
Корінь: Backend failover або операції життєвого циклу сховища (відкат, перебудова, перемикання реплікації) змінюють ідентичність об’єктів повторно.
Виправлення: Виправте процес життєвого циклу: стабільні бекенди, консистентні ID файлових систем і контрольовані cutover-и з координацією клієнтів. Ребути — лише тимчасовий захід.
«Трапляється під час тестів failover»
Симптом: Подія HA викликає масштабний ESTALE.
Корінь: Failover-вузол подає той самий шлях експорту, але має іншу ідентичність бекенду або неконсистентне відображення fsid.
Виправлення: Проектуйте HA з урахуванням стабільної ідентичності: той самий бекенд із консистентними ID, або приймайте, що клієнти повинні перемонтуватись і додатки перезапуститись як частина runbook-у.
«Це проблема Docker/Kubernetes»
Симптом: Поди повідомляють про stale handles; ноди виглядають у порядку; storage команда вказує на Kubernetes.
Корінь: Контейнери тримають довгоживучі монти та дескриптори; сервер NFS змінив ідентичність. Kubernetes лише полегшує ситуацію, дозволяючи процесам жити довго й помічати проблему.
Виправлення: Не ставте NFS як безкінечно змінний бекенд. Якщо потрібно змінювати експорти/бекенди — роолійте поди/ноди, щоб освіжити хендли. Віддавайте перевагу стабільним PV і уникайте переміщення експортів.
«Ми використали ‘soft’ монти, щоб уникнути зависань, тепер маємо дивні збірки»
Симптом: Періодичні відмови, часткові результати і іноді stale handles під навантаженням.
Корінь: Soft mounts дозволяють операціям падати посередині; додаток не був написаний з урахуванням часткових I/O-операцій.
Виправлення: Для критичних даних використовуйте hard монти і налаштовуйте таймаути. Якщо потрібна немиттєва поведінка, реалізуйте її на рівні додатку (таймаути, повтори, локальна підготовка).
Три міні-історії з практики
Інцидент №1: хибне припущення («Шляхи — це ідентичності»)
Компанія вела монорепозиторій на фермі збірок під Ubuntu. Білд-воркери монтували /mnt/build з NFS-сервера.
В одну п’ятницю інженер зберігання переніс share на новий том. Вони залишили той самий шлях на сервері: /exports/build.
Припущення було просте й дуже людське: якщо шлях той самий — клієнти не помітять змін.
В понеділок CI почав падати так, ніби це поганий компілятор. Випадкові джоби вмирали при виклику stat() тимчасових директорій.
Деякі працювали, деякі ні. Повтори іноді вдавалися. Команди звинувачували одна одну: білд — планувальник — воркери — storage — Linux caching.
Підказкою було те, що проблеми були на довго працюючих воркерах. Свіжо перезавантажені воркери були в порядку. На уражених хостах
lsof показував старі cwd, що вказували на застарілі каталоги в workspace. Перемонтування усувало проблему миттєво.
Міграція сервера не «зламала NFS». Вона змінила ідентичності об’єктів за шляхом.
Виправлення не було героїчним: скоординована міграція share з вікном для оновлення клієнтів. Це означало контрольований дрен воркерів,
unmount/remount і повернення в кластер. Постмортем включив нудне правило: ставте бекенди NFS як версії API.
Якщо змінюєте мапінг ідентичності — клієнти мають бути перезавантажені.
Інцидент №2: оптимізація, що привела до відкату (експорт батька «щоб спростити»)
Інша організація мала кілька експортів: /exports/app1, /exports/app2, /exports/app3.
Хтось вирішив, що це «занадто багато монтів». Пропозиція: експортувати лише /exports і дати клієнтам доступ до підкаталогів.
Один монтувальний пункт замість кількох. Зміна впроваджувалась поступово, бо CM дозволяв «просто переключити».
За місяць з’явилися stale file handle тільки в одному додатку і тільки під час деплоїв. Це було бісить.
Процес деплою створював новий release-каталог, переключав symlink, а потім чистив старі релізи. На локальних дисках це стандартно працює.
На NFS це також працювало — поки ви не експортуєте батька, що містить інші mountpoints, і ви не переставляєте їх.
Прихований момент: /exports/app2 вже не був каталогом на тій самій ФС; він став окремим монтувальним пунктом.
«Єдиний експорт» став перетинати межі файлових систем. Під час обслуговування монтувальна точка, що обслуговувала app2, була розмонтована і перемонтована.
Клієнти, які кешували хендли у тому піддереві, почали отримувати ESTALE, тоді як інші додатки були здорові.
Відкат до окремих експортів виправив ситуацію. Не тому, що «більше монтів краще», а тому, що кожен експорт відображав стабільну межу файлової системи.
Оптимізація зменшила конфігураційну складність, але підвищила складність інцидентів. Таке часто не окупається.
Інцидент №3: нудна практика, що врятувала день (стабільні ID і скоординовані ремонти)
Фінтех-компанія використовувала NFS для спільних інструментів і артефактів збірки. У них була пара в HA і регулярні тести failover.
На початку вони вважали failover «шумним»: клієнти іноді викидали stale handles, і люди просто «перезавантажували щось».
Потім вони зайнялися серйозно і написали runbook, який робив стабільність ідентичності першочерговою вимогою.
Вони зафіксували fsid в експорті, тримали шляхи експорту прив’язаними до стабільних меж файлової системи і заборонили зміну топології експорту на місці.
Коли бекенди треба було перемістити, вони планували це як міграцію схеми: тикет, дрен клієнтів, скоординований ремонт.
Без героїки — лише дисципліна.
Під час апаратного інциденту прошивки сховища пара в HA відмовила несподівано. Деяким клієнтам все ще потрібен був ремонт,
але площа ураження була меншою: менше stale handles, швидше відновлення і менше «привидів» процесів з старими FD.
Runbook спрацював, бо він не залежав від везіння або тубільних знань.
Висновок: надійність — не секретна кнопка. Це набір обмежень, яких ви домовились не порушувати, навіть коли поспіх.
Як це зупинити: ефективні патерни запобігання
1) Тримайте експорти стабільними і нудними
Найбільший важіль: не змінюйте відображення ідентичності під шляхом експорту легковажно.
Якщо треба мігрувати дані — робіть це так, щоб зберегти ідентичність об’єктів (часто неможливо), або приймайте, що клієнти мають оновитися.
- Уникайте підміни файлових систем під тим самим шляхом експорту без клієнтського плану обслуговування.
- Уникайте експорту батьківського каталогу, що містить mountpoints, які можуть незалежно перемонтовуватися.
- Надавайте перевагу експорту кореня файлової системи бекенду (або стабільної межі датасета), а не випадкового каталогу.
2) Використовуйте NFSv4 із послідовною стратегією простору імен
Для NFSv4 розглядайте простір імен сервера як API. Зміни псевдо-root або переміщення експортів ламають клієнтів так, що це відчувається нелокально.
Тримайте простір імен стабільним. Якщо потрібен новий макет — створіть новий експорт і мігруйте клієнтів свідомо.
3) Фіксуйте fsid, де це доречно (сервер)
На Linux NFS-серверах явні значення fsid= в /etc/exports допомагають зберегти ідентичність експорту під час перезавантажень і подій HA
(залежно від архітектури). Це не чарівна пігулка, але запобігає випадковому перенумеруванню.
4) Не вирішуйте інженерні проблеми через «soft» монти
Для надійності hard монти зазвичай є стандартом, бо вони зберігають POSIX-подібні очікування: записи не провалюються посередині.
Якщо потрібні обмежені відмови — реалізуйте їх у додатку (таймаути, повтори, локальна підготовка), а не через «брехню» файлової системи.
5) Плануйте оновлення клієнтів: перезапускайте служби, що тримають застарілі посилання
Навіть після ремонту довготривалі демони можуть зберігати дескриптори файлів, що вказують на застарілі об’єкти. Визначте їх і перезапустіть як частину відновлення.
Це особливо стосується: CI-ранерів, language servers, application servers, що читають шаблони/конфіги, і всього, що слідкує за директоріями.
6) Розглядайте операції життєвого циклу сховища як руйнівні
Відкат снапшота, відновлення файлової системи, cutover реплікації і «перебудова шару» — не прозорі.
Якщо ваш процес сховища змінює ідентичність об’єктів, він потребує:
- оголошення (хто постраждає),
- плану відновлення (remount/restart),
- кроку валідації (тест шляху з канаркового клієнта).
7) Якщо ви запускаєте NFS під Kubernetes — прийміть переростання
Коли ідентичність сервера змінюється, поди не одужають самі по собі. Ваш найкращий захист — операційний патерн:
по черзі оновлюйте деплойменти (або навіть ноди) у контрольованому порядку після подій зі сховищем. Це звучить грубо — але ефективно.
8) Спостережуваність: логайте «події ідентичності», а не лише затримки
Усі графлять IOPS і пропускну здатність. Менше команд графлять: перезавантаження експорту, зміни UUID файлової системи, події failover, відкат снапшотів.
Саме ці події корелюють зі stale handles. Додайте їх у таймлайн інциденту.
Чек-листи / покроковий план
Чек-лист A: Під час інциденту (на боці клієнта)
- Підтвердіть, що ядро бачить це: перевірте
dmesgна повідомлення про stale handle. - Ідентифікуйте монтувальний пункт: використайте
findmntіnfsstat -m. - Оцініть масштаб: одне піддерево чи весь монтувальний пункт?
- Знайдіть утримувачів:
lsof +D(обережно на великих деревах) абоfuser -vm. - Зупиніть навантаження, що тримають stale FD (або дренуйте ноду).
- Відмонтуйте акуратно; якщо зайнято і потрібно діяти — використайте
umount -lі потім перезапустіть постраждалі служби. - Перемонтуйте і перевірте за допомогою
statі невеликого тесту читання/запису, відповідного шару. - Якщо проблема швидко повторюється — зупиніться: ймовірно, це серверна/експортна churn-проблема.
Чек-лист B: Під час інциденту (на боці сервера)
- Перевірте перезапуски сервісів/реекспорт у
journalctl. - Підтвердіть ефективні експорти за допомогою
exportfs -v. - Перевірте, що лежить під експортом:
findmnt -Tна експортованому шляху. - Пошукайте підказки про пересоздання файлової системи (зміни UUID, нові датасети, логи перемонтів).
- Якщо HA: підтвердіть, чи відбувся failover і чи новий вузол обслуговує тотожну бекенд-ідентичність.
- Чітко повідомте: «Клієнти повинні перемонтуватися і сервіси перезапуститися» — валідна операційна інструкція, коли ідентичність змінилася.
Чек-лист C: Впровадження профілактики (план змін)
- Зробіть інвентар експортів і їхніх бекендів. Задокументуйте, які межі стабільні.
- Визначте стратегію простору імен (особливо для NFSv4): стабільний псевдо-root, уникайте переміщення експортів.
- Зафіксуйте значення fsid там, де потрібно; тримайте їх стабільними в HA-дизайні.
- Визначте процедуру відновлення клієнта: remount + перезапуск конкретних сервісів.
- Додайте канарки: один-два клієнти, що періодично виконують
stat/findі сповіщають про ESTALE. - Проведіть failover або зміну експорту в робочий час з присутністю власників.
- Напишіть runbook і зробіть його стандартом, а не усною традицією.
FAQ
1) Чи є «Stale file handle» багом Ubuntu 24.04?
Зазвичай ні. Це Linux NFS-клієнт, що чесно повідомляє, що сервер інвалідизував ідентичність об’єкта. Ubuntu 24.04 просто запускає сучасні ядра
і сучасні навантаження, які роблять churn ідентичностей легшим для виникнення і важчим для ігнорування.
2) Чому ремонт вирішує проблему?
Ремонт змушує клієнта скинути кешовані хендли і повторно резольвити шляхи. Якщо сервер тепер послідовний і стабільний — нові хендли працюють.
Якщо сервер продовжує змінювати ідентичність — проблема повернеться.
3) Чи можуть опції кешування атрибутів запобігти stale handles?
Не справді. Кешування атрибутів впливає на те, як швидко помічаються зміни метаданих (mtime/size/permissions). Stale handles відбуваються, коли сервер
взагалі не може відобразити хендл. Ви все одно можете отримати ESTALE, якщо ідентичності змінюються.
4) Чи усуває NFSv4 проблему stale handles?
Ні. NFSv4 покращує багато речей (сесії, модель блокувань, простір імен), але не може зберегти хендл валідним, якщо бекенд-сервер змінив ідентичність.
5) Це викликано проблемами мережі?
Втрата пакетів і затори можуть зробити NFS «виглядати» поламаним, але зазвичай вони прямо не створюють ESTALE. Проте вони можуть збільшити churn монтів,
таймаути, повтори і дії відновлення, що збігаються зі змінами ідентичності. Діагностуйте обидва аспекти, але не плутайте їх.
6) Які найбезпечніші опції монтирования для продакшну?
Універсальної відповіді немає, але розумна база для критичних монтувань: NFSv4.1+, hard, TCP, розумний timeo,
і уникайте екзотичних правок без виміряної причини. Надійність важливіша за хитрощі.
7) Чому тільки довготривалі процеси падають, а нові shell-и працюють?
Довготривалі процеси зберігають відкриті дескриптори файлів або поточний робочий каталог, що вказує на об’єкти, які стали невалідними.
Нові shell-и резольвлять шляхи заново і отримують нові хендли, тому вони здаються «в порядку». Ця розбіжність — класичний підпис stale handle.
8) Як поводитися зі stale handles у Kubernetes?
Припускайте, що треба буде щось перезапустити: перезапустіть поди, які торкалися шару, можливо дренуйте/перезавантажте ноди у крайніх випадках.
Ще важливіше: уникайте churn-у ідентичностей, тримайте експорти/бекенди стабільними і розглядайте cutover-и як скоординовані операції.
9) Чи можна «очистити» stale handles без відмонтування?
Іноді можна обійти: cd з застарілого каталогу, повторно відкрити файли або перезапустити сервіс.
Але якщо застарілі посилання поширені — чистий шлях — unmount/remount.
10) Що казати командам додатків, коли це трапляється?
Говоріть їм правду в операційних термінах: «Ідентичність NFS-сервера змінилася; ваш процес тримає застарілі посилання.
Ми перемонтуємо і перезапустимо ваш сервіс, щоб заново відкрити шляхи.» Не кажіть, що це «випадкова NFS-флуктуація».
Висновок: практичні наступні кроки
«Stale file handle» трапляється, коли ви ставитеся до NFS як до чарівної папки за назвою, а не як до розподіленої системи з ідентичностями.
Виправлення рідко буває екзотичним. Зазвичай це дисципліна: стабільні експорти, стабільні бекенди і скоординований клієнтський оновлення, коли ідентичності змінюються.
- Зараз: використайте швидкий план діагностики, знайдіть монтувальний пункт і піддерево, і акуратно перемонтуйте після зупинки процесів, що тримають FD.
- Цього тижня: перевірте топологію експорту і припиніть експортувати шляхи, що перетинають нестабільні mountpoints. Зафіксуйте стабільну ідентичність там, де потрібно.
- Цього кварталу: переведіть міграції, відкати і failover-и у вигляді runbook-ів із канарковою валідацією і явними кроками remount/restart клієнтів.
Вам не потрібно любити NFS. Але ви повинні експлуатувати його як реальну інфраструктуру. Бо так воно і є.