Якщо ви коли-небудь бачили хост ZFS з 256 ГБ RAM, який виглядає дивно «заповненим», при цьому продуктивність не змінюється, ви зустріли погану звичку ARC: кешувати дані, які не заслуговують на другий показ. ARC чудово вчиться, що вам знадобиться знову. Він також покірний. Якщо ви продовжуєте підгодовувати його навантаженням «прочитати один раз і ніколи більше», він охоче поглинатиме пам’ять і витіснятиме те, що дійсно важливо.
primarycache перестає бути приміткою і стає панеллю операційного керування. Правильно налаштований, він — скальпель: правила кешування на рівні датасету, які тримають ARC гарячим для метаданих і справді повторно використовуваних блоків, дозволяючи потоковим читанням і тимчасовим датасетам проходити повз, не перетворюючи RAM на музей учорашніх бекапів.
Що насправді контролює primarycache (і чого не контролює)
primarycache — це властивість датасету ZFS, яка визначає, що ZFS може поміщати в ARC (кеш у пам’яті). Вона має три значення:
all— кешувати в ARC як дані файлів, так і метадані (за замовчуванням)metadata— кешувати лише метадані (dnode, непрямі блоки тощо)none— нічого з цього датасету в ARC не кешувати
Звучить просто, але є дві тонкі операційні істини:
- Йдеться про допуск, а не про політику витіснення. Воно вирішує, які типи блоків з цього датасету мають право потрапити в ARC. Воно прямо не «фіксує» і не «пріоритизує» нічого.
- Це властивість на рівні датасету, успадковується і її легко зловживати. Вона потужна саме тому, що можна застосувати її до датасету з бекапами, не караючи датасет з віртуальними машинами. Але так само легко встановити її на батьківському рівні й забути, тихо підрубавши продуктивність для всього під ним.
Ще один нюанс: primarycache — не чарівний вимикач для «використовувати L2ARC замість цього». Це робить secondarycache. Ви можете встановити обидва, і вони взаємодіють, але вирішують різні задачі: допуск в ARC проти допуску в L2ARC.
І ще: встановлення primarycache=none не означає «ZFS ніколи не використовуватиме RAM для цього датасету». ZFS все одно використовує пам’ять для обліку, і ваш додаток все ще використовує page cache (на Linux), якщо ви не використовуєте direct I/O. ARC — лише один із кількох «ротів», що їдять RAM.
Жарт №1 (короткий і по темі): ARC — як стажер з чудовою пам’яттю, який ніколи не питає, навіщо він вчить весь телефонний довідник.
Як ARC «марнує» RAM у реальному житті
ARC, що марнує RAM, зазвичай не є багом. Це невідповідність між вашим навантаженням і припущеннями кешу.
ARC працює найкраще, коли:
- існує значуща тимчасова локальність (ви читаєте ті самі блоки знову найближчим часом), і/або
- високе повторне використання метаданих (обхід директорій, дрібні випадкові IO, метадані VM), і/або
- ваш робочий набір поміщається або майже поміщається в RAM.
ARC працює погано (або принаймні «дорого»), коли:
- ви потоково читаєте величезні файли один раз (бекапи, scrub, великі ETL-зчитування),
- робочий набір набагато більший за пам’ять, викликаючи постійне кружляння кешу,
- хост також запускає ресурсоємні сервіси (бази даних, JVM), яким ця RAM потрібна більше.
Як виглядає «марнування» операційно?
- Затримка не покращується після першого проходу, бо другого проходу немає.
- ARC росте, тому що ZFS робить свою роботу: бачить вільну пам’ять і використовує її.
- Інші процеси тісняться, що призводить до свопінгу, OOM-убивств або агресивного тиску на звільнення пам’яті.
- Коефіцієнт потраплянь в ARC виглядає непогано, але промахи все одно дорогі, оскільки промахи потрапляють у критичний шлях (часто це метадані або дрібні випадкові читання), а ваші «попадання» — це купа неважливих послідовних даних.
У багатьох інцидентах у продакшні перше неправильне припущення — що «коефіцієнт потраплянь кешу» — це одна цифра, яка може валідовувати всю систему. Не може. Ви можете мати пристойний коефіцієнт потраплянь і все одно програти, бо кеш заповнений малозначущими блоками.
Факти та історія: чому існує цей перемикач
Нижче — контекст, який робить цю властивість легшою для розуміння. Ось кілька конкретних фактів і історичних нотаток, які впливають на те, як primarycache поводиться в реальному житті:
- ZFS спроектовано з RAM як первинним рівнем продуктивності. Коли ZFS народжувався в Sun, великі сервери з великою пам’яттю були частиною цільової архітектури. ARC — не побічна ідея; він є серцем дизайну.
- ARC — це не просто кеш; це рушій політик. Він розбиває кеш на MRU/MFU (недавні проти частих) сегменти, щоб не обманюватися одноразовими сканами.
- Навіть із захистом від сканів, послідовні навантаження все одно заповнюють ARC. ARC може намагатися не знищувати ваш гарячий набір під час скану, але йому все одно потрібно вирішити, що допускати.
primarycache— це важіль «не допускати ці речі». - Ідея «лише метадані» старша за ZFS. Файлові системи давно визнавали локальність метаданих як великий виграш. ZFS формалізував це на рівні датасету.
- Датасети ZFS призначені бути межами політик. Властивості як
recordsize,compression,syncіprimarycacheіснують, щоб ви могли запускати змішані навантаження в одному пулі без того, щоб одне навантаження задавило інше. - L2ARC історично мав «податок на RAM». Збереження заголовків L2ARC в пам’яті колись було дорогим. Новіші реалізації знизили накладні витрати, але урок залишається: кешування ніколи не є безкоштовним.
- На Linux page cache і ARC можуть конкурувати. OpenZFS на Linux інтегровано обережно, але з оператора вигляду це все одно означає «існують два рівні кешування, якщо ви не використовуєте direct I/O».
- Recordsize взаємодіє з цінністю кешування. Великі записи роблять послідовну пропускну здатність щасливою, але вони також означають, що кожне допущення до кешу може бути важким. Ви можете швидше забруднити ARC великими record.
- Dedup споживає кеш навіть коли ви «не використовуєте кеш». Якщо ви увімкнули dedup, DDT хоче пам’яті. Це окрема вісь болю, яку
primarycacheне вирішить.
Моделі навантажень: коли застосовувати all, metadata або none
primarycache=all (за замовчуванням): для навантажень, які дійсно повторно використовують дані
Тримайте all, коли дані датасету повторно використовуються. Типові випадки:
- образи VM, де гості багаторазово торкаються тих самих блоків файлу
- бази даних з гарячими таблицями і індексами, що частково вміщуються в пам’ять
- домашні каталоги та дерева з вихідним кодом, де метадані + дрібні файли повторюються
- чутливі до затримки сервіси, які читають ті самі конфігурації/шаблони багаторазово
Операційний сигнал: коефіцієнт потраплянь ARC має корелювати з покращенням затримки для користувачів. Якщо після перезавантаження система «прогрівається» хвилинами або годинами, ARC виправдовує себе.
primarycache=metadata: недооцінений «золотий середній»
metadata — це моя стандартна відповідь для «цей датасет великий, переважно послідовний, але все ж потрібно обходитись каталогами і працювати зі снапшотами без страждань».
Чудові варіанти:
- репозиторії бекапів, де відновлення рідкісні, але операції переліків і снапшотів часті
- великі архіви медіафайлів: багато великих файлів, небагато повторних читань, але ви все ще переглядаєте
- Data lake: вузли обробки читають дані потоково раз на роботу
Що ви отримуєте: ARC зберігає «мозок» файлової системи, а не її масивне тіло. Обходи директорій, diff-си снапшотів і метадані-важкі операції залишаються швидкими, а потокові зчитування не витісняють справжні гарячі дані з інших датасетів.
primarycache=none: налаштування «карантин»
none не злочин. Це карантинна зона для датасетів, які ви точно знаєте як токсичні для кешу.
Підходить для:
- тимчасових просторів для одноразових пакетних експортувань
- стейджингу для отримань реплікацій (залежно від робочого процесу)
- потоків масового завантаження, де дані пишуться один раз і одразу відправляються кудись ще
Коли це повертається бумерангом: дрібні випадкові читання, метадані-важкі навантаження або будь-що із повторними читаннями. Якщо ви встановите none на датасет VM, бо «ARC великий», готуйтеся до болю з IOPS і здивованих колег.
Жарт №2 (короткий і по темі): Встановити primarycache=none на датасет VM — як прибрати стільці, щоб люди не сиділи: технічно ефективно, соціально катастрофічно.
Три корпоративні міні-історії (перемоги, поразки та один нудний герой)
Міні-історія №1: Інцидент через неправильне припущення (ARC ≠ «безкоштовна RAM»)
У середній компанії з змішаним віртуалізаційним кластером один хост почав свопити під час бізнес-годин. Графіки виглядали дивно: багато «available» пам’яті, але ядро агресивно робило reclaim, і латентність на API для клієнтів стрибнула.
На виклику зробили те, що багато хто робить під тиском: подивились на розмір ARC, побачили, що він великий, і вирішили «ZFS краде RAM». Зменшили максимально дозволений ARC на хості й розійшлись спати. Наступного дня стало тихіше — до наступного тижневого бекапу.
Під час вікна бекапу хост одночасно обслуговував читання VM і писав великий послідовний потік бекапу з датасету, який також зберігав деякі диски VM (бо «сховище — це сховище»). ARC, тепер обмежений, мав менше місця для гарячого набору VM. Бекап ішов щастливо, але VМи стали повільнішими, і скарги на латентність повернулись.
Неправильне припущення було не в тому, що «ARC використовує RAM». Неправильне припущення було в тому, що «розмір ARC — проблема». Насправді проблему створював бекап, що забруднював ARC і витискав гарячий набір VM. Вирішення — не морити ARC голодом; потрібно ізолювати політику: винести бекапи в окремий датасет і там встановити primarycache=metadata. ARC залишився великим, але тепер зберігав корисні речі.
Після цієї зміни затримка API знову стала нудною. Щотижневий бекап продовжував працювати. Без геройських подвигів. Просто одна властивість датасету, яка перетворила хаотичний кеш на дисциплінований.
Міні-історія №2: Оптимізація, що відбилась боком (надмірна «лише метадані»)
Інша організація мала інженера зі схильністю до чистих правил. Він вирішив: «дані бази даних ніколи не повинні кешуватися, бо база має власний кеш». Вони встановили primarycache=metadata на датасеті з PostgreSQL, очікуючи звільнити ARC для «важливіших речей».
На папері це виглядало захищено. На практиці це ігнорувало дві деталі: (1) не кожне читання бази даних потрапляє в буфер кеш бази, особливо під час розгортань і міграцій, та (2) кеш бази обмежений налаштуваннями пам’яті і конкуруючими робочими потоками, а не бажанням.
Вони не помітили цього одразу. Затримка під час звітних годин поступово зростала, потім під час міграції схеми, яка примусила великі читання індесів, все різко впало. Попит на IOPS різко зріс, а пул був на HDD з обмеженою випадковою продуктивністю. ARC міг би поглинути частину цього навантаження. Натомість кожен промах кеша ставав подією на диску.
Відкат був простий: повернути датасет до primarycache=all (і більш обачно налаштувати інші параметри). Урок: «додатки теж кешують» не означає, що кеш файлової системи зайвий. Це означає, що потрібно розуміти ієрархію кешів і режими відмов, особливо під час атипових операцій як міграції, VACUUM чи холодні рестарти.
Міні-історія №3: Нудна, але правильна практика, яка врятувала день (межі політик + тести)
Одна команда підприємства експлуатувала об’єктний стор на ZFS і набір NFS-експортів на тому ж пулі. Навантаження об’єктного стору були здебільшого великі послідовні читання і записи; NFS-експорти створювали багато дрібної метаданної активності від CI-джобів.
Вони зробили щось глибоко нецікаве: створили окремі датасети для кожного класу навантажень, документували потрібні властивості і контролювали їх простою перевіркою конфігурації в пайплайні провізії. Для об’єктних сторів: primarycache=metadata. Для NFS CI: primarycache=all. Для ефермерних staging: primarycache=none.
Через кілька місяців внутрішня команда запустила нову аналітику, яка в денний час читала десятки терабайтів послідовно. У багатьох компаніях це початок війни. Тут це стало неподією: джоб працював на датасеті, який вже був під карантином від кешування даних в ARC. CI-ферма залишилась швидкою. NFS-експорти не стали повільними. Єдиний «інцидент» — хтось запитав, чому нічого не загорілося.
Оце справжня перемога: нудна правильність. Не геройська нічна метушня з sysctl, а набір меж, які роблять непередбачувані навантаження менш небезпечними.
Практичні завдання: команди, інтерпретація та що змінювати
Нижче — практичні завдання, які ви можете виконати на типовій системі OpenZFS (приклади для Linux). Команди реалістичні; адаптуйте імена датасетів/пулів.
Завдання 1: Перелічити датасети і знайти налаштування primarycache
cr0x@server:~$ zfs get -r -o name,property,value,source primarycache tank
NAME PROPERTY VALUE SOURCE
tank primarycache all default
tank/vm primarycache all local
tank/backup primarycache metadata local
tank/backup/staging primarycache none local
Інтерпретація: Шукайте несподіване успадкування. Якщо у батьківського датасету none, усе під ним може тихо страждати. Стовпець SOURCE показує, чи властивість локальна, успадкована чи за замовчуванням.
Завдання 2: Перевірити secondarycache теж (допуск в L2ARC)
cr0x@server:~$ zfs get -r -o name,property,value,source secondarycache tank
NAME PROPERTY VALUE SOURCE
tank secondarycache all default
tank/backup secondarycache metadata local
Інтерпретація: Поширена корисна комбінація для бекапів — primarycache=metadata і secondarycache=metadata, що тримає і ARC, і L2ARC сфокусованими на метаданих.
Завдання 3: Безпечно змінити primarycache для одного датасету
cr0x@server:~$ sudo zfs set primarycache=metadata tank/backup
Інтерпретація: Це змінює майбутні допуски в ARC. Це не миттєво очистить уже закешовані дані з цього датасету. Очікуйте змін поведінки з часом, коли ARC оновлюватиметься.
Завдання 4: Підтвердити зміну і побачити успадкування
cr0x@server:~$ zfs get -o name,value,source primarycache tank/backup tank/backup/staging
NAME VALUE SOURCE
tank/backup metadata local
tank/backup/staging none local
Інтерпретація: Підтвердіть, що датасет, який вас цікавить, не успадковує те, про що ви забули.
Завдання 5: Виявити «токсичні для кешу» датасети за навантаженням (найактивніші)
cr0x@server:~$ zfs iostat -v tank 5 3
capacity operations bandwidth
pool alloc free read write read write
-------------------------- ----- ----- ----- ----- ----- -----
tank 48.2T 21.7T - - - -
raidz2-0 48.2T 21.7T 980 430 1.20G 210M
sda - - 120 55 150M 28M
sdb - - 115 54 148M 27M
...
-------------------------- ----- ----- ----- ----- ----- -----
cr0x@server:~$ zfs iostat -v tank/backup 5 3
capacity operations bandwidth
dataset alloc free read write read write
-------------------------- ----- ----- ----- ----- ----- -----
tank/backup 22.1T - 820 40 1.05G 18M
-------------------------- ----- ----- ----- ----- ----- -----
Інтерпретація: Якщо датасет робить величезний послідовний bandwidth читань/записів, він є відмінним кандидатом для primarycache=metadata або none залежно від повторного використання.
Завдання 6: Спостерігати розмір ARC і базову поведінку
cr0x@server:~$ cat /proc/spl/kstat/zfs/arcstats | egrep "^(size|c |c_min|c_max|hits|misses|mru_hits|mfu_hits|demand_data_hits|demand_data_misses|demand_metadata_hits|demand_metadata_misses) " | head -n 20
size 4 68719476736
c 4 82463372032
c_min 4 17179869184
c_max 4 103079215104
hits 4 9812334401
misses 4 554332110
mru_hits 4 431228001
mfu_hits 4 9272116400
demand_data_hits 4 7122331100
demand_data_misses 4 431002200
demand_metadata_hits 4 2690000000
demand_metadata_misses 4 12329910
Інтерпретація: Не поклоняйтеся одній метриці hit ratio. Порівнюйте demand data та demand metadata. Якщо пропуски метаданих високі і затримка страждає, ймовірно вам потрібно більше кешування метаданих, а не менше.
Завдання 7: Спостерігати поведінку ARC під час потокової роботи
cr0x@server:~$ for i in {1..5}; do
> awk '
> /^(size|hits|misses|demand_data_hits|demand_data_misses|demand_metadata_hits|demand_metadata_misses)/ {print}
> ' /proc/spl/kstat/zfs/arcstats | paste - - - - - - -;
> echo "----";
> sleep 5;
> done
size 4 69123481600 hits 4 9813334401 misses 4 554532110 demand_data_hits 4 7123331100 demand_data_misses 4 431202200 demand_metadata_hits 4 2690100000 demand_metadata_misses 4 12339910
----
size 4 69811097600 hits 4 9815334401 misses 4 555032110 demand_data_hits 4 7127331100 demand_data_misses 4 431802200 demand_metadata_hits 4 2690200000 demand_metadata_misses 4 12349910
----
Інтерпретація: Під час потокового читання ви можете бачити, як demand data misses зростають, тоді як hits не допомагають пізніше. Це підпис для «перестаньте кешувати дані цього датасету».
Завдання 8: Перевірити тиск пам’яті і свопінг (чи конкурує ARC з вашими додатками?)
cr0x@server:~$ free -h
total used free shared buff/cache available
Mem: 251Gi 182Gi 4.1Gi 2.0Gi 65Gi 18Gi
Swap: 16Gi 1.2Gi 14Gi
cr0x@server:~$ vmstat 1 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
4 0 123456 4200000 90000 61200000 0 0 120 900 3200 8800 28 10 59 3 0
5 0 123456 3800000 90000 60800000 0 0 110 950 3300 9100 27 11 58 4 0
Інтерпретація: Використання swap плюс низький «available» — ознака, що потрібно переглянути політику кешування. ARC може бути великим і при цьому допустимим, але якщо ваші додатки піддаються пагінгу, ви платите «орендну плату» двічі.
Завдання 9: Визначити, чи датасет переважно послідовний (швидка вибірка)
cr0x@server:~$ iostat -x 1 3
Device r/s rkB/s rrqm/s %rrqm r_await rareq-sz w/s wkB/s w_await wareq-sz aqu-sz %util
sda 120.0 155000.0 0.2 0.2 7.10 1291.7 55.0 28500.0 9.80 518.2 0.92 88.0
Інтерпретація: Великий rareq-sz і високий throughput вказують на потокове читання. Тут часто перемагає primarycache=metadata, особливо якщо повторні читання рідкісні.
Завдання 10: Зміряти реальне до/після з холодним кешом (обережно)
Це небезпечно в продакшні, якщо бути недбалим. Але ви можете тестувати з конкретним файлом і контрольованими читаннями. Використовуйте некритичний датасет або тестовий хост.
cr0x@server:~$ sudo zfs set primarycache=all tank/testseq
cr0x@server:~$ dd if=/tank/testseq/bigfile.bin of=/dev/null bs=16M status=progress
21474836480 bytes (21 GB, 20 GiB) copied, 22 s, 976 MB/s
cr0x@server:~$ sudo zfs set primarycache=metadata tank/testseq
cr0x@server:~$ dd if=/tank/testseq/bigfile.bin of=/dev/null bs=16M status=progress
21474836480 bytes (21 GB, 20 GiB) copied, 22 s, 974 MB/s
Інтерпретація: Якщо продуктивність не змінюється, але забруднення ARC зменшується, ви знайшли «безкоштовні гроші». Потокові читання часто не виграють від кешування, але вони можуть витісняти цінні дані.
Завдання 11: Перевірити властивості датасету, що підсилюють ризик забруднення кешу
cr0x@server:~$ zfs get -o name,property,value recordsize,compression,atime,logbias,primarycache tank/backup
NAME PROPERTY VALUE SOURCE
tank/backup recordsize 1M local
tank/backup compression zstd local
tank/backup atime off local
tank/backup logbias throughput local
tank/backup primarycache metadata local
Інтерпретація: Великий recordsize підходить для бекапів, але також означає, що кожен закешований record великий. Поєднання великих записів з primarycache=metadata часто є розумним способом запобігти перетворенню RAM на музей бекапів.
Завдання 12: Знайти датасети з успадкованим «none» (тихий вбивця продуктивності)
cr0x@server:~$ zfs get -r -H -o name,value,source primarycache tank | awk '$2=="none" || $3=="inherited" {print}'
tank/staging none local
tank/staging/tmp none inherited
Інтерпретація: Якщо щось важливе успадковує none, це випадкова політика продуктивності. Виправляйте на правильному рівні (перевизначення для дитини або виправлення батька).
Завдання 13: Підтвердити ліміти ARC (не боріться з ОС сліпо)
cr0x@server:~$ cat /sys/module/zfs/parameters/zfs_arc_max
109951162777
cr0x@server:~$ cat /sys/module/zfs/parameters/zfs_arc_min
17179869184
Інтерпретація: Якщо ви занадто обмежили ARC, ви можете примусово викликати читання з диска для гарячих метаданих. Використовуйте primarycache, щоб покращити якість ARC, перш ніж зменшувати його розмір.
Завдання 14: Підтвердити бажану політику на дереві (виявлення дрейфу)
cr0x@server:~$ zfs get -r -o name,value,source primarycache tank | egrep "tank/(vm|backup|staging)"
tank/vm all local
tank/backup metadata local
tank/staging none local
Інтерпретація: Це звичка SRE: перевірити, що реальність відповідає вашій ментальній моделі. Більшість аварій кешу походить від «ми думали, що це встановлено», а не від поганої теорії.
Швидкий план діагностики
Це шлях «повільно і люди дивляться на вас». Порядок кроків спрямований на швидке знаходження ймовірного вузького місця, а не на академічну повноту.
Крок 1: Чи система страждає від браку пам’яті або свопить?
cr0x@server:~$ free -h
cr0x@server:~$ vmstat 1 5
cr0x@server:~$ swapon --show
Що шукати: низький показник available пам’яті, активність своп-ін/своп-аут і симптоми як випадкові паузи. Якщо відбувається свопінг, вирішіть, чи політика допуску ARC (primarycache) забруднює пам’ять, чи вам реально потрібно більше RAM.
Крок 2: Чи пул I/O-забитий чи CPU-завантажений?
cr0x@server:~$ iostat -x 1 5
cr0x@server:~$ zpool iostat -v 1 5
Що шукати: високу %util пристрою, високе await і черги. Якщо диски завантажені, тюнінг ARC може допомогти тільки якщо ви підвищите коефіцієнт потраплянь для релевантних даних/метаданих. Якщо CPU завантажений (компресія, контрольні суми), зміни кешування не вирішать проблему обчислювальної насиченості.
Крок 3: Чи ARC допомагає навантаженню, яке вам важливе?
cr0x@server:~$ cat /proc/spl/kstat/zfs/arcstats | egrep "^(hits|misses|demand_data_hits|demand_data_misses|demand_metadata_hits|demand_metadata_misses|size|c )"
Що шукати: Чи високі пропуски метаданих? Чи зростають demand data misses під час потокової роботи? Якщо так, розгляньте встановлення primarycache=metadata на датасеті, що виконує потоковий I/O.
Крок 4: Визначити датасет, що викликає кружляння
cr0x@server:~$ zfs iostat -v tank 2 10
Що шукати: Який датасет/пул штовхає bandwidth/IOPS. Зв’яжіть це з бізнес-контекстом (бекапи, аналітика, сховище VM) і застосуйте політику кешування відповідно.
Крок 5: Застосувати таргетовану зміну (малий радіус впливу)
cr0x@server:~$ sudo zfs set primarycache=metadata tank/backup
Що шукати: Зменшення кружляння ARC і покращена стабільність для інших навантажень. Не змінюйте спочатку zfs_arc_max, якщо ви не на межі; спочатку виправте, що допускається, перед тим як зменшувати кеш.
Типові помилки (симптоми та виправлення)
Помилка 1: Встановлення primarycache=none на «повільне сховище» (і зробити його ще повільнішим)
Симптоми: Штормові завантаження VM стають гіршими, дрібні випадкові читання різко зростають у латентності, метадані-важкі операції повільніють, коефіцієнт потраплянь ARC падає для значущих читань.
Виправлення: Відновіть primarycache=all для датасетів з повторним використанням (VM, бази даних) і карантинуйте тільки потокові датасети. Якщо потрібно захистити ARC від сканів, ставте primarycache=metadata на бекап/архівні датасети замість повного виключення кешування.
Помилка 2: Застосування політики кеша на неправильному рівні (пастка успадкування)
Симптоми: «Ми змінили, але нічого не покращилося» або «чому датастор VM змінив поведінку?»
Виправлення: Використовуйте zfs get -r ... source. Виправляйте батьківський датасет, якщо політика повинна бути широкою; перевизначайте в дочірньому, якщо це виняток. Документуйте очікуване дерево успадкування.
Помилка 3: Плутанина primarycache з secondarycache
Симптоми: Ви додали L2ARC-пристрій і бачите мало користі; ARC все одно заповнюється сміттям.
Виправлення: Пам’ятайте: primarycache контролює допуск в ARC, secondarycache контролює допуск в L2ARC. Для потокових датасетів розгляньте primarycache=metadata і secondarycache=metadata, а не надію «L2ARC мене врятує».
Помилка 4: Надмірна оптимізація під hit ratio замість латентності
Симптоми: Після зміни дашборд виглядає «краще», але користувачі скаржаться більше.
Виправлення: Сприймайте hit ratio як підказку, а не як KPI. Фокусуйтеся на demand metadata misses, хвостовій латентності і глибині черги на диску. Кешуйте неважливі дані — і ви можете підняти hits, виснажуючи реальні робочі навантаження.
Помилка 5: Ігнорування recordsize і узгодження з навантаженням
Симптоми: ARC швидко зростає під час масових операцій; тиск пам’яті зростає; мало приросту продуктивності.
Виправлення: Великий recordsize плюс потокові читання часто означає «масове забруднення кешу». Використовуйте primarycache=metadata на таких датасетах і тримайте великі записи там, де вони потрібні (бекап/архів), а не на навантаженнях з випадковим I/O.
Помилка 6: Боротьба з ARC max/min перед виправленням якості допуску
Симптоми: Ви знижуєте ARC max, щоб «звільнити пам’ять», але продуктивність стає нестабільною, пропуски метаданих ростуть, і I/O на диску зростає.
Виправлення: Спочатку припиніть допускати сміття за допомогою primarycache. Потім, якщо потрібно обмежити ARC для сусідніх навантажень, робіть це обережно і перевіряйте поведінку пропусків метаданих.
Контрольні списки / покроковий план
Контрольний список A: Визначити правильне значення primarycache для датасету
- Класифікуйте датасет: VM/бази даних, загальні файлові шари, бекапи, архів, scratch.
- Задайте одне жорстке питання: «Чи перечитаємо ми ті самі блоки протягом годин?»
- Якщо так: почніть з
primarycache=all. - Якщо здебільшого ні, але метадані важливі: виберіть
primarycache=metadata. - Якщо це одноразовий/викидний потік: розгляньте
primarycache=none. - Підтвердіть за допомогою
zfs iostatі ARC-статистики під час реального вікна роботи.
Контрольний список B: Впроваджувати обережно (мінімальний радіус впливу)
- Підтвердіть шлях датасету і дерево успадкування:
cr0x@server:~$ zfs list -r tank cr0x@server:~$ zfs get -r -o name,value,source primarycache tank - Змінюйте лише один датасет за раз:
cr0x@server:~$ sudo zfs set primarycache=metadata tank/backup - Спостерігайте 15–60 хвилин (або за одним запуском завдання):
cr0x@server:~$ zfs iostat -v tank 5 cr0x@server:~$ cat /proc/spl/kstat/zfs/arcstats | egrep "^(size|hits|misses|demand_metadata_misses|demand_data_misses)" - Занотуйте результат: затримка, своп, disk
await, поведінку ARC. - Якщо допомогло, формалізуйте це (infra-as-code, шаблони провізії або runbook).
Контрольний список C: Розділити навантаження, щоб політика кешу працювала
- Створюйте датасети за класом навантажень, а не за організаційною схемою.
- Тримайте бекапи/архіви поза деревом VM.
- Застосовуйте
primarycacheна межі датасету, де навантаження однорідні. - Проводьте аудит щоквартально на предмет «хтось підкинув нове навантаження в неправильний датасет».
FAQ
1) Чи впливає зміна primarycache на вже закешовані дані миттєво?
Ні. Вона впливає на те, що допускатиметься надалі. Існуючі записи в ARC мають віджити по мірі оновлення кешу. Якщо потрібен миттєвий ефект, операційний підхід зазвичай — чекати на оновлення або планувати зміни до важкого завдання, а не примусово очищати кеші в продакшні.
2) Чи варто встановлювати primarycache=metadata для всіх бекапів?
Часто так, бо бекапи — класичні «прочитати один раз» потоки, які можуть забруднити ARC, тоді як метадані важливі для перегляду, керування снапшотами та вибору відновлення. Але якщо ви регулярно відновлюєте однакові підмножини (тестові відновлення, часті часткові відновлення), ви можете отримати вигоду від кешування деяких даних — виміряйте це.
3) Чи правильне використання primarycache=none колись?
Так, для по-справжньому викидних датасетів (scratch, staging) або для робочих процесів, де кешування явно шкодить важливішим навантаженням. Помилка — використовувати none як універсальну відповідь на «ZFS використовує забагато RAM».
4) У чому різниця між primarycache і secondarycache простими словами?
primarycache вирішує, що може потрапити в RAM (ARC). secondarycache вирішує, що може потрапити в L2ARC (зазвичай SSD). Ви можете сказати ZFS «лише метадані» для обох, щоб обидва рівні кешу були сфокусовані на структурі файлової системи, а не на об’ємних даних.
5) Чи прискорить primarycache=metadata записи?
Прямо — ні. Це стосується кешування читань. Однак опосередковано це може покращити загальну стабільність системи і зменшити тиск пам’яті, що може допомогти системам з великою кількістю записів, які страждали від reclaim чи свопінгу. Записи більше залежать від ZIL/SLOG, налаштувань груп транзакцій, затримки пристроїв і sync-параметрів.
6) Якщо мій додаток має власний кеш (Redis, PostgreSQL shared_buffers), чи варто вимикати кеш даних ARC?
Не автоматично. Багато додатків кешують дещо добре, а дещо — погано, і вони не покривають холодний старт або атипові операції. Файлова система часто допомагає з індексами, бінарниками, спільними бібліотеками і активністю ОС. Сприймайте primarycache як інструмент для робочого навантаження: тестуйте зміни під реальними операціями (включно з рестартами, міграціями і піковими навантаженнями).
7) Чому ARC все одно росте, якщо я встановлю primarycache=metadata на великий датасет?
Бо інші датасети можуть все ще кешувати дані, метадані теж можуть бути значними, і ARC тримає різні внутрішні структури. Також ріст ARC не обов’язково поганий; погано, коли він витісняє цінніші споживачі пам’яті або коли заповнений низькоцінними блоками.
8) Яка найпростіша «хороша» політика за замовчуванням для змішаного пулу?
Тримайте primarycache=all для VM/баз даних і інтерактивних файлових шарів. Використовуйте primarycache=metadata для бекапів/архівів. Для scratch/staging, що справді одноразові, — primarycache=none. Справжня хитрість не в значеннях, а в створенні датасетів, що чітко розділяють навантаження.
9) Чи можна виправити забруднення ARC без зміни primarycache?
Іноді можна. ARC спроектовано, щоб протистояти забрудненню від сканів, і ви також можете керувати лімітами ARC. Але primarycache — найчистіший політичний інструмент на рівні датасету. Якщо проблема в тому, що «цей датасет ніколи не повинен витрачати RAM на дані», не покладайтеся на глобальні евристики.
10) Як зрозуміти, чи метадані — вузьке місце?
Дивіться на demand metadata misses в arcstats і корелюйте з латентністю під час обходів директорій, операцій зі снапшотами і роботою з дрібними файлами. Якщо пропуски метаданих ростуть і диски зайняті, ваша проблема швидше за все в кешуванні метаданих, а не в об’ємних даних.
Висновок
primarycache — одна з тих властивостей ZFS, що виглядає як дрібна перевага, поки ви не експлуатуєте змішаний пул довший час. Тоді вона стає межею: різницею між ARC як високорозумним рівнем продуктивності і ARC як збирачем мотлоху з необмеженою шафою.
Практичний підхід простий: розділяйте навантаження на датасети, які мають сенс, тримайте primarycache=all там, де дані реально повторно використовуються, і використовуйте primarycache=metadata (або інколи none), щоб зупинити потокові та викидні навантаження від витіснення вашого справжнього гарячого набору. Робіть це за допомогою вимірювань, а не інтуїції. У продакшні «нудно і правильно» перемагає «хитро і глобально» щоразу.