Ви перезавантажуєте сервер — і він знову швидкий. Через два тижні все повторюється: операції запису зависають, латентність зростає, бази даних “таємниче” таймаутяться, а ваші дашборди нагадують сейсмограф. Диск “здоровий”, CPU майже без навантаження, а команда застосунку впевнена, що ви щось змінили. Ви не змінювали. SSD зробив це.
Цей режим відмови частий на серверах з Ubuntu 24.04: продуктивність SSD/NVMe поступово деградує, коли карта вільних блоків диска ускладнюється, збирач сміття (GC) виконує більше роботи, а TRIM/discard або не відбувається, або не доходить до фізичного пристрою. Хороша новина: ви можете довести це за допомогою чітких вимірювань і виправити так, щоб можна було перевірити результат.
Як виглядає уповільнення в реальних системах
Не всі повідомлення про “повільний NVMe” стосуються TRIM/GC. Але патерн “погіршується з часом” — це індикатор. Ось як зазвичай проявляється, коли discard/TRIM не ефективний:
- Латентність записів поступово зростає під постійним навантаженням, особливо при випадкових записах і змішаному читанні/записі.
- Періодичні спайки латентності (сотні мілісекунд до секунд), навіть коли застосунок не насичує пропускну здатність.
- Перезавантаження або тривалий простій тимчасово покращують продуктивність. (Деякі диски агресивніше виконують фоновий GC у простій; перезавантаження також може змінити патерни навантаження і дати час на простій.)
- Вільного місця у файловій системі достатньо, але пристрій поводиться так, ніби він повний. Ось у чому річ: поняття “вільно” у SSD відрізняється від поняття файлової системи, якщо TRIM не повідомляє про вільні блоки.
- iowait не обов’язково високий. Достатньо кількох потоків, що блокуються на зберіганні, щоб зруйнувати SLO.
Більшість команд виявляють це однаково: продакшн-система, яка була “в порядку” при запуску, перетворюється на генератор інцидентів повільного характеру. Першим інстинктом звично звинувачують базу даних, потім ядро, потім хмару, потім інтерна. Не робіть так. Почніть з перевірки, чи повідомляється SSD про те, які блоки більше не використовуються.
Цікаві факти та історичний контекст (коротко й по суті)
- Ранні споживчі SSD могли сильно втратити продуктивність після того, як їх один раз заповнили, бо мали обмежений overprovisioning і примітивний збирач сміття.
- TRIM було введено, щоб вирівняти уявлення файлової системи про вільні блоки з уявленням SSD. Без нього SSD повинен вважати, що кожен записаний блок все ще потрібен.
- “Garbage collection” на флеші — не опція: сторінки можна читати й записувати, але стирання відбувається більшими erase-блоками, тому перезапис вимагає переміщення даних.
- Write amplification — ворог, якого ви не бачите: невеликий запис з боку хоста може спричинити багато внутрішніх записів, коли SSD змушений консолідувати валідні сторінки.
- NVMe покращив латентність і паралелізм, але це не відміняє фізику. GC все ще існує; він просто працює при вищих IOPS і інколи з різкішими провалами.
- Linux давно підтримує TRIM, але “підтримка” ≠ “увімкнено наскрізь”. LUKS, LVM, dm-crypt, device-mapper та віртуалізоване сховище можуть блокувати discards, якщо їх не налаштувати.
- Монтування з опцією continuous discard історично було суперечливим, бо могло додавати накладні витрати й фрагментацію; періодичний fstrim став нудним, але ефективним стандартом у багатьох дистрибутивах.
- Деякі масиви зберігання та хмарні блочні пристрої ігнорують discards або транслюють їх так, що фізичний простір не звільняється. Гостьова ОС думає, що допомогла; бекенд не дуже переймається.
Швидкий план діагностики (перший/другий/третій)
Це версія “на вас дзвонить опція”. Мета — не ідеальний аналіз; мета — знайти вузьке місце за хвилини й вирішити, чи варто гнатися за TRIM/GC або шукати іншу причину.
Перший крок: упевніться, що проблема в збереженні, а не в CPU/пам’яті
- Перевірте
iostatна предмет латентності пристрою (await) і завантаження. - Перевірте IO по процесах за допомогою
pidstatабо метрик застосунку. - Шукайте патерн: латентність зростає протягом днів/тижнів, а не раптове стрибкоподібне падіння після розгортання.
Другий крок: підтвердьте існування шляху TRIM end-to-end
- Чи увімкнений і успішний
fstrim.timer? - Чи файлова система підтримує discard? Чи блочний рівень приймає discards?
- Чи використовуєте LUKS/LVM/MD RAID, де discards можуть бути вимкнені або заблоковані?
Третій крок: відтворіть і виміряйте контрольованим навантаженням
- Використайте
fioдля послідовного тесту випадкових записів (акуратно, на не-продакшн цілі або запасному розділі). - Запустіть
fstrim, потім повторіть тест і порівняйте розподіл латентності, а не тільки середню пропускну здатність MB/s.
Якщо після TRIM показники p95/p99/p99.9 суттєво покращилися або IOPS витримуються довше перед провалом, у вас є винуватець: диск страждав від нестачі чистих блоків.
Доведіть, що це TRIM/GC: вимірювання без суперечок
Дебати про TRIM і garbage collection легко перетворюються на містичні натяки. Не беріть у цьому участі. Надайте докази, які відповідають на одне питання: чи зменшує інформування пристрою про звільнені блоки симптоми write amplification і латентність?
Важливі дві речі:
- Розподіл латентності (p95/p99/p99.9), а не тільки середня пропускна здатність. Біль GC часто проявляється як спайки.
- До/після події discard (ручний fstrim або контрольований workload з discard), використовуючи той самий профіль навантаження.
Також майте на увазі, чим TRIM не є:
- Це не магічна “дефрагментація” для SSD.
- Воно не миттєво стирає клітини; воно маркує сторінки як недійсні, щоб SSD міг пізніше ефективно стерти блоки.
- Воно не вирішить помираючий диск, перевантажений контролер або зламану чергування.
Одне висловлювання варто повісити на стіну, бо воно описує потрібну вам операційну позицію:
«Надія — не план.» — Генерал Гордон Р. Салліван
Тепер до справи: конкретні завдання з командами, очікуваними виводами і рішенням щодо наступних кроків.
Практичні завдання: команди, очікуваний вивід та що вирішити далі
Ці кроки розташовані приблизно в тому порядку, в якому я б їх виконував на сервері Ubuntu 24.04 із підозрою на «SSD повільніший з часом». Команди реальні і готові до виконання. Виводи репрезентативні; у вас будуть інші назви пристроїв.
Завдання 1: Визначте фактичний(і) блочний(і) пристрій(и)
cr0x@server:~$ lsblk -o NAME,TYPE,SIZE,FSTYPE,MOUNTPOINTS,MODEL,ROTA,DISC-MAX,DISC-GRAN
NAME TYPE SIZE FSTYPE MOUNTPOINTS MODEL ROTA DISC-MAX DISC-GRAN
nvme0n1 disk 1.8T /dev/nvme0n1 0 2G 4K
├─nvme0n1p1 part 512M vfat /boot/efi
└─nvme0n1p2 part 1.8T crypto
└─vg0-root lvm 300G ext4 /
Що це означає: Ви на NVMe (ROTA=0), і стек включає LUKS crypto + LVM. Саме там часто тихо вмирають discards.
Рішення: Потрібно перевірити підтримку discard через dm-crypt і LVM, а не тільки файлову систему.
Завдання 2: Перевірте тип файлової системи та опції монтування (discard vs periodic)
cr0x@server:~$ findmnt -no SOURCE,FSTYPE,OPTIONS /
/dev/mapper/vg0-root ext4 rw,relatime,errors=remount-ro
Що це означає: Немає опції discard при монтуванні. Це не обов’язково помилка; Ubuntu часто покладається на періодичний fstrim.
Рішення: Не додавайте discard автоматично. Спочатку перевірте, чи увімкнений і працює періодичний TRIM.
Завдання 3: Чи увімкнений щотижневий TRIM timer?
cr0x@server:~$ systemctl status fstrim.timer
● fstrim.timer - Discard unused blocks once a week
Loaded: loaded (/usr/lib/systemd/system/fstrim.timer; enabled; preset: enabled)
Active: active (waiting) since Mon 2025-12-22 00:12:01 UTC; 1 weeks 1 days ago
Trigger: Mon 2025-12-29 00:28:14 UTC; 1 days ago
Triggers: ● fstrim.service
Що це означає: Таймер увімкнений і запланований. Це необхідна, але не достатня умова.
Рішення: Перевірте результат останнього запуску. Таймер може бути увімкнений, але кожного разу невдало завершуватись.
Завдання 4: Чи fstrim справді успішно пройшов останнім разом?
cr0x@server:~$ journalctl -u fstrim.service -n 50 --no-pager
Dec 29 00:28:14 server systemd[1]: Starting fstrim.service - Discard unused blocks on filesystems from /etc/fstab...
Dec 29 00:28:14 server fstrim[32107]: /: 0 B (0 bytes) trimmed on /dev/mapper/vg0-root
Dec 29 00:28:14 server systemd[1]: fstrim.service: Deactivated successfully.
Dec 29 00:28:14 server systemd[1]: Finished fstrim.service - Discard unused blocks on filesystems from /etc/fstab.
Що це означає: Trimmed 0 B. Це може означати “нічого звільнити” або “discard не проходить”, або “файлова система вважає, що нічого не вільно”, або “ви на віртуальному блоці, який ігнорує discards”. На зайнятому сервері 0 B тиждень за тижнем — підозріло.
Рішення: Перевірте підтримку discard на блочному рівні та через dm-crypt/LVM. Також запустіть ручний trim і подивіться, чи щось зміниться.
Завдання 5: Переконайтесь, що пристрій повідомляє про здатність приймати discard
cr0x@server:~$ cat /sys/block/nvme0n1/queue/discard_max_bytes
2147483648
Що це означає: Сировинний NVMe-пристрій приймає discards до 2 GiB на команду. Добре.
Рішення: Якщо ви не віддаєте trim, то не через обмеження NVMe. Причина — програмний стек не надсилає discards або не пропускає їх вниз.
Завдання 6: Перевірте, чи dm-пристрій підтримує discard
cr0x@server:~$ cat /sys/block/dm-0/queue/discard_max_bytes
0
Що це означає: Ваш dm-пристрій (ймовірно LVM LV або dm-crypt маппінг) не рекламує discard. Ось чому fstrim повідомляв 0 байт: discard заблоковано вище, ніж NVMe.
Рішення: Перевірте конфігурації dm-crypt і LVM. Ймовірно, потрібно ввімкнути discards для LUKS (allow-discards) і впевнитися, що LVM їх не блокує.
Завдання 7: Підтвердьте налаштування dm-crypt для discard
cr0x@server:~$ sudo cryptsetup status nvme0n1p2
/dev/mapper/nvme0n1p2 is active and is in use.
type: LUKS2
cipher: aes-xts-plain64
keysize: 512 bits
key location: keyring
device: /dev/nvme0n1p2
sector size: 512
offset: 32768 sectors
size: 3906250000 sectors
mode: read/write
flags:
Що це означає: Жодних прапорців не показано. Якби allow-discards були увімкнені, ви зазвичай побачили б це в flags.
Рішення: Заплануйте контрольовану зміну, щоб увімкнути discards у crypttab (або повторно відкрити мапінг з discard), і після цього перевірте, чи dm почне рекламувати discard.
Завдання 8: Перевірте конфігурацію /etc/crypttab
cr0x@server:~$ sudo cat /etc/crypttab
nvme0n1p2 UUID=9f3d7b2a-2c42-4e47-b2c6-7d92a4e5a8a1 none luks,discard
Що це означає: У цьому прикладі вже вказано discard. Якщо у вас його немає — dm-crypt за замовчуванням блокує discards.
Рішення: Якщо відсутня — додайте discard (або allow-discards, залежно від інструментів) і заплануйте перезавантаження або обслуговування для безпечного пере-відкриття мапінгу.
Завдання 9: Перевірте, що LVM не є вузьким місцем для discard
cr0x@server:~$ sudo lvs -o lv_name,vg_name,lv_attr,segtype,devices
LV VG Attr Type Devices
root vg0 -wi-ao---- linear /dev/mapper/nvme0n1p2(0)
Що це означає: Лінійний LV — це ок. Thin-пули та snapshot-и ускладнюють семантику discard.
Рішення: Якщо бачите thin-pool або інтенсивне використання snapshot-ів, потрібно перевірити підтримку discard у такій конфігурації і розглянути періодичний fstrim в гостьовій ОС плюс коректне проходження discards на хості.
Завдання 10: Запустіть ручний fstrim і інтерпретуйте результат
cr0x@server:~$ sudo fstrim -av
/boot/efi: 256.4 MiB (268783616 bytes) trimmed on /dev/nvme0n1p1
/: 112.7 GiB (121011388416 bytes) trimmed on /dev/mapper/vg0-root
Що це означає: Ось як виглядає “працюючий trim”: ненульові байти, особливо для root. Якщо ваш журнал раніше показував 0 B, а тепер ви бачите великі trim-результати — ви щойно знайшли зламаний розклад або шлях, який було виправлено.
Рішення: Якщо trim тепер працює — перейдіть до доведення покращення продуктивності (fio + iostat). Якщо fstrim і далі показує 0 B, але ви точно видаляєте дані — продовжуйте шукати: шлях discard все ще зламаний або ваше навантаження не звільняє блоки у спосіб, видимий для trim.
Завдання 11: Спостерігайте латентність і завантаження під час повільного періоду
cr0x@server:~$ iostat -x 1 10
Linux 6.8.0-41-generic (server) 12/30/2025 _x86_64_ (16 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
3.12 0.00 1.45 2.10 0.00 93.33
Device r/s rkB/s rrqm/s %rrqm r_await rareq-sz w/s wkB/s wrqm/s %wrqm w_await wareq-sz aqu-sz %util
nvme0n1 5.00 220.0 0.00 0.00 2.40 44.00 310.00 18432.0 120.00 27.91 38.50 59.46 12.40 98.00
Що це означає: %util близько 98% з w_await ≈ 38 ms вказує, що пристрій насичений і записи чекають. Якщо це зростає з часом при однаковому навантаженні — GC підозрілий.
Рішення: Захопіть цей “поганий” базовий стан, потім порівняйте одразу після успішного fstrim і короткого простою.
Завдання 12: Перевірте NVMe SMART / стан, щоб виключити очевидні проблеми з диском
cr0x@server:~$ sudo nvme smart-log /dev/nvme0n1
Smart Log for NVME device:nvme0n1 namespace-id:ffffffff
critical_warning : 0x00
temperature : 43 C
available_spare : 100%
available_spare_threshold : 10%
percentage_used : 3%
data_units_read : 123,456,789
data_units_written : 98,765,432
host_read_commands : 3,210,987,654
host_write_commands : 2,109,876,543
controller_busy_time : 9,812
power_cycles : 27
power_on_hours : 2,144
unsafe_shutdowns : 1
media_errors : 0
num_err_log_entries : 0
Що це означає: Без критичних попереджень, невеликий знос (percentage_used). Це підсилює ідею, що диск не ламається; він просто виконує внутрішні роботи під навантаженням.
Рішення: Якщо бачите media errors, critical warnings або високий percentage_used — спочатку розглядайте апаратні проблеми. TRIM не врятує помираючий SSD.
Завдання 13: Виміряйте продуктивність контрольованим fio job (до TRIM)
Робіть це тільки на безпечній цілі (тестовий LV, запасний розділ або виділений файл на не-критичній файловій системі). Якщо ви спрямовуєте fio на продакшн дані без роздумів, ви не SRE — ви приклад для попередження.
cr0x@server:~$ sudo fio --name=randwrite --filename=/var/tmp/fio.test --size=8G --direct=1 --ioengine=libaio --bs=4k --rw=randwrite --iodepth=32 --numjobs=1 --runtime=60 --time_based --group_reporting
randwrite: (groupid=0, jobs=1): err= 0: pid=4123: Tue Dec 30 11:12:01 2025
write: IOPS=18.2k, BW=71.2MiB/s (74.7MB/s)(4272MiB/60001msec); 0 zone resets
slat (nsec): min=1500, max=180512, avg=6210.3, stdev=3341.2
clat (usec): min=80, max=215000, avg=1732.4, stdev=8200.7
lat (usec): min=90, max=215020, avg=1738.8, stdev=8201.1
clat percentiles (usec):
| 1.00th=[ 120], 5.00th=[ 150], 10.00th=[ 170], 50.00th=[ 320],
| 90.00th=[ 1400], 95.00th=[ 3800], 99.00th=[20000], 99.90th=[120000]
cpu : usr=3.10%, sys=12.40%, ctx=1123456, majf=0, minf=12
IO depths : 1=0.1%, 2=0.2%, 4=0.5%, 8=1.2%, 16=7.0%, 32=91.0%, >=64=0.0%
Що це означає: Середня латентність виглядає “непогано”, але хвости p99 і p99.9 — страшні. Саме ці довгі хвости шкодять базам даних і SLO API. Такий патерн сумісний зі GC-сталлерами.
Рішення: Запустіть fstrim (якщо можливо), за потреби дайте кілька хвилин простою, потім повторіть той самий fio job і порівняйте перцентилі.
Завдання 14: Trim, а потім повторіть fio (після TRIM)
cr0x@server:~$ sudo fstrim -v /
/: 112.7 GiB (121011388416 bytes) trimmed on /dev/mapper/vg0-root
cr0x@server:~$ sudo fio --name=randwrite --filename=/var/tmp/fio.test --size=8G --direct=1 --ioengine=libaio --bs=4k --rw=randwrite --iodepth=32 --numjobs=1 --runtime=60 --time_based --group_reporting
randwrite: (groupid=0, jobs=1): err= 0: pid=4188: Tue Dec 30 11:16:01 2025
write: IOPS=28.9k, BW=113MiB/s (118MB/s)(6780MiB/60001msec); 0 zone resets
slat (nsec): min=1500, max=110220, avg=5901.1, stdev=2987.4
clat (usec): min=70, max=42000, avg=980.2, stdev=1400.3
lat (usec): min=78, max=42012, avg=986.1, stdev=1400.5
clat percentiles (usec):
| 1.00th=[ 110], 5.00th=[ 140], 10.00th=[ 160], 50.00th=[ 280],
| 90.00th=[ 980], 95.00th=[ 1700], 99.00th=[ 5200], 99.90th=[16000]
Що це означає: Хвостова латентність значно покращилась. Диск витрачає менше часу на переміщення валідних сторінок під час записів, бо в нього більше попередньо стертих блоків.
Рішення: Тепер ви “довели” гіпотезу: стан TRIM/GC впливає на продуктивність. Перейдіть до постійних виправлень: забезпечте надійну обробку discards і зважте операційні практики, щоб не тримати диски на 95% заповнення.
Завдання 15: Переконайтесь, що continuous discard не увімкнений (і вирішіть, чи потрібен)
cr0x@server:~$ mount | grep ' on / '
/dev/mapper/vg0-root on / type ext4 (rw,relatime,errors=remount-ro)
Що це означає: Опції монтування не містять discard. Це нормально, якщо працює періодичний trim.
Рішення: Віддавайте перевагу періодичному fstrim для серверів загального призначення. Використовуйте continuous discard лише для специфічних робочих навантажень, де ви виміряли користь і накладні витрати прийнятні.
Завдання 16: Перевірте вільне місце й ризик переповнення
cr0x@server:~$ df -hT /
Filesystem Type Size Used Avail Use% Mounted on
/dev/mapper/vg0-root ext4 295G 271G 10G 97% /
Що це означає: 97% заповнено. Для багатьох SSD це зона провалу продуктивності, навіть з TRIM, бо диску залишається менше місця для wear leveling і GC.
Рішення: Вільне місце — це функція продуктивності. Ціль — 70–85% використання для записо-інтенсивних систем або додати ємність. Якщо фінансовий відділ проти — назвіть це “страхуванням від латентності”.
Жарт №1: Керувати SSD на 97% заповнення — як проводити навчальну евакуацію під час реальної пожежі: технічно це вправа, практично — поганий день.
Виправлення, які працюють (і чому)
Є три категорії виправлень, і зазвичай потрібно щонайменше два з них:
- Зробіть так, щоб TRIM реально відбувався (періодично або постійно) наскрізь через ваш стек.
- Дайте SSD простір для дихання (не тримайте диск майже повним; зменшіть churn на “гарячих” томах).
- Не ускладнюйте GC без потреби (налаштування навантаження та файлової системи, розумна черговість, уникнення патологічних шарів).
Виправлення 1: Увімкніть і перевірте періодичний fstrim (те, що зазвичай має бути)
В Ubuntu 24.04 періодичний TRIM зазвичай забезпечується через fstrim.timer. Ви хочете, щоб він був увімкнений і щоб він повідомляв ненульові результати на системах, де дані видаляються/перезаписуються.
cr0x@server:~$ sudo systemctl enable --now fstrim.timer
Created symlink /etc/systemd/system/timers.target.wants/fstrim.timer → /usr/lib/systemd/system/fstrim.timer.
Перевірте, що він запускається:
cr0x@server:~$ systemctl list-timers --all | grep fstrim
Mon 2026-01-05 00:28:14 UTC 5 days left Mon 2025-12-29 00:28:14 UTC 1 day ago fstrim.timer fstrim.service
Потім перевірте вивід:
cr0x@server:~$ sudo journalctl -u fstrim.service --since "14 days ago" --no-pager | tail -n 20
Dec 29 00:28:14 server fstrim[32107]: /: 112.7 GiB (121011388416 bytes) trimmed on /dev/mapper/vg0-root
Якщо він завжди тримає 0 B — не святкуйте. Ви обрізуєте повітря.
Виправлення 2: Забезпечте проходження discards через dm-crypt (LUKS), якщо ви використовуєте шифрування
dm-crypt блокує discards за замовчуванням з вагомих причин: discards можуть витікати інформацію про те, які блоки використовуються. Багато продакшн-середовищ приймають цей компроміс, бо продуктивність і передбачуваність латентності важливіші за прихованість шаблонів розподілу даних.
Що робити: Додайте discard у /etc/crypttab (або переконайтесь, що він там є), після чого перезавантажте або безпечно пере-відкрийте мапінги у вікні обслуговування. Після цього підтвердіть, що /sys/block/dm-*/queue/discard_max_bytes ненульовий.
Перевірка — обов’язкова: якщо dm все ще рекламує 0, SSD і далі вас не чує.
Виправлення 3: Віддавайте перевагу періодичному fstrim над монтуванням з discard (у більшості випадків)
Опція монтування discard відправляє discards постійно під час звільнення блоків. Це може бути корисно при деяких стійких churn-навантаженнях, але може також додати накладні витрати, особливо для файлових систем з великою кількістю дрібних видалень, і погано взаємодіяти з деякими реалізаціями пристроїв.
Мій упереджений дефолт:
- Використовуйте періодичний
fstrimдля ext4/xfs на серверах. - Розгляньте continuous
discardтільки якщо:- ви виміряли, що періодичний trim недостатній, і
- ваше навантаження має постійний churn і суворі SLO по латентності, і
- ви перевірили накладні витрати під навантаженням.
Виправлення 4: Перестаньте тримати SSD “майже повними”
Це звучить як проблема бюджету, але насправді це інженерна проблема в маскуванні бюджету.
- Для записо-інтенсивних томів ціль — 15–30% вільного простору як операційний буфер.
- Уникайте великих монолітних root-томів, що збирають усе. Розділіть гарячі шляхи запису на виділені томи, де можна керувати простором і поведінкою trim.
- Якщо ви використовуєте thin provisioning — моніторьте використання пулу, наче це rota у виклику на чергуванні, бо так і є.
Виправлення 5: Давайте диску іноді просто відпочити (так, серйозно)
Багато SSD ефективніше виконують фоновий GC під час простою. Це не заміна для TRIM, але може зменшити серйозність спайків латентності.
Якщо ваш сервер завантажений 24/7 постійними записами, ви змушуєте GC виконуватися в foreground. Це можна пом’якшити вирівнюванням записів (агрегація на рівні застосунку, черги) або масштабуванням, щоб кожен диск отримував час для “подиху”.
Виправлення 6: Узгодьте файлові системи та стек так, щоб семантика discard працювала
Деякі конфігурації ускладнюють discard:
- LVM thin pools: discards можуть потребувати явної підтримки. Thin provisioning плюс інтенсивний churn — класична ситуація “виглядає нормально, поки не стане погано”.
- Повсюдні snapshot-и: snapshot-и утримують старі блоки, тобто ваші видалення фактично не звільняють місце на нижньому рівні. Trim може не відображати реального reclaimable простору.
- Віртуалізовані диски: discards можуть ігноруватись або відкладатись. Гість може робити все правильно і все одно не впливати на фізичне медіа.
Жарт №2: Сховища як лазанья — кожен додатковий шар робить її смачнішою, поки ви не зрозумієте, що дебагати сир.
Три корпоративні міні-історії (анонімізовано, правдоподібно і технічно коректно)
Міні-історія 1: Інцидент через хибне припущення
Вони мігрували флот серверів Ubuntu з SATA SSD на блискучі NVMe. Міграція пройшла гладко, і перші тижні були щасливі: латентність впала, дашборди виглядали спокійно, і всі в чаті вітали один одного. Через шість тижнів почалися алерти: p99 латентності записів бази даних вертикально зростала у часи піку. На чергуванні зробили звичний танець — перевірили CPU, пам’ять, мережу, звинуватили ORM, потім дивились на iostat як на співучасника. NVMe показував високе завантаження і довгі записи уочікування, але нічого “не було зламано”. SMART був чистий. Тож вони масштабували інстанси. Було краще тимчасово, потім знову повернулося.
Хибне припущення було тонким: “NVMe швидкий, тож house-keeping не матиме значення.” Вони не помітили, що нове зібрання використовує шифрування LUKS з дефолтними налаштуваннями, і discards були заблоковані. fstrim запускався щотижня і повідомляв успіх, але зрізав 0 байт кожного разу. Ніхто не помічав, бо “Finished successfully” — це те, що люди тренуються неправильно читати.
Коли вони ввімкнули discards у dm-crypt і перевірили /sys/block/dm-*/queue/discard_max_bytes, таймер почав справді тримати простір. Наступний період піку все ще мав навантаження, але латентні провали зникли. Пункти постмортему: не “купити швидші диски”, а “перевіряти проходження discard наскрізь у золотому образі”.
Міні-історія 2: Оптимізація, яка відкотилася
Інша організація мала pipeline ingest-логів, що писав постійно: дрібні файли, постійні видалення, великий metadata churn. Хтось прочитав, що mount з discard тримає SSD у формі. Тож вони змінили монтування лог-тома на continuous discard. Бенчмарків не робили, бо “це ж просто discard”.
Через дні пропускна здатність ingest впала, системний час CPU виріс. Диск не виглядав насиченим по пропускній здатності, але латентність стала шумнішою. Вони фактично перемістили роботу discard у гарячий шлях: постійні дрібні discards, постійні додаткові команди пристрою і більше накладних витрат на кожне видалення. SSD отримував повідомлення про вільний простір тисячі разів на секунду, ніби колега, який настирно коментує кожний натиск клавіші.
Вони відкотили до періодичного fstrim і запланували trim у непіковий час. Пропускна здатність повернулася, CPU заспокоївся, а SSD і далі отримував потрібну інформацію — просто пачками, де накладні витрати амортизовані.
Урок: continuous discard не є злом, але це регулятор, який залежить від навантаження. Увімкнувши його у всіх підряд за політикою, ви не налаштовуєте — ви намагаєтесь пощастити.
Міні-історія 3: Нудна, але правильна практика, яка врятувала день
Команда платіжного шлюзу мала ненаглядну практику: кожна зміна, що стосувалась зберігання, вимагала чеклісту “доведи це”. Не документ для аудиторів — а справжній інженерний ритуал. Вони вимірювали p95/p99 латентність запису синтетичним fio-профілем, який імітував їхню базу даних. Записували до змін, після змін і знову через два тижні.
Після переходу на Ubuntu 24.04 числа були нормальні в перший день. Через два тижні запланований бенчмарк показав, що хвости латентності поволі піднімаються. Не катастрофа, але тривожна тенденція. Оскільки це виявив рутинний моніторинг, у них був час розслідувати без активного інциденту.
Вони виявили, що для зручності використовували нову thin-provisioned LVM-структуру. Discards з файлової системи не звільняли простір у thin pool так, як очікувалось, і пул перегрівався. Вони спростили макет (для тома бази даних), забезпечили періодичний trim і ввели бюджет вільного простору. Без героїки, без пейджів о другій ночі.
Нічого в цій історії не цікаве. У цьому й суть. Нудна практика — вимірювати зараз і вимірювати пізніше — врятувала їх від цікавої проблеми зі сховищем.
Поширені помилки: симптом → причина → виправлення
Цей розділ — накопичений рубець досвіду. Зіставте ваш симптом з імовірною причиною, потім перевірте за завданнями вище.
1) fstrim “успішно” запускається, але завжди тримає 0 байт
- Симптом: журнал показує
/: 0 B trimmedтиждень за тижнем. - Причина: Discards заблоковано dm-crypt, LVM, налаштуваннями thin pool або бекенд ігнорує discards.
- Виправлення: Перевірте
/sys/block/*/queue/discard_max_bytesдля реального пристрою джерела монтування. Увімкніть discards у crypttab, підтвердіть, що dm рекламує discard, повторно запустітьfstrim -av.
2) Після перезавантаження продуктивність покращується, а потім знову деградує
- Симптом: фольклор “перезавантаження фіксує це”, що повторюється кожні кілька тижнів.
- Причина: Диск отримав час простою або змінились умови черги; основна проблема — відсутність TRIM або хронічно майже повний стан, що викликає GC під навантаженням.
- Виправлення: Доведіть за допомогою fio до/після ручного trim; увімкніть періодичний trim; підтримуйте вільний простір.
3) NVMe виглядає здоровим, але p99 записів жахливий
- Симптом: SMART нормальний, помилок носія немає, але довгі хвости латентності.
- Причина: Foreground GC через недостатність чистих блоків; write amplification; пристрій працює на високому завантаженні в змішаному навантаженні.
- Виправлення: Забезпечте ефективний TRIM; зменшіть рівень заповнення; розділіть навантаження (логи vs БД); перевірте чергування та налаштування планувальника.
4) Continuous discard увімкнений і продуктивність погіршилась
- Симптом: Зростання CPU sys time, падіння пропускної здатності, шумніша латентність при workload з частими видаленнями.
- Причина: Накладні витрати discard у гарячому шляху; надто багато дрібних discards.
- Виправлення: Приберіть опцію монтування
discard; використайте періодичнийfstrim.timer; плануйте trims у непікові години.
5) TRIM працює на bare metal, але не в VM
- Симптом: Гість запускає fstrim, повідомляє про trim, але хост-пристрій все одно деградує; або гість показує 0 байт.
- Причина: Гіпервізор/бекенд не пропагує discards; тип віртуального диска не підтримує їх; поведінка провайдера хмари.
- Виправлення: Перевірте підтримку discard на рівні віртуалізації. Якщо discards не проходять, використайте механізми звільнення на хості або прийміть, що потрібна резервна ємність і періодична репровізія.
6) Thin provisioning вдаряє по стіні
- Симптом: Thin pool або бекенд заповнюється, продуктивність падає, trims не звільняють простір.
- Причина: Discards не передаються в thin pool, snapshot-и закріплюють блоки або пул перепризначений і недостатньо моніториться.
- Виправлення: Перевірте налаштування thin discard; зменшіть збереження snapshot-ів; моніторьте data% thin pool як критичне SLO; тримайте вільний простір.
Контрольні списки / покроковий план
Ось операційний план, який можна передати в чергування без додаткового душевного навантаження.
Чекліст A: Доведіть, що проблема в TRIM/GC (30–90 хв)
- Зніміть базовий стан латентності пристрою під час “поганого” періоду (
iostat -xта p99 латентність записів застосунку). - Підтвердіть можливість discard на сировинному пристрої (
/sys/block/nvme*/queue/discard_max_bytes). - Підтвердіть можливість discard на фактичному джерелі монтування (зазвичай
dm-*). - Запустіть
sudo fstrim -avі зафіксуйте trimmed bytes по монтах. - Запустіть контрольований fio-тест і зафіксуйте p95/p99 перцентилі.
- Повторіть fio після fstrim (і короткого простою) з тими ж параметрами.
- Якщо хвостова латентність суттєво покращилась: вважайте TRIM-шлях і бюджет вільного простору як ціль виправлення.
Чекліст B: Зробіть TRIM надійним (вікно обслуговування)
- Увімкніть
fstrim.timerі перевірте, що він запланований. - Переконайтесь, що
/etc/crypttabмістить опції discard, якщо ви використовуєте LUKS і ваша модель загроз це дозволяє. - Перезавантажте або безпечно пере-відкрийте dm-crypt мапінги за потреби.
- Підтвердіть, що
/sys/block/dm-*/queue/discard_max_bytesненульовий. - Одного разу вручну запустіть
fstrim -avі підтвердіть ненульові trims. - Відстежуйте тижневі журнали fstrim і отримуйте алерти, якщо на томах з інтенсивним churn він постійно тримає 0 байт.
Чекліст C: Тримайте це виправленим (поточна гігієна)
- Встановіть цілі по ємності: тримайте 15–30% вільного простору на гарячих томах.
- Розділяйте записо-інтенсивні навантаження по томах/пристроях, якщо можливо.
- Запишіть стандартний fio-профіль для вашого середовища і перезапускайте його щомісяця (або після оновлень ядра/змін у стеку зберігання).
- Моніторьте NVMe SMART: температуру, critical warnings, media errors, percentage_used.
- Моніторьте перцентилі латентності, а не тільки пропускну здатність і середній await.
Питання й відповіді (FAQ)
1) Чому продуктивність SSD/NVMe погіршується з часом взагалі?
Бо флеш-пам’ять вимагає стирання перед записом на блоці. Коли SSD не може знайти чисті блоки, він мусить перемістити валідні дані (GC) перед записом. Без TRIM SSD вважає більше сторінок валідними, ускладнюючи GC і збільшуючи write amplification та спайки латентності.
2) Хіба NVMe не має бути “завжди швидким”?
NVMe — це протокол і інтерфейс, оптимізований під паралелізм і низькі накладні витрати. Він не змінює фізику NAND флеш-пам’яті. Швидкий інтерфейс може лише пришвидшити падіння з обриву.
3) Чи слід монтувати ext4 з discard на Ubuntu 24.04?
Зазвичай ні. Віддавайте перевагу періодичному fstrim.timer. Використовуйте continuous discard тільки після бенчмаркування і лише на томах, де шаблони видалення і вимоги латентності це виправдовують.
4) Як часто запускати fstrim?
Щотижня — розумний дефолт. Для високочастотних churn-навантажень можна запускати щодня під час непікового часу. Вимірюйте: якщо продуктивність деградує за дні, тримайте частіше або виправте рівень заповнення й навантаження.
5) Чи працює TRIM через шифрування LUKS?
Може працювати, але лише якщо увімкнено. dm-crypt може блокувати discards, поки його не налаштувати (зазвичай через discard в /etc/crypttab). Увімкнення може витікати шаблони розподілу блоків, тож вирішіть, виходячи зі своєї моделі безпеки.
6) Я запустив fstrim і він багато чого обрізав. Чи це погано для ресурсу SSD?
TRIM сам по собі не записує дані; він повідомляє SSD, що блоки більше не потрібні. Насправді це може знизити write amplification, допомагаючи SSD ефективніше очищувати простір. Більший ризик для ресурсу — постійний write amplification від роботи майже на повному диску без ефективного TRIM.
7) Чому fstrim показує 0 байт на завантаженому сервері, де ми щодня видаляємо дані?
Поширені причини: discards заблоковані dm-crypt/LVM; thin provisioning або snapshot-и утримують блоки “використаними”; бекенд ігнорує discards (деякі віртуальні диски); або ваше навантаження перезаписує in-place без звільнення extent-ів у спосіб, видимий для trim.
8) Чи можу я “скинути” SSD, щоб відновити продуктивність?
Деякі диски підтримують secure erase або формат, що повертає пристрій у початковий стан, але це руйнівно. Неруйнівний підхід: переконайтеся, що TRIM працює, підтримуйте вільний простір і уникайте патологічних стеків, які блокують discards.
9) Мій диск лише на 3% використаний (SMART percentage_used), чому він повільний?
SMART percentage_used — це показник зношення, а не заповнення. Диск може бути майже новим, але з поганою продуктивністю, якщо його логічно тримають майже повним при постійних записах без ефективного TRIM і велике внутрішнє GC.
10) Чи потрібно змінювати I/O scheduler для NVMe на Ubuntu 24.04?
Зазвичай ні; сучасні ядра за замовчуванням обирають розумні опції (часто none для NVMe). Тюнінг планувальника не компенсує диск, який змушений виконувати важкий foreground GC. Спочатку виправте discard і вільний простір, потім налаштовуйте, якщо потрібно.
Висновок: практичні наступні кроки
Якщо ваш Ubuntu 24.04 SSD/NVMe стає повільнішим з часом, ставтеся до цього як до інженерної проблеми, а не фольклору. Доведіть гіпотезу вимірюваннями до/після: той самий fio job, той самий пристрій, з і без успішного trim. Якщо хвостова латентність покращується після trim — припиніть суперечки і почніть фіксити шлях discard наскрізь.
Наступні кроки в порядку пріоритету:
- Перевірте ланцюжок discard: підтримка discard у raw NVMe, потім у dm-пристрої, потім вивід fstrim.
- Зробіть fstrim надійним: увімкніть таймер, підтвердіть ненульові trims з часом, налаштуйте алерти якщо він тихо нічого не робить.
- Виправте структурну проблему: припиніть тримати write-heavy томи на 95–99% заповнення; це самостійно нанесений податок на латентність.
- Зберігайте чеки: зберігайте базовий fio-профіль і перезапускайте його після оновлень, змін образів і модифікацій стеку зберігання.
Диск продовжуватиме виконувати garbage collection. Ваше завдання — тримати її у фоновому режимі, де це місце її праці.