Тонкие настройки производительности на старом железе.
Профиль машины: 2 ядра CPU ~1.3 ГГц, 4 ГБ RAM, 4 механических диска в пуле ZFS raidz1, загрузка с USB-флешки.
# loader.conf vfs.zfs.arc_max=1G
ARC по умолчанию растёт до ~половины RAM — на 4 ГБ это неприемлемо, конкурирует за память с остальными сервисами. Дальнейшее занижение ниже 1G не имеет смысла — теряется эффективность кэша без ощутимого выигрыша в свободной памяти.
| Датасет | primarycache | Причина |
|---|---|---|
| pool root | metadata | директории/ACL, выигрывает вся файловая иерархия, включая SMB |
| датасет с активно перечитываемыми данными | all (local override) | реальный выигрыш от кэша данных |
| датасет с данными “пишем раз — не перечитываем” (архив бэкапов, транзитное шифрованное хранилище) | metadata | не вытеснять из маленького ARC то, что реально нужно |
zfs set primarycache=metadata tank zfs set primarycache=all tank/active_data
| Параметр | Значение | Причина |
|---|---|---|
| compression | off | бэкап уже сжат средствами клиента резервного копирования |
| recordsize | 1M | крупные последовательные файлы — меньше метаданных/чек-сумм на объём |
| logbias | throughput | приоритет пропускной способности при больших последовательных записях |
| primarycache | metadata | данные пишутся раз, почти не перечитываются |
`compression=off` — если через датасет проходят уже зашифрованные блоки (см. статью про Syncthing, тип папки receive-encrypted): зашифрованные данные несжимаемы, попытка сжатия — чистые потери CPU.
zfs set xattr=sa redundant_metadata=most tank
Не на USB-флешку (загрузочный носитель): медленно под нагрузкой, ограниченный ресурс перезаписи флеш-памяти (свопинг ускоряет деградацию носителя, который одновременно и загрузочный).
Не на zvol ZFS-пула: запись в своп идёт через ZFS-стек, которому самому нужна память на I/O (ARC, транзакционные группы) — риск дедлока под давлением памяти.
Правильный вариант — raw-разделы (не zvol), собранные в RAID0 через `gstripe`, мимо ZFS-стека целиком:
Механизма создания разделов в GUI нет, поэтому нужно работать через CLI:
gpart add -t freebsd-swap -a 1m -s 2g -l swap0 ada0 gpart add -t freebsd-swap -a 1m -s 2g -l swap1 ada1 gpart add -t freebsd-swap -a 1m -s 2g -l swap2 ada2 gpart add -t freebsd-swap -a 1m -s 2g -l swap3 ada3 gstripe label -v swap0 /dev/ada0p2 /dev/ada1p2 /dev/ada2p2 /dev/ada3p2
Регистрация в XigmaNAS: System → Advanced → Swap, Type = Device, Device = `/dev/stripe/swap0`.
Ограничение ZFS raidz: ужать раздел под живым raidz-vdev нельзя (расширение поддерживается — RAIDZ expansion, обратная операция нет). Разметку под своп на тех же дисках, что и raidz-пул, закладывать заранее при создании пула — иначе единственный путь получить место под неё, это пересоздать пул.
Объём: ориентир “2× RAM” для legacy-железа; если нужен kernel core dump — своп не меньше объёма RAM.
На слабом CPU/дисках приоритет — короче худший случай задержки отклика, а не пиковая пропускная способность. Актуально при потоке мелких операций записи (много мелких файлов разом).
| Параметр | Дефолт | Значение | Требует ребута | Причина |
|---|---|---|---|---|
| vfs.zfs.txg.timeout | 5с | 1с | Нет (live sysctl) | Короче окно накопления транзакционной группы — короче потенциальный стопор на её фиксации |
| vfs.zfs.dirty_data_max_percent | 10% от RAM | 5% | Да — read-only tunable, только через loader.conf | Меньше данных копится в памяти перед принудительным сбросом на диск |
| vfs.zfs.vdev.async_write_max_active | 10 | 3 | Нет (live sysctl) | Глубина очереди записи на vdev — на старых дисках без развитого NCQ большая очередь удлиняет отклик для операций, ожидающих за длинной очередью |
| vfs.zfs.vdev.sync_write_max_active | 10 | 3 | Нет (live sysctl) | То же для синхронных записей |
# loader.conf / sysctl.conf vfs.zfs.txg.timeout=1 vfs.zfs.dirty_data_max_percent=5 vfs.zfs.vdev.async_write_max_active=3 vfs.zfs.vdev.sync_write_max_active=3
arc_min — не трогать. Может казаться логичным зафиксировать минимальный размер ARC, чтобы не проседал под нагрузкой, но на машине с и так туго рассчитанной памятью это забирает у ARC возможность сжаться и отдать память другим процессам именно тогда, когда она нужнее всего (при пиковой нагрузке). Оставлять `arc_min` неактивным — ARC пусть сам решает, когда сжаться.
`kern.maxvnodes` — верхняя граница живых vnode в системе. Если по дереву датасета проходит live filesystem watcher (см. статью про тюнинг Syncthing — секция про fsWatcher/kqueue) или просто идёт операция над деревом с сотнями тысяч мелких файлов/директорий, число vnode может подступить к лимиту — система начинает агрессивно вытеснять vnode, что способно сериализовать файловые операции по всей системе, а не только у процесса-триггера.
Диагностика: `sysctl kern.maxvnodes vfs.numvnodes` — если `numvnodes` устойчиво держится близко к `maxvnodes` во время нагрузки, лимит тесен. Поднять его — не панацея (каждый vnode — расход памяти ядра), но если основная причина нагрузки на дерево устранена на уровне приложения (например, отключением live-watcher), поднимать лимит обычно не требуется.
Значение в GUI/loader.conf/sysctl.conf не гарантированно применяется на живой системе. Встречается:
Проверка: `sysctl <параметр>` на живой системе после любой правки loader.conf/sysctl.conf — не доверять только факту наличия строки в конфиге.
AAM (Automatic Acoustic Management), уровень 1–127: 1 — минимальный шум, 127 — максимальная производительность/шум.
ataidle /dev/ada0 # проверка поддержки и текущего значения ataidle -A 1 /dev/ada0 # тихий режим ataidle -A 127 /dev/ada0 # полная производительность
Расписания в GUI нет — через cron:
0 23 * * * root for d in ada0 ada1 ada2 ada3; do /usr/local/sbin/ataidle -A 1 /dev/$d; done 0 6 * * * root for d in ada0 ada1 ada2 ada3; do /usr/local/sbin/ataidle -A 127 /dev/$d; done
| Параметр | Значение | Причина не менять |
|---|---|---|
| APM диска | максимальная производительность | сервер с бэкапами, экономия питания не приоритет |
| HDD standby timer | задаётся в минутах, не в секундах | при частом фоновом обращении к дискам (мониторинг раз в несколько минут) порог простоя физически не достигается |
| Power Mode CPU | adaptive | не проседает на всплесках нагрузки (в отличие от minimum), не расходует лишнее (в отличие от maximum) |