Ви не помічаєте «сховище», коли воно працює. Ви помічаєте його, коли черга збірок зупиняється, ваша VM завантажується ніби через мішалку для кави,
а база даних починає логувати «fsync taking too long», поки всі звинувачують мережу, бо це соціально прийнятний козел відпущення.
ZFS поверх NFS може відчуватися шокуюче близько до локального диска — поки цього не трапиться. Різниця майже завжди в налаштуваннях, непогоджених припущеннях і кількох
дрібних, але смертельно небезпечних значеннях за замовчуванням. Виправимо це.
Ментальна модель: чому «NFS повільний» зазвичай — неправда
«NFS повільний» — це не діагноз. Це емоційний стан. У продакшні повільність походить з одного з чотирьох джерел:
затримка, серіалізація, семантика синхронізації або фрагментація/несумісність з робочим навантаженням. ZFS і NFS обидва мають чіткі уявлення
про те, як має відбуватися IO. Коли їхні уявлення збігаються, ви отримуєте відчуття локального диска. Коли ні — ви отримуєте розподілений
DoS, збудований з маленьких, добре намірених значень за замовчуванням.
Ваше завдання — узгодити конвеєр:
- Форма IO в додатку: випадкова проти послідовної, мала проти великої, sync проти async, метаданто-завантажена проти стрімінгу.
- Поведінка NFS: кешування атрибутів, read-ahead, delegation/locking, кількість паралельних RPC, семантика mount.
- Поведінка ZFS: recordsize, compression, primarycache, розмір ARC, special vdev, політика sync, ZIL/SLOG.
- Апаратна і мережна реальність: мінімальна затримка, швидкість лінку, глибина черги, пом’якшення переривань, NIC offloads.
Найпоширеніший спосіб провалу — вважати сховище «достатньо швидким», бо воно добре бенчмаркується локально на сервері.
NFS змінює шаблон IO. ZFS реагує. Затримка підсилюється круговими поїздками та синхронними семантиками. Пул, що робить 2 GB/s послідовних читань,
може все одно відчуватися жахливо для навантаження, що робить 4 KB sync-записи по NFS.
Ще один важливий момент: «відчувається як локальний диск» не означає «така ж пропускна здатність». Це означає «така ж хвостова затримка в нормальній роботі».
Хвостова затримка — те, що змушує користувачів писати тікети або, гірше, робити обхідні шляхи.
Перефразована ідея (атрибуція): John Allspaw стверджував, що надійність — це зменшення несподіванок, а не лише запобігання помилкам.
Налаштування NFS — це про зниження несподіванок.
Факти та історія, що досі важливі в продакшні
Кілька конкретних контекстних моментів роблять сьогоднішні вибори налаштувань менш містичними. Це не дрібниці; вони пояснюють, чому значення за замовчуванням такі,
і чому ваше навантаження все ще може впасти з обриву.
- NFS починався, припускаючи ненадійні мережі. Ранні дизайни тяжіли до безстанності (особливо в NFSv3), що впливає на відновлення клієнтів і кешування.
- NFSv4 ввів стан. Блокування й делегації змінили координування клієнт/сервер і можуть покращити продуктивність — поки не виникне конфлікт із дивною поведінкою клієнта або схемами failover.
- ZFS створювався навколо copy-on-write. Це чудово для снапшотів і цілісності; але це також означає, що малі випадкові записи можуть перетворюватися на більші, складніші IO-патерни.
- ZIL існує навіть без виділеного SLOG. Дехто все ще вважає «нема SLOG — нема ZIL». ZIL — це структура журналу; SLOG — просто швидший пристрій для нього.
- Синхронні записи — це семантична обіцянка, а не перевага продуктивності. Бази даних і гіпервізори часто змушують fsync з вагомих причин.
- Recordsize — не «розмір блоку». Це максимальний логічний розмір блока для файлів, що впливає на те, як ZFS пакує дані і скільки читає/записує для конкретного запиту.
- Кешування атрибутів в NFS — це хак для продуктивності з наслідками. Воно може прискорити метаданто-завантажені навантаження — або ввести плутанину «чому я не бачу файл?» у розподілених додатках.
- Контрольні суми змінили гру. Контрольні суми ZFS і scrub-операції — через них історії про «мовчазну корупцію» в ентерпрайз-сховищах більше не міф.
- 10GbE зробив пропускну спроможність простою, затримку — ні. Багато команд «підтягнули трубу», а потім виявили, що їхнім вузьким місцем є RTT синхронізації та час скидання сховища.
Ручки NFS клієнта й сервера, що впливають на результат
Свідомо обирайте версію протоколу
NFSv4.x зазвичай — правильний дефолт у 2025 році: краща модель безпеки, compound-операції, stateful-особливості, які можуть зменшити «балаканину».
Але NFSv3 все ще має місце, особливо там, де потрібна простіша поведінка або ви працюєте з певними гіпервізорами й легасі-стеками, що «спеціальні» у спосіб, який псує вихідні дні.
Ключ — послідовність. Змішані версії на клієнтах можуть створити неочевидні відмінності в поведінці (блокування, кешування, відновлення), і ви почнете дебажити
«продуктивність», коли насправді дебажите семантику.
rsize/wsize: припиніть боятися
Сучасні мережі й кернелі добре працюють з великими розмірами IO. Використовуйте 1M там, де це підтримується. Якщо ваше середовище не може — ви швидко про це дізнаєтесь у переговорі.
Малі значення rsize/wsize дають більше RPC, більше оверхеду і більше шансів впертися в стіну затримки.
Але не застосовуйте сліпо: якщо ви на високозатриманому WAN-лінку, великі розміри можуть покращити пропускну здатність, але погіршити інтерактивну хвостову затримку в деяких сценаріях.
Вимірюйте за вашим робочим навантаженням, а не за синтетичним тестом послідовного читання.
nconnect і паралелізм: найкращий друг пропускної здатності
Linux-клієнти підтримують nconnect= для відкриття кількох TCP-з’єднань до сервера для одного маунту. Це може значно збільшити пропускну здатність,
розподіливши навантаження по CPU-чергах і уникаючи становлення одного потоку як вузького місця. Це не безкоштовно; більше з’єднань — більше стану і іноді більше конкуренції за локи на сервері.
Hard vs soft mounts: будьте сміливими, але не безпечними
Використовуйте hard mounts для всього, що має значення. Soft mounts повертають помилки при таймауті, які багато додатків трактують як корупцію або «видалити і повторити».
Так ви перетворюєте тимчасовий збій на втрату даних.
Для інтерактивних домашніх директорій розробників «soft» може здаватися приємнішим, коли сервер недоступний, але це пастка. Якщо хочете відгукувальності, налаштуйте таймаути і
retransmits. Не міняйте коректність на зручність.
actimeo і кешування атрибутів: свідомо обирайте отруту
Метаданто-завантажені навантаження (системи збірки, менеджери пакетів) можуть виграти від кешування атрибутів. Але розподілені додатки, що чекають майже миттєвого відображення змін файлів,
можуть заплутатися, якщо клієнти кешують атрибути надто довго.
Чистий підхід: встановіть actimeo на розумне значення (наприклад, 1–5 секунд), а не вимикайте кешування повністю.
«actimeo=0» — це самопроникнення продуктивності для більшості навантажень.
Потоки сервера і поведінка RPC
На Linux NFS-серверах кількість потоків nfsd має значення при високій конкурентності. Занадто мало потоків — запити ставляться в чергу; занадто багато — ви спалюєте CPU на контекстних переключеннях
і конкуренцію за локи. Потрібно «достатньо, щоб трубопровід був повний», а не «максимально, скільки вміститься в RAM».
Параметри ZFS dataset і пула, що змінюють результати
recordsize: підганяйте під навантаження, а не під відчуття
Якщо ви подаєте образи VM або бази даних через NFS, найпоширеніша перемога — встановити recordsize на щось на кшталт 16K або 32K (іноді 8K),
бо ці навантаження роблять багато малих випадкових IO. Значення за замовчуванням 128K чудове для стрімінгу й бекапів, але не для гостей з великою кількістю випадкових записів.
Для загального використання домашніх директорій 128K підходить. Для медіа-архівів розгляньте більші recordsize, якщо платформа це підтримує.
Головна ідея — уникати read-modify-write-підсилення і зберегти ARC корисним.
compression: увімкніть, якщо немає причин ні
compression=lz4 — одна з небагатьох майже безкоштовних опцій у сховищі. Вона часто покращує пропускну здатність і зменшує IO. На сучасних CPU вартість помірна.
Ви не «врятуєте продуктивність», відключивши compression; часто ви просто змушуєте більше байт їхати по диску та мережі.
atime: вимикайте для більшості NFS-експортів
Оновлення часу доступу створюють додаткові записи і метаданто-хаос. Якщо немає вимог з комплаєнсу або з боку додатків, використовуйте atime=off.
Для спільних файлових систем, що віддають багато читань, це легке зниження затримки.
xattr і ACL: обирайте режим, що відповідає вашим клієнтам
Linux-клієнти, Windows-клієнти (через SMB-шлюзи) і гіпервізори можуть очікувати різної поведінки щодо ACL і розширених атрибутів.
Погане узгодження проявляється як метаданто-шторм і проблеми з правами. Визначте основний випадок використання і налаштуйте під нього.
special vdev: метаданти заслуговують кращого, ніж «те, що залишилося»
Якщо ваше навантаження метаданто-завантажене (мільйони дрібних файлів, збірки, дереви з кодом), special vdev може змінити правила гри.
Помістіть метаданти (і за потреби малі блоки) на швидкі SSD. Попадання в ARC — чудово, але промахи ARC трапляються, а промахи по метадантах — це смерть від тисячі пошуків.
primarycache і secondarycache: будьте навмисні
ARC — це пам’ять; L2ARC — SSD-кеш. Для NFS-експортів, що віддають великі стрімінгові читання, кешування може виштовхувати корисні метаданти.
Для образів VM кешування даних може допомогти, але спочатку варто перевірити розмір пам’яті. Поширений патерн:
primarycache=metadata для певних dataset-ів, щоб зберегти ARC для того, що дійсно допомагає.
ashift: ви не налагодите це пізніше
ashift задається при створенні vdev і впливає на вирівнювання секторів. Помиліться — і платитимете вічно за write amplification.
Якщо ви на 4K секторних дисках або SSD (а ви, ймовірно, на них), ashift=12 — звичайний безпечний вибір. Не дозволяйте авто-детекції помилитися.
Синхронні записи, SLOG і чому «sync=disabled» — шлях у проблеми
Клієнти NFS часто відправляють записи як синхронні залежно від опцій маунту та поведінки додатку. Бази даних викликають fsync, бо хочуть, щоб їхні дані
пережили відключення живлення. Гіпервізори часто використовують синхронну семантику для дисків VM, бо «втратити файлову систему VM» — дороге зібрання.
У ZFS синхронні записи підтверджуються тільки коли вони безпечно закомічені. Це означає, що шлях ZIL має значення.
Без виділеного SLOG ZIL живе на основному пулі, і затримка синхронного запису стає «наскільки швидко пул може безпечно зафіксувати малі записи».
На HDD-пулах це може бути жорстоко. На SSD-пулах — можливо нормально. На змішаних пулах — залежить від найповільнішого узгодженого кроку.
Виділений SLOG-пристрій може кардинально знизити синхронну затримку. Але тільки якщо це правильний пристрій: низька затримка, захист від втрати живлення, стабільна продуктивність
і надійне підключення. Дешевий споживчий NVMe без PLP — генератор відмов у маскуванні.
Жарт №1: Споживчий SSD як SLOG — як використовувати паперову парасолю в урагані — технічно парасоля, емоційно провал.
Не вимикайте sync, щоб «вирішити продуктивність»
sync=disabled робить бенчмарки дивовижними. Він також перетворює «підтверджений запис» на «можливо запишеться згодом», а це не те, чого очікують багато додатків.
Якщо сервер впаде, ви можете втратити дані, які клієнт вважав довговічними. Це не налаштування; це трюк із підлогою.
Розумійте режими sync: standard, always, disabled
- sync=standard: поважає запити додатків (за замовчуванням, зазвичай правильно).
- sync=always: трактує всі записи як sync. Корисно для певних випадків відповідності; часто карає продуктивністю.
- sync=disabled: брешіть клієнтам. Лише для спеціальних випадків, де ви свідомо прийняли ризик і задокументували це, як дорослі.
logbias і наміри навантаження
logbias=latency підказує ZFS надавати пріоритет низькій затримці логування (часто підходить для sync-важких навантажень). logbias=throughput може допомогти для стрімінгу.
Це ручка для вирівнювання наміру, а не магічний важіль продуктивності. Перевіряйте її для кожного dataset.
Мережевий шлях: нудні налаштування, які купують вам мілісекунди
NFS чутливий до затримки, бо кожний RPC — це кругова поїздка, а синхронні записи — ланцюжок підтверджень.
Вам не потрібна розкішна мережа. Вам потрібна передбачувана.
Jumbo frames: не обов’язково, але не робіть півзаходів
Якщо ви вмикаєте MTU 9000, це має бути end-to-end: NIC, свічі, VLANи, bondingи і сервер сховища. Часткова конфігурація jumbo гірша за відсутність, бо отримаєте
фрагментацію або чорні діри. Якщо ви не контролюєте весь шлях — пропустіть це і зосередьтесь на уникненні дропів.
NIC offloads і CPU
Offloads можуть допомогти, але також можуть викликати дивні спайки затримки залежно від драйверів і прошивки. Правильний підхід — емпіричний:
виміряйте CPU softirq, дропи і затримку, а потім вирішіть. Не вимикайте функції лише тому, що блог 2013 року так радив.
Затори і bufferbloat
На швидких LAN-ах все ще можуть бути мікро-сплески і черги. Слідкуйте за буферами комутаторів, черговістю на хості і TCP retransmits.
Якщо NFS «відчувається повільним» лише під навантаженням, ви можете спостерігати накопичення черг, а не обмеження пропускної здатності.
Практичні завдання: команди, виводи й наступні рішення
Це польові завдання, які ви можете виконати під час скарги на продуктивність, не перетворюючи інцидент на археологічний проєкт.
Кожне завдання включає: команду, що означає вивід, і рішення, яке ви на його підставі приймаєте.
Завдання 1: Підтвердіть опції маунту NFS (клієнт)
cr0x@server:~$ nfsstat -m
/home from nas01:/tank/home
Flags: rw,relatime,vers=4.2,rsize=1048576,wsize=1048576,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=10.10.10.21,local_lock=none
Що це означає: Ви на NFSv4.2 з rsize/wsize 1M, hard-маунт, TCP. Це здоровий базовий рівень.
Рішення: Якщо бачите крихітні rsize/wsize (наприклад 64K) або несподівано vers=3, спочатку виправте маунти. Якщо там soft, змініть, якщо це не тимчасові дані.
Завдання 2: Швидка перевірка погодженої версії NFS і транспорту (клієнт)
cr0x@server:~$ cat /proc/mounts | grep nfs
nas01:/tank/home /home nfs4 rw,relatime,vers=4.2,rsize=1048576,wsize=1048576,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=10.10.10.21,local_lock=none 0 0
Що це означає: Підтверджує те, що думає ядро, а не те, що хотілося записати в fstab.
Рішення: Якщо в fstab вказано nconnect=8, а тут його немає — ви насправді ним не користуєтесь. Виправте автоматизацію маунтів.
Завдання 3: Виміряйте затримку до NFS-сервера (клієнт)
cr0x@server:~$ ping -c 5 nas01
PING nas01 (10.10.10.10) 56(84) bytes of data.
64 bytes from 10.10.10.10: icmp_seq=1 ttl=64 time=0.312 ms
64 bytes from 10.10.10.10: icmp_seq=2 ttl=64 time=0.287 ms
64 bytes from 10.10.10.10: icmp_seq=3 ttl=64 time=0.301 ms
64 bytes from 10.10.10.10: icmp_seq=4 ttl=64 time=0.295 ms
64 bytes from 10.10.10.10: icmp_seq=5 ttl=64 time=0.289 ms
--- nas01 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4090ms
rtt min/avg/max/mdev = 0.287/0.296/0.312/0.009 ms
Що це означає: RTT менше мілісекунди в LAN. Добре. Якщо це 2–5 ms, синхронні навантаження будуть відчуватися «липкими».
Рішення: Якщо RTT високий або дуже варіабельний, припиніть налаштовувати ZFS. Спочатку виправте мережевий шлях, NIC або маршрутизацію.
Завдання 4: Перевірте TCP retransmits і дропи (клієнт)
cr0x@server:~$ netstat -s | egrep -i 'retrans|segments retransm|lost|timeouts' | head
12 segments retransmitted
0 retransmit timeouts
0 connections reset due to unexpected data
Що це означає: Невелика кількість retransmits. Якщо це зростає під час скарг — втрачаєте пакети або сильне чергування.
Рішення: Зростання retransmits під навантаженням = перевірте статистику NIC, порти свічів, невідповідність MTU або bufferbloat.
Завдання 5: Підтвердіть, що NFS-сервер експортує те, що ви думаєте (сервер)
cr0x@server:~$ exportfs -v
/tank/home 10.10.10.0/24(rw,async,wdelay,hide,no_subtree_check,sec=sys,secure,root_squash,no_all_squash)
Що це означає: Експорт має async на рівні NFS (це про поведінку відповіді сервера, а не про синхронні семантики ZFS). Root squashing увімкнено.
Рішення: Якщо ви подаєте бази даних/VM, ретельно продумайте async. Багато організацій залишають NFS export async, покладаючись на ZFS sync для коректності; інші вимагають синхронного експорту. Не гадіть — узгодьте з вашою моделлю ризику.
Завдання 6: Перевірте кількість потоків nfsd (Linux сервер)
cr0x@server:~$ cat /proc/fs/nfsd/threads
32
Що це означає: 32 nfsd-потоки. Якщо у вас сотні клієнтів роблять метаданто-операції, замало потоків призведе до черг.
Рішення: Якщо CPU низький, а клієнти стоять у черзі, збільшіть потоки помірно (наприклад до 64). Якщо CPU високий і затримка зростає, додавання потоків може нашкодити.
Завдання 7: Спостерігайте активність NFS RPC (сервер)
cr0x@server:~$ nfsstat -s
Server rpc stats:
calls badcalls badclnt badauth xdrcall
482913 0 0 0 0
Server nfs v4:
null compound read write getattr
0 412001 32941 21887 100221
Що це означає: Велика кількість compound і getattr вказує на метаданто-завантажений трафік. Лічильники read/write показують IO-мікс.
Рішення: Якщо getattr домінує і затримка страждає, розгляньте special vdev для ZFS, фокус ARC на метадантах і стратегію кешування атрибутів на клієнті.
Завдання 8: Перевірте здоров’я ZFS пула і індикатори повільного IO (сервер)
cr0x@server:~$ zpool status -v
pool: tank
state: ONLINE
scan: scrub repaired 0B in 02:11:43 with 0 errors on Sun Dec 22 01:10:18 2025
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
raidz2-0 ONLINE 0 0 0
sda ONLINE 0 0 0
sdb ONLINE 0 0 0
sdc ONLINE 0 0 0
sdd ONLINE 0 0 0
sde ONLINE 0 0 0
sdf ONLINE 0 0 0
errors: No known data errors
Що це означає: Пул здоровий, scrub чистий. Це не доказ продуктивності, але прибирає «degraded vdev» зі списку підозрюваних.
Рішення: Якщо бачите деградований диск або resilver, зупиніться. Тюнінг під час відновлення — як налаштовувати авто під час пожежі в шині.
Завдання 9: Подивіться реальну ZFS-затримку й поведінку sync (сервер)
cr0x@server:~$ zpool iostat -v tank 1 5
capacity operations bandwidth
pool alloc free read write read write
---------- ----- ----- ----- ----- ----- -----
tank 3.12T 8.54T 220 1450 48.1M 31.2M
raidz2-0 3.12T 8.54T 220 1450 48.1M 31.2M
sda - - 35 240 8.2M 5.3M
sdb - - 36 241 8.1M 5.2M
sdc - - 37 239 8.0M 5.3M
sdd - - 37 242 8.0M 5.2M
sde - - 38 243 8.0M 5.1M
sdf - - 37 245 7.8M 5.1M
Що це означає: Write IOPS високі, пропускна спроможність помірна — класичне навантаження з малими записами. HDD RAIDZ2 під sync-важким IO почуватиметься повільно.
Рішення: Якщо це VM/бази даних через NFS, розгляньте SLOG і менший recordsize. Якщо це метаданто-шафл, подумайте про special vdev і вимкнення atime.
Завдання 10: Перегляньте властивості ключового dataset (сервер)
cr0x@server:~$ zfs get -o name,property,value -s local,default recordsize,compression,atime,sync,logbias,primarycache tank/home
NAME PROPERTY VALUE
tank/home recordsize 128K
tank/home compression lz4
tank/home atime off
tank/home sync standard
tank/home logbias latency
tank/home primarycache all
Що це означає: Сенсні дефолти для загального використання, але recordsize може бути неправильним для образів VM або баз даних.
Рішення: Якщо цей dataset подає диски VM, встановіть recordsize меншим (16K–32K) і розгляньте primarycache=metadata залежно від пам’яті й шаблону доступу.
Завдання 11: Перевірте тиск ARC і коефіцієнт попадань (сервер)
cr0x@server:~$ arcstat 1 3
time read miss miss% dmis dm% pmis pm% mmis mm% arcsz c
12:01:11 780 90 11 22 2 68 9 0 0 42G 48G
12:01:12 802 95 12 24 2 71 9 0 0 42G 48G
12:01:13 799 88 11 21 2 67 8 0 0 42G 48G
Що це означає: ~11–12% miss rate. Не жахливо. Якщо miss% стрибає під час навантаження — диски будуть «скребти», і NFS-затримка зросте.
Рішення: Якщо ARC занадто обмежений або пам’ять голодує, обережно налаштуйте розмір ARC або зосередьте кешування на метадантах через властивості dataset.
Завдання 12: Підтвердьте наявність і роль SLOG (сервер)
cr0x@server:~$ zpool status tank | sed -n '1,80p'
pool: tank
state: ONLINE
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
raidz2-0 ONLINE 0 0 0
sda ONLINE 0 0 0
sdb ONLINE 0 0 0
sdc ONLINE 0 0 0
sdd ONLINE 0 0 0
sde ONLINE 0 0 0
sdf ONLINE 0 0 0
logs
nvme0n1p1 ONLINE 0 0 0
Що це означає: Є виділений лог-пристрій. Добре. Тепер переконайтесь, що це правильний клас пристрою (затримка, PLP).
Рішення: Якщо немає SLOG і у вас sync-важкі навантаження на HDD — додайте дзеркальний SLOG з enterprise-пристроїв.
Завдання 13: Виявити «біль від sync-записів» з боку клієнта (клієнт)
cr0x@server:~$ dd if=/dev/zero of=/home/testfile bs=4k count=4096 conv=fdatasync status=progress
16777216 bytes (17 MB, 16 MiB) copied, 2.10 s, 8.0 MB/s
4096+0 records in
4096+0 records out
16777216 bytes (17 MB, 16 MiB) copied, 2.10 s, 8.0 MB/s
Що це означає: 4K sync-flush записи повільні (8 MB/s). Це та сама біль, яку відчувають користувачі в базах даних і журналях VM.
Рішення: Якщо це «погано», не ганяйтеся за rsize/wsize. Переслідуйте якість SLOG, затримку пула і семантику sync.
Завдання 14: Порівняйте асинхронну стрімінгову продуктивність (клієнт)
cr0x@server:~$ dd if=/dev/zero of=/home/testfile2 bs=1M count=4096 status=progress
4294967296 bytes (4.3 GB, 4.0 GiB) copied, 9.12 s, 471 MB/s
4096+0 records in
4096+0 records out
4294967296 bytes (4.3 GB, 4.0 GiB) copied, 9.12 s, 471 MB/s
Що це означає: Великі стрімінгові записи виглядають чудово. Цей контраст класичний: пропускна здатність в порядку, затримка sync — ні.
Рішення: Оптимізуйте під реальне навантаження. Якщо ваш додаток робить sync 4K, зосередьтесь на ZIL/SLOG і затримці, а не на пропускній здатності.
Завдання 15: Перевірте підозри на write amplification по dataset (сервер)
cr0x@server:~$ zfs get -o name,property,value copies,dedup,checksum tank/home
NAME PROPERTY VALUE
tank/home copies 1
tank/home dedup off
tank/home checksum on
Що це означає: Dedup відключено (добре для більшості), single copy, checksumming увімкнено. Dedup на зайнятому NFS-dataset — часта історія «чому все повільно?»
Рішення: Якщо dedup випадково увімкнено — плануйте міграцію з нього. Вимкнення не «віддедупує» існуючі блоки.
Завдання 16: Виловіть помилки на рівні NIC і невідповідності MTU (сервер)
cr0x@server:~$ ip -s link show dev eno1
2: eno1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc mq state UP mode DEFAULT group default qlen 1000
link/ether 3c:fd:fe:aa:bb:cc brd ff:ff:ff:ff:ff:ff
RX: bytes packets errors dropped missed mcast
918G 612M 0 12 0 1200
TX: bytes packets errors dropped carrier collsns
877G 590M 0 3 0 0
Що це означає: Кілька дропів. Не обов’язково фатально, але якщо дропи підскакують під час піків — NFS-затримка і retransmits слідуватимуть.
Рішення: Якщо MTU 9000 тут, а десь ще 1500 — виправте мережу. Якщо дропи продовжуються — перевірте кільця буферів, IRQ affinity і чергування на свічі.
Швидкий план діагностики
Коли хтось каже «NFS повільний», вам потрібен план, що знаходить вузьке місце за хвилини, а не за ланцюг емейлів.
Ось порядок дій, що мінімізує марну витрату часу.
Перше: вирішіть, чи це біль від затримки або від пропускної здатності
- Біль від затримки: малі IO, sync-важкі, метаданто-операції. Симптоми: повільний git status, повільна інсталяція пакетів, бази даних жаліються на fsync, паузи VM.
- Біль від пропускної здатності: повільні великі трансфери. Симптоми: повільні бекапи, копіювання великих файлів нижче швидкості лінку.
Запустіть пару швидких тестів: sync-flush dd (Завдання 13) і великий послідовний dd (Завдання 14). Якщо послідовний в порядку, а sync жахливий — проблема вже звужена.
Друге: перевірте мережу на очевидні зрадники
- Ping RTT і jitter (Завдання 3).
- Retransmits (Завдання 4).
- Помилки інтерфейсу/дропи (Завдання 16).
Якщо бачите підвищені retransmits під час інциденту — зупиніться і виправте мережевий шлях. Налаштування сховища не перехитрить втрачені пакети.
Третє: перевірте семантику маунту і версію протоколу
- Підтвердіть опції маунту і погоджені rsize/wsize, версію, proto (Завдання 1–2).
- Перевірте, чи
nconnectдійсно працює. - Шукайте
actimeo=0або дивні таймаути.
Четверте: визначте, чи сервер CPU-bound, thread-bound або IO-bound
- Потоки NFS сервера (Завдання 6).
- Мікс NFS-операцій (Завдання 7): метаданти vs дані.
- ZFS pool iostat (Завдання 9): профіль IOPS і пропускної здатності.
- Поведіка ARC (Завдання 11): чи ви промахуєтесь у кеш і йдете на диск?
П’яте: підтвердіть sync-шлях (SLOG/ZIL) і властивості dataset
- Наявність SLOG (Завдання 12).
- Dataset sync/logbias/recordsize (Завдання 10).
- Сюрпризи dedup/copies (Завдання 15).
Якщо навантаження sync-важке, а у вас немає належного SLOG — відповідь очевидна. Якщо SLOG є, підозрюйте якість пристрою або його насичення,
або що ви фактично ним не користуєтесь через властивості dataset.
Три корпоративні історії з передової
Інцидент: хибне припущення («NFS async означає достатньо безпечно»)
Середня компанія тримала CI-артефакти і невеликий інстанс Postgres на NFS-експорті, що базувався на ZFS. Команда зберігання встановила NFS-експорт як async,
бо «це покращило продуктивність», і вважала, що ZFS усе одно покриє витривалість. Команда додатку вважала «NFS — спільний диск, отже довговічний».
Потім стався подія з живленням. Нічого драматичного — короткий аут і нечисте перезавантаження. Postgres перезапустився і почав скаржитися на пошкоджені сторінки.
CI-система також показала відсутні шматки артефактів, які нібито «успішно завантажилися» кілька хвилин тому. Канал інцидентів наповнився класичними питаннями:
«Може це DNS?» і «Я думав, ZFS запобігає корупції».
Корінь проблеми не в корупції ZFS. Він у семантиці. NFS-сервер відповів на записи до того, як вони були довговічні на стабільному носії.
ZFS мала цілісність, але цілісність того, що фактично було закомічено. Деякі підтверджені записи так і не дійшли. Це не проблема чексума; це проблема обіцянки.
Виправлення не було одним перемикачем. Вони розділили навантаження: CI-артефакти залишили на async-експортах (прийнятний ризик, дані відтворювані),
бази даних перемістили на експорт і політику dataset, що поважає синхронну довговічність, з дзеркальним enterprise SLOG.
Також задокументували політику в каталозі сервісів, щоб «async» перестав бути невидимою рушійною силою проблем.
Оптимізація, що обернулась проти: ставка на recordsize
Інша організація подавала образи VM через NFS з блискучого нового ZFS-пула. Хтось помітив дефолтний recordsize=128K і вирішив, що «більші блоки — значить швидше».
Вони встановили recordsize в 1M для dataset-а з образами VM. Початкові тести виглядали чудово: копіювання великих ISO швидше, синтетичний послідовний бенчмарк
дав графік, який міг би виграти нагороду.
Через два тижні почалися скарги на випадкову затримку: часи завантаження VM коливалися, інтерактивні сесії підлагували, а логи гіпервізора показували іноді таймаути IO.
Сервер сховища зовні не здавався «навантаженим» з точки зору пропускної здатності, але був зайнятий найгіршим чином: read-modify-write-підсиленням і неефективністю кешу.
Малі записи гостей змушували систему торкатися величезних записів, а ARC почав кешувати великі блоки даних замість метадантів і гарячих регіонів, що дійсно мали значення.
Тривалість розслідування була більше, ніж потрібно, бо всі дивилися на пропускну здатність. Пропускна була в порядку. Хвостова затримка — ні.
Зрештою хтось порівняв розміри IO від гіпервізора з recordsize ZFS і зрозумів, що налаштували під невірне навантаження.
План відновлення був нудний: новий dataset із розумним recordsize (16K–32K), storage vMotion/міграція дисків VM і залишити 1M recordsize для архівів бекапів.
Урок: не налаштовуйте файлову систему для бенчмарку, який ви не запускаєте в продакшні.
Нудно, але правильно: окремі dataset-и, розумні дефолти, задокументований намір
Велике підприємство мало внутрішню «NFS платформу» для dev, build, analytics і кількох станфул сервісів. Вони зробили щось глибоко неефектне:
стандартизували шаблони dataset-ів. Домашні каталоги отримали один шаблон; кеші збірок інший; образи VM — третій. Кожен шаблон мав recordsize, atime, compression
і політику кешування, узгоджену з кейсом використання.
Коли стався інцидент продуктивності під час великого релізного тижня, on-call не мав гадати, «для чого цей share». Назва dataset кодувала намір, а властивості відповідали йому.
Вони викликали zfs get і одразу виключили класичні помилки: немає неочікуваного dedup, немає випадкового sync=always,
немає atime-чаргу на read-heavy шарах.
Проблема виявилася в мережевій заторі на ToR-свічі. Оскільки конфігурація сховища була передбачуваною, вони не витратили години на перемикання налаштувань ZFS
і перезавантаження клієнтів. Виправили чергування — і проблема зникла.
Перемога не була в розумному тюні. Перемога — це усунення неоднозначності, що є найнадійнішою оптимізацією продуктивності, яку я знаю.
Типові помилки: симптом → корінь → виправлення
1) «Копіювання великих файлів швидке, але бази даних повільні»
Симптом: Послідовний dd виглядає чудово, але все, що fsync-ить, повзе; гостеві VM підлагують.
Корінь: Вузьке місце синхронного запису (немає SLOG, слабкий SLOG, повільний flush пула).
Виправлення: Додайте належний дзеркальний SLOG з PLP; тримайте sync=standard. Перевірте sync-flush тести і спостерігайте затримку під навантаженням.
2) «Все стало повільним після встановлення actimeo=0»
Симптом: Збірки і операції переліку файлів стали млявими; CPU сервера зріс; getattr операції підскочили.
Корінь: Відключений атрибутний кеш, що викликає постійну перевірку метаданту.
Виправлення: Використовуйте помірний actimeo=1 або налаштування acregmin/acregmax замість нуля; додайте special vdev для метаданих за потреби.
3) «NFS зависає назавжди, коли сервер впав»
Симптом: Процеси зависли в стані D; неможливо вбити IO-wait.
Корінь: Hard-маунт робить те, що обіцяє, плюс додаток, який не витримує блокуючий IO.
Виправлення: Тримайте hard-маунти для коректності, але налаштуйте timeo/retrans розумно і проектуйте додатки з таймаутами; для неважливих маунтів розгляньте окремі шляхи або локальні кеші.
4) «Випадковий IO жахливий на RAIDZ пулі»
Симптом: Навантаження з високими write IOPS дає жахливу затримку; iostat показує багато малих записів по HDD vdev-ах.
Корінь: RAIDZ + малі випадкові записи + sync-семантика = write amplification і шторм пошуків.
Виправлення: Використовуйте mirror-бу для пулів з великою кількістю випадкових записів, або забезпечте кешування/агрегацію навантаження; додайте SLOG для sync, налаштуйте recordsize і розгляньте special vdev для метаданих/малих блоків.
5) «Ми додали потоки nfsd і стало гірше»
Симптом: CPU підскочив, контекстні переключення виросли, затримка збільшилась.
Корінь: Занадто багато серверних потоків спричинили конкуренцію і оверхед планувальника.
Виправлення: Зменшіть потоки до виміряного оптимуму; зосередьтесь на CPU affinity, мережевих прерываннях і базовій затримці сховища.
6) «Після ввімкнення jumbo frames деякі клієнти випадково повільні»
Симптом: Деякі підмережі або хости бачать таймаути, retransmits; інші — в порядку.
Корінь: Невідповідність MTU десь у шляху, що викликає фрагментацію або дропи.
Виправлення: Забезпечте end-to-end консистентність MTU або поверніться до 1500; перевірте ping з DF і налаштування комутаторів.
7) «ARC hit rate в порядку, але ми все одно повільні»
Симптом: ARC miss% виглядає нормально, але клієнти скаржаться; пул показує тиск на sync-записи.
Корінь: Кеш не допомагає затримці commit для sync; вузьке місце — час flush/commit.
Виправлення: Інвестуйте в SLOG і низькозатратні пристрої; зменшуйте sync IO там, де це коректно (налаштування додатка), а не там, де небезпечно (не налаштовуйте sync=disabled).
8) «Ми увімкнули dedup і сервер NFS одержимий»
Симптом: Підстрибує затримка, пам’ять страждає, продуктивність непередбачувана.
Корінь: Dedup потребує великих гарячих метадантичних структур; якщо вони не розміровані правильно — все трясеся і карає кожний IO.
Виправлення: Не використовуйте dedup для загального NFS. Мігрируйте дані з dedup-dataset; тримайте compression замість цього.
Жарт №2: Dedup — це сховищний еквівалент усиновлення єнота — іноді мило, але він обов’язково все розтягне.
Чеклісти / покроковий план
План A: змусити існуючий ZFS+NFS share відчуватися як локальний диск для загальних користувачів
- Базуйте клієнтський маунт. Підтвердіть
vers,proto=tcp,hard, і погодженіrsize/wsize(Завдання 1–2). - Встановіть розумні опції маунту. Типовий старт: NFSv4.2,
rsize/wsize=1M,hard, налаштованийtimeo, і розгляньтеnconnect=4або8для зайнятих клієнтів. - Вимкніть atime на dataset.
zfs set atime=offдля користувацьких шарів, якщо не потрібно. - Увімкніть compression lz4.
zfs set compression=lz4. - Слідкуйте за поведінкою метаданих. Якщо
getattrдомінує (Завдання 7), розгляньте помірне кешування атрибутів і special vdev для метаданих. - Перевірте мережеву адекватність. RTT, retransmits, дропи (Завдання 3–4, 16).
- Повторно протестуйте реальні робочі процеси. Git-операції, збірки, перегляд файлів, а не тільки великий
dd.
План B: подавати образи VM через NFS без жалю
- Створіть виділений dataset. Не використовуйте «home dirs» dataset і не сподівайтеся на краще.
- Встановіть recordsize під IO. Почніть з 16K або 32K для дисків VM. Протестуйте обидва.
- Тримайте sync чесним. Використовуйте
sync=standard. Додайте належний дзеркальний SLOG, якщо на HDD або якщо затримка sync висока. - Розгляньте стратегію кешування. Часто
primarycache=metadataдопомагає, якщо dataset великий і ARC був би забруднений даними гостей. - Вимірюйте затримку sync. Використовуйте sync-flush тести (Завдання 13) і спостерігайте zpool iostat під навантаженням (Завдання 9).
- Перевірте поведінку при відмові. Відновлення клієнта NFS і очікування гіпервізора можуть створити проблеми продуктивності, які виглядають як «сховище».
План C: метаданто-важкі збірки і дерева з кодом
- Пріоритезуйте метаданти. Розгляньте special vdev для метаданих/малих блоків.
- Використовуйте compression і atime=off. Зменшіть churn IO.
- Налаштуйте кешування атрибутів. Не ставте
actimeo=0, якщо не любите самонаведений біль. - Слідкуйте за CPU сервера і потоками nfsd. Збільшуйте потоки лише при чергуванні, а не за звичаєм.
- Забезпечте ARC простором для дихання. Кешування метаданту — ваш найкращий друг тут.
FAQ
1) Чи використовувати NFSv3 чи NFSv4.2?
За замовчуванням обирайте NFSv4.2 на сучасних Linux, якщо немає причин сумісності. NFSv3 може бути простішим і іноді легшим для дебагу, але фічі v4.x
часто зменшують «балаканину» і покращують позицію безпеки.
2) Які rsize/wsize слід використовувати?
Почніть з 1M, де підтримується. Якщо переговори відкотяться — ви побачите це в nfsstat -m. Якщо навантаження чутливе до затримки і з малими IO,
rsize/wsize не врятують вас від затримки sync — тут вирішують SLOG і дизайн пула.
3) Чи завжди корисний nconnect?
Часто корисний для пропускної здатності й паралелізму, особливо на швидких лінках і багатоядерних серверах. Але він збільшує стан з’єднань і може виявити конкуренцію на сервері.
Спробуйте 4 або 8, вимірюйте і не вважайте, що більше завжди краще.
4) Чи потрібен мені SLOG?
Якщо у вас sync-важкі навантаження (бази даних, образи VM, все що часто викликає fsync) і ваш пул не має вже низької затримки — так. Для all-flash пулів з
відмінною затримкою SLOG може не давати багато вигоди. Виміряйте sync-flush записи.
5) Чи можна просто поставити sync=disabled, щоб виправити продуктивність?
Можна, і це виглядатиме чудово — поки ви не впадете і не втратите підтверджені записи. Для тимчасових даних можливо. Для всього важливого — не робіть цього.
Виправте реальний шлях затримки замість цього.
6) Який recordsize ZFS слід використовувати для NFS-шарів?
Для загальних файло-шерів: 128K підходить. Для образів VM і баз даних: почніть з 16K або 32K. Для великих послідовних архівів: більший розмір може допомогти.
Правильне значення залежить від форми IO, а не від швидкості лінку.
7) Чи допомагає compression чи шкодить NFS-продуктивності?
Часто допомагає. Менше даних по диску і мережі, іноді краще використання кешу. lz4 — звичайний вибір. Якщо CPU завантажено і IO низький,
тоді варто протестувати, але не вимикайте compression із забобонів.
8) Чому мій NFS-share відчувається повільно лише в години пікового навантаження?
Черги і затори. Перевірте retransmits, завантаженість порту свічу, дропи інтерфейсу і softirq load на сервері. Сховище може бути в порядку; мережа може будувати черги, що підвищують хвостову затримку.
9) Чи варто використовувати special vdev?
Якщо ваше навантаження метаданто-важке або у вас мільйони дрібних файлів — special vdev на швидких SSD може дати радикальне покращення.
Але ставтеся до нього як до критичного vdev: дзеркаліть його і моніторте, бо втрата може ускладнити конфігурацію пула залежно від налаштувань.
10) Як дізнатися, чи вузьке місце на NFS-сервері чи в ZFS-пулі?
Подивіться на server-side nfsstat -s для міксу операцій і обсягу, потім зв’яжіть з zpool iostat. Якщо NFS-операції стрибають, а пул залишається простим,
підозрівайте CPU/потоки/мережу. Якщо IOPS і затримка пула зростають — підозрюйте дизайн сховища (sync-шлях, розклад vdev-ів, recordsize, промахи кеша).
Висновок: практичні подальші кроки
Якщо ви хочете, щоб ZFS поверх NFS відчувався як локальний диск, оптимізуйте під хвостову затримку і семантику, а не заради красивих графіків пропускної здатності.
Почніть з основ: підтвердіть маунти, підтвердіть здоров’я мережі, спостерігайте форму IO, потім узгодьте властивості ZFS dataset під робоче навантаження.
- Запустіть два швидкі клієнтські тести: sync-flush і послідовний throughput (Завдання 13 і 14). Визначте, чи боретеся ви із затримкою чи пропускною здатністю.
- Підтвердіть погоджені опції NFS і виправте невідповідності (Завдання 1–2). Не дебажте те, що фактично не налаштовано.
- Перевірте RTT мережі і retransmits (Завдання 3–4). Якщо пакети падають — тюнінг сховища це не вирішить.
- На сервері зіставте мікс NFS-операцій з поведінкою ZFS-пула (Завдання 7–9). Визначте, чи це метаданти, sync або сирий IO.
- Застосуйте цілеспрямовані зміни ZFS: recordsize під навантаження, compression увімкнений, atime off, і належний SLOG там, де sync має значення (Завдання 10–12).
Потім запишіть, що ви обрали і чому. Майбутній ви буде втомленим, на чергуванні і алергічним до загадкових ручок.