АйТи Фреш
Главная / Статьи / Серверы и хостинг
Серверы и хостинг

Заменили диски на 4К-секторы, а ZFS стал писать медленнее: что на самом деле делает ashift

Автор: Семёнов Евгений Сергеевич, директор ООО «АйТи-Фреш» · · ~27 мин чтения
Заменили диски на 4К-секторы, а ZFS стал писать медленнее: что на самом деле делает ashift
Иллюстрация к статье «Заменили диски на 4К-секторы, а ZFS стал писать медленнее: что на самом деле делает ashift».

Эта статья для тех, кто держит ZFS под файловый сервер, репозиторий резервных копий или гипервизор — и однажды поменял старые диски на новые, а получил не прирост, а просадку. Разберу, что такое ashift на пальцах, почему свойство пула ashift никогда не переделает уже созданный vdev, как за пять минут выяснить настоящую геометрию своих пулов и что делать дальше — с реальным выездом, цифрами и командами. И отдельно скажу, где паника оправдана, а где вам просто продали страшилку.

Купили диски побольше — получили сервер помедленнее

Классика жанра: пул собран лет восемь-десять назад на дисках по 2 ТБ, место кончилось, купили комплект по 8 ТБ. Меняем по одному через zpool replace, ресильвер отрабатывает, zpool status зелёный, места стало втрое больше. А ночной бэкап, который укладывался в сорок минут, теперь идёт два часа. Пользователи жалуются на «тормозит папка». И самое обидное — на старых дисках такого не было.

Дальше человек гуглит, натыкается на слово ashift, видит, что у него 9, а у новых дисков сектор 4 КиБ, и делает очевидное: zpool set ashift=12 tank. Перезагружает сервер. Ничего не меняется. Пробует ещё раз выдернуть диск и заменить его — уже «с правильным ashift». Опять ничего. На этом месте ко мне обычно и приходят.

Разберёмся, что вообще такое ashift. Это двоичный показатель размера сектора: значение 9 означает 2^9 = 512 байт, 12 — это 2^12 = 4096 байт, 13 — 8192 байта. По документации OpenZFS допустимы значения от 9 до 16 включительно, плюс 0 — значение по умолчанию: автоопределение по данным блочного уровня ядра и внутреннего списка исключений ZFS (туда занесены модели, которые заведомо врут о размере сектора). Ashift задаёт минимальную единицу размещения данных на vdev и выравнивание записи. Не размер блока файла (это recordsize) и не размер блока zvol (volblocksize), а именно «квант» физического ввода-вывода.

И вот ключевая механика, из-за которой всё ломается. Руководство OpenZFS по тюнингу формулирует это прямо: частичная запись сектора влечёт штраф — сектор сначала нужно прочитать в буфер, и только потом записать. Если пул считает, что сектор равен 512 байтам, а физически диск оперирует блоками по 4 КиБ, то каждая запись в 512 байт превращается в «прочитай 4 КиБ — измени 512 байт — запиши 4 КиБ обратно». На SSD это ещё и лишний цикл записи, на шпинделе — лишний оборот пластины, то есть 5–8 мс на ровном месте. На RAIDZ, где одна логическая запись раскладывается на все диски группы, штраф множится на число дисков.

Свойство пула ashift и фактический ashift конкретного vdev — это две разные сущности с одинаковым именем. Половина ошибок в этой теме растёт именно отсюда.
Цифры и версии: Купили диски побольше — получили сервер помедленнее — схема
Цифры и версии: Купили диски побольше — получили сервер помедленнее. Открыть схему в полном размере

Почему zpool set ashift=12 не чинит уже созданный пул

Открываем man zpoolprops(7) и читаем про ashift буквально: «Changing this value will not modify any existing vdev, not even on disk replacement» — изменение этого значения не модифицирует ни один существующий vdev, даже при замене диска. И следом: «When set, this property is used as the default hint value in subsequent vdev operations (add, attach and replace)» — оно используется как значение-подсказка по умолчанию для последующих операций add, attach и replace.

То есть свойство пула — это не настройка, а заготовка на будущее. Оно повлияет на новый top-level vdev, который вы добавите командой zpool add. Оно повлияет на новый диск, который вы прицепите в новое зеркало. А вот существующая группа дисков, созданная в 2016 году с ashift=9, останется с ashift=9 навсегда. Внутренний ashift верхнего vdev фиксируется в момент создания этого vdev, пишется в его метку на диске и не меняется никогда — ни скрабом, ни ресильвером, ни экспортом-импортом, ни обновлением ZFS.

Проверяется это тремя способами. Первый и самый честный — zdb, документация прямо рекомендует смотреть реальное значение именно им. Второй — свойства vdev: в vdevprops(7) есть read-only свойство ashift с описанием «The physical sector size of this vdev expressed as the power of two», то есть физический размер сектора vdev, выраженный как степень двойки. Третий — метка диска, zdb -l.

# фактический ashift каждого top-level vdev в пуле
zdb -C tank | grep -E 'ashift|children|type'

# то же самое через свойства vdev (read-only)
zpool get ashift tank raidz2-0

# что записано в метке конкретного диска
zdb -l /dev/disk/by-id/ata-TOSHIBA_MG08ADA800E_XXXXXXXX-part1 | grep ashift

# а это — всего лишь подсказка на будущее, не текущее состояние
zpool get ashift tank

Если zpool get ashift tank показывает 12, а zdb -C tank в описании vdev показывает ashift: 9 — поздравляю, вы нашли свою проблему. Свойство переставили, геометрию не тронули. И zpool replace -o ashift=12 тут тоже не поможет: да, в zpool-replace(8) опция -o property=value есть и там прямо сказано, что единственное поддерживаемое сейчас свойство — ashift, но диск встаёт в уже существующий vdev и обязан жить по его правилам. Подсказка применяется, когда создаётся новая геометрия, а не когда вы вставляете диск в старую. Зато текущие версии zpool status сами подсвечивают такую ситуацию: у каждого затронутого диска появляется пометка block size: 512B configured, 4096B native, а в шапке — «One or more devices are configured to use a non-native block size. Expect reduced performance.» с рекомендацией заменить устройства или мигрировать данные на правильно сконфигурированный пул.

Хотите одну команду для аудита всего парка — `for p in $(zpool list -H -o name); do echo "== $p"; zdb -C $p | grep -w ashift | sort | uniq -c; done`. Выполняется за секунды, а результат иногда сильно меняет планы на квартал.
Заменили диски на 4К-секторы, а ZFS стал писать медленнее: что на самом деле делает ashift — схема
Схема к статье. Открыть схему в полном размере

Разбор выезда: питомник собак на 13 рабочих мест

Условный клиент — питомник собак «Королевский двор»: тринадцать рабочих мест, администрация, ветеринарный кабинет, отдел продаж щенков. Один физический сервер на Debian с ZFS под всё сразу: общая SMB-шара с фото и видео выводков, сканами родословных и ветеринарных паспортов, файловая база 1С:Бухгалтерии и репозиторий резервных копий рабочих станций. Пул tank собирал ещё прошлый подрядчик в 2016 году: четыре диска по 2 ТБ в raidz2 за RAID-контроллером в режиме JBOD, никто ничего явно не указывал — zpool create tank raidz2 ... и всё. Контроллер отдавал системе диски как 512/512, хотя физически они были 512e с сектором 4 КиБ. Автодетект честно поверил и выбрал ashift=9.

Почти десять лет пул отработал без претензий. Весной 2026-го место кончилось (свободно 7 %), контроллер заменили на обычный HBA, закупили четыре диска по 8 ТБ и поменяли их по одному через zpool replace, с интервалом в сутки на ресильвер. Место выросло примерно с 3,5 до 14 ТиБ. А через неделю пришла заявка «ночной бэкап не успевает, а 1С по утрам тормозит». Смотрю: копирование станций раньше укладывалось в 40 минут, теперь 1 час 50 минут. Замер fio случайной записью блоком 16 КиБ с fsync показал 38 IOPS на четырёх шпинделях — примерно втрое ниже того, что такие диски дают на правильной геометрии.

zpool iostat -vl 5 показал красивую картину: очередь записи почти пустая, IOPS смешные, а средняя задержка записи (колонка write в блоке total_wait) — 12–13 мс при том, что диски свежие и smartctl чист. iostat -x 5 со стороны Linux дал %util под 100 при смешной полезной нагрузке: диски были заняты постоянно, но делали не то, что нужно. А zpool status всё это время показывал у каждого нового диска block size: 512B configured, 4096B native — просто туда никто не смотрел. Классическая картина read-modify-write: каждая запись тянет за собой чтение.

# то, ради чего всё затевалось
$ zdb -C tank | grep -w ashift
            ashift: 9

$ lsblk -o NAME,MODEL,LOG-SEC,PHY-SEC,ROTA /dev/sd{a..d}
NAME MODEL            LOG-SEC PHY-SEC ROTA
sda  TOSHIBA MG08ADA8     512    4096    1
...

$ zpool get ashift tank
NAME  PROPERTY  VALUE   SOURCE
tank  ashift    12      local     # кто-то уже пытался «починить»

Дальше была попытка выкрутиться малой кровью: добавить новый зеркальный vdev с ashift=12, перегнать данные и убрать старый через zpool remove. Не вышло, и не могло выйти. В zpool-remove(8) условия сформулированы жёстко: верхнеуровневые vdev можно удалить, только если в основном хранилище пула нет top-level raidz или draid vdev, все top-level vdev имеют одинаковый ashift и ключи всех зашифрованных датасетов загружены. У нас нарушены сразу два условия из трёх: raidz2 и разный ashift. Обратите внимание на второе — оно означает, что смешанный по ashift пул навсегда лишается механизма эвакуации vdev. Одна давняя ошибка автодетекта закрывает вам инструмент, который мог бы её же и исправить.

В итоге сделали единственно рабочее. На время миграции подключили два б/у диска по 8 ТБ и собрали на них временный зеркальный пул tmp с явным -o ashift=12; живых данных было около 2,4 ТиБ, так что влезло с запасом. Перелили через zfs send -R, ночью остановили шару и 1С, догнали инкрементом, уничтожили старый пул, собрали новый raidz2 из тех же четырёх дисков по 8 ТБ уже с -o ashift=12 и перелили обратно. Итог по цифрам: случайная запись 38 → 135 IOPS, средняя задержка записи 12,4 → 1,6 мс, ночной бэкап 1 ч 50 мин → 35 минут. Занятое место выросло примерно на 3 % — плата за более крупный квант выделения, и она того стоила.

Самое неприятное в этой истории — что деградация пришла не в момент замены, а размазалась по неделе после последней замены. Никто не связал «поменяли последний диск» и «бэкап не успевает»: а предупреждение в `zpool status` никто не читал.
Цифры и версии: Разбор выезда: питомник собак на 13 рабочих мест — схема
Цифры и версии: Разбор выезда: питомник собак на 13 рабочих мест. Открыть схему в полном размере

Диагностика: убедитесь, что виноват именно ashift

Прежде чем планировать миграцию на выходные, потратьте полчаса и исключите более простые причины. Я видел как минимум три случая, когда «это ashift» оказывалось совсем не ashift, а миграция всё равно проводилась — с нулевым эффектом и с потраченными выходными.

Начните с геометрии. lsblk -o NAME,MODEL,LOG-SEC,PHY-SEC,ROTA покажет, что диск сообщает системе. Сравните с zdb -C — если логический и физический сектор у дисков 4096, а ashift vdev равен 9, диагноз почти наверняка верный. Если же диски честные 512/512 (старые серверные SAS, некоторые enterprise SSD), то ashift=9 сам по себе беды не создаёт, ищите в другом месте.

Дальше — короткий чек-лист альтернативных подозреваемых. Самый частый — SMR-диски: черепичная запись даёт ровно те же симптомы, «сначала быстро, потом колом», и лечится только заменой дисков на CMR. Второй — заполненность пула: после 80–85 % растёт фрагментация свободного места, аллокатору всё дольше искать подходящие участки, а при почти заполненных метаслабах он переходит на медленный режим best-fit — и запись проседает независимо ни от какого ashift. Третий — синхронная запись без отдельного SLOG: NFS-датастор гипервизора или база данных заставляют ZFS честно ждать ZIL. Четвёртый — включённая дедупликация на пуле без запаса ОЗУ. Пятый — банально идущий скраб или ресильвер.

zpool list -o name,size,alloc,free,cap,frag,health   # cap выше 80% — вот вам и причина
zpool status -t                                       # идёт ли scrub/resilver, когда был trim
zpool status tank | grep -i "block size"              # 512B configured, 4096B native = ваш случай
zpool iostat -vl 5                                    # latency по каждому диску отдельно
iostat -x 5                                           # %util и await со стороны ядра
zfs get -r sync,recordsize,compression,dedup tank | grep -v default
cat /sys/block/sdX/queue/rotational                    # SMR отдельно проверяйте по модели

Отдельно про диагностику «в одну строчку»: если один диск в zpool iostat -vl показывает задержку в разы выше соседей — это не геометрия, это умирающий диск, и его надо менять до всяких миграций. ashift деградирует все диски vdev примерно одинаково, потому что штраф структурный, а не аппаратный.

Если пул заполнен на 90 % и собран с ashift=9 — сначала разгрузите его до 70 %, замерьте заново и только потом принимайте решение о миграции. Иногда после разгрузки вопрос снимается сам.

Как это чинится на самом деле: только миграция данных

Хорошая новость — рецепт один и он предсказуемый. Плохая — обойтись без переливки данных нельзя. Никакой команды «переформатировать vdev под другой ashift» в ZFS нет и, судя по архитектуре, не будет: ashift зашит в разметку пространства vdev, менять его на живых данных — это переписать весь пул, что эквивалентно миграции.

Мой рабочий сценарий такой. Собираем новый пул с явно указанным ashift, перегоняем данные через zfs send | zfs recv под нагрузкой, потом коротким окном догоняем инкрементом и переключаемся. Простой сокращается до времени последнего инкремента — обычно это минуты, а не часы.

# 1. Новый пул — ashift указываем ЯВНО, не надеясь на автодетект
zpool create -o ashift=12 -O compression=lz4 -O atime=off \
  -O xattr=sa -O acltype=posixacl tank2 raidz2 \
  /dev/disk/by-id/ata-DISK1 ... /dev/disk/by-id/ata-DISK6

# 2. Полный слепок под нагрузкой (шары продолжают работать)
zfs snapshot -r tank@mig1
zfs send -R -L -e -c tank@mig1 | zfs recv -F -u tank2

# 3. Окно простоя: гасим службы, догоняем инкрементом
systemctl stop smbd nfs-server
zfs snapshot -r tank@mig2
zfs send -R -L -e -c -I tank@mig1 tank@mig2 | zfs recv -F -u tank2

# 4. Переключение: старый пул убираем, новый импортируем под старым именем
zpool export tank
zpool export tank2 && zpool import tank2 tank
zfs mount -a && systemctl start smbd nfs-server
zdb -C tank | grep -w ashift        # убедиться, что теперь 12

Пояснения по флагам, потому что на них спотыкаются. -R отправляет весь набор датасетов с их свойствами и снапшотами. -L разрешает большие блоки — без него датасеты с recordsize=1M приедут порезанными на 128 КиБ, и вы потеряете часть выигрыша. -e включает embedded-блоки, -c — передачу уже сжатых данных без распаковки, это заметно ускоряет перегон. Для зашифрованных датасетов нужен -w (raw), иначе принимающая сторона потребует ключи. -u на приёме означает «не монтируй сразу» — обязательно, иначе новый пул попытается смонтироваться поверх работающего старого. И важная деталь: если полный поток шёл с -L -e -c, инкремент отправляйте с теми же флагами, иначе приём может отказать или блоки снова порежутся. Импорт tank2 под именем tank сохраняет пути для служб и скриптов бэкапа — не придётся переписывать конфиги Samba и заданий резервного копирования.

Чего делать не нужно и на что не стоит надеяться. zpool remove для эвакуации старого vdev не сработает: как я показал выше, он требует одинакового ashift у всех top-level vdev и отсутствия raidz/draid в основном хранилище. Расширение RAIDZ (feature raidz_expansion, оно про «attach a new device to a RAID-Z group, expanding the total amount usable space in the pool») добавляет диск в существующую группу — и новый диск наследует ashift этой группы, то есть проблему не решает, а консервирует. zpool attach в зеркало ведёт себя так же. И, повторюсь, zpool set ashift не делает ничего с существующей геометрией.

Перед `zpool destroy` старого пула убедитесь, что на новом на месте не только данные, но и свойства: sharenfs/sharesmb, quota/refreservation, mountpoint, а также системные настройки — bootfs, cachefile и права ACL.

Как больше не попадать: правила при создании пулов

Правило первое и главное: всегда указывайте ashift явно. zpool create -o ashift=12 — это две секунды при создании и ноль сюрпризов через восемь лет. Автодетект полагается на то, что накопитель честно сообщает физический размер сектора, а огромный пласт железа — 512e-диски, потребительские SSD, диски за RAID-контроллером в режиме passthrough, iSCSI/виртуальные тома — сообщает 512 просто потому, что так безопаснее для совместимости со старыми ОС.

Правило второе: подстрахуйтесь на уровне модуля. У ZFS есть параметр zfs_vdev_min_auto_ashift со значением по умолчанию 9 (ASHIFT_MIN) — это минимальный ashift, используемый при создании новых top-level vdev. Поднимите его до 12, и даже коллега, забывший ключ -o, не создаст пул с 512-байтной геометрией. Парный параметр zfs_vdev_max_auto_ashift по умолчанию равен 14 и может быть увеличен до ASHIFT_MAX (16), но документация честно предупреждает, что это негативно скажется на эффективности использования пространства. На FreeBSD и TrueNAS CORE тот же параметр — это sysctl: в системах на OpenZFS (FreeBSD 13 и новее) он называется vfs.zfs.vdev.min_auto_ashift, в старых FreeBSD со встроенным ZFS — vfs.zfs.min_auto_ashift. Handbook FreeBSD прямо пишет, что значение 12 даёт тот же результат, что -o ashift=12, и для создания пула, и для последующих zpool add и zpool attach. Графическим мастерам пулов я не доверяю на слово: после создания всегда zdb -C.

# /etc/modprobe.d/zfs.conf
options zfs zfs_vdev_min_auto_ashift=12
# применить без перезагрузки (действует на СОЗДАВАЕМЫЕ vdev)
echo 12 > /sys/module/zfs/parameters/zfs_vdev_min_auto_ashift
update-initramfs -u   # если корень на ZFS
# FreeBSD / TrueNAS CORE (OpenZFS)
sysctl vfs.zfs.vdev.min_auto_ashift=12
echo 'vfs.zfs.vdev.min_auto_ashift=12' >> /etc/sysctl.conf

Правило третье: 12 или 13 — вопрос спорный, и я скажу честно. Документация OpenZFS для флеш-памяти допускает и 12 (4К), и 13 (8К), потому что современные SSD внутри работают страницами по 8 КиБ и больше. Но на практике на NVMe разница между ashift=12 и 13 у меня ни разу не вылезала за пределы погрешности измерения, а вот потери места на RAIDZ при ashift=13 вполне заметны. Я ставлю 12 везде по умолчанию и отступаю от этого, только если производитель прямо документирует страницу 8 КиБ и нагрузка того требует. Тот, кто говорит, что «правильный ответ один» — либо не мерил, либо мерил на одном стенде. Отдельный случай — NVMe с пространством имён, отформатированным в 4Kn: логический сектор 4096, поэтому автодетект даст минимум 12, а 9 невозможен в принципе. Формат LBA смотрится командой nvme id-ns /dev/nvme0n1 -H | grep "LBA Format" (активный помечен «in use»), а переключение через nvme format --lbaf=N уничтожает данные — делать только до создания пула. Для 13 на NVMe нужны основания вроде документированной страницы 8 КиБ и собственного замера.

Правило четвёртое, про которое забывают: на RAIDZ ashift работает в связке с размером блока. При ashift=12 минимальный аллокейт — 4 КиБ на диск, и если вы отдаёте zvol с volblocksize=8K под виртуалку на raidz2, то на выравнивание и чётность уходит непристойная доля ёмкости — на практике я видел двукратные потери. Для zvol на RAIDZ берите volblocksize от 32–64 КиБ, для файловых датасетов оставляйте recordsize=128K по умолчанию или поднимайте до 1M под бэкапы и медиа. Отдельные vdev — special, log, dedup — это тоже полноценные top-level vdev со своим ashift, и их геометрию тоже надо задавать осознанно: смешанный ashift в пуле, напомню, навсегда закрывает возможность zpool remove.

ashift=12 на дисках с честными 512-байтными секторами почти ничего не стоит — вы теряете немного места на очень мелких файлах. ashift=9 на дисках с 4К-секторами стоит вам кратной производительности записи. Асимметрия очевидна: сомневаетесь — ставьте 12.

Приоритеты: что делать в понедельник и на что можно забить

Начну с успокоительного, потому что тему любят раздувать. Если у вас пул ashift=9 на 512e-дисках, а нагрузка — последовательное чтение-запись крупными блоками (архив, медиа, файловая свалка с recordsize=1M), то реальная деградация будет в районе 10–20 %, а не в разы. Такое можно спокойно дожить до планового обновления железа и мигрировать заодно. Ронять прод на выходных ради пятнадцати процентов на архивной шаре — плохая сделка.

А вот где деградация действительно кратная: синхронная запись мелкими блоками. Базы 1С и SQL на zvol, NFS-датастор гипервизора, репозиторий резервных копий с большим числом мелких транзакций, почтовый сервер с maildir. Там read-modify-write бьёт по каждой операции, и разница между ashift=9 и 12 на шпинделях вырастает в три-четыре раза — ровно как в разборе выше. Если ваш случай отсюда — планируйте миграцию, ждать нечего.

Порядок действий, который я рекомендую всем клиентам с ZFS. Первое — инвентаризация: прогоните zdb -C по всем пулам и запишите фактический ashift каждого vdev в паспорт стенда. Это полчаса на весь парк. Второе — зафиксируйте zfs_vdev_min_auto_ashift=12 на всех хостах, чтобы новые пулы гарантированно рождались правильными. Третье — для найденных пулов с ashift=9 определите класс нагрузки и поставьте миграцию в план, привязав её к ближайшему расширению или замене дисков: делать два простоя вместо одного бессмысленно. Четвёртое — никогда не меняйте свойство ashift на живом пуле в надежде, что что-то улучшится: не улучшится, а вы потеряете диагностический признак, потому что zpool get ashift начнёт показывать одно, а zdb -C — другое, и следующий инженер запутается.

И последнее, про закупки. Перед тем как заказывать диски на замену, посмотрите zdb -C и lsblk -o NAME,LOG-SEC,PHY-SEC вместе. Если у существующего vdev ashift=9, а новые диски — 4Kn (логический сектор 4096, а не 512e), ZFS их в этот vdev просто не примет: устройство с ashift больше, чем у верхнего vdev, не открывается, а zpool replace выдаёт «new device has a different optimal sector size». Опция -o ashift=9 не поможет — логический сектор диска меньше не станет. Лучше узнать об этом до оплаты счёта, а не в ночь замены: берите 512e-модели на дожитие старого пула или сразу планируйте новый.

Главный практический вывод: ashift — это решение, принимаемое один раз на всю жизнь vdev. Всё остальное в ZFS можно докрутить на ходу, это — нет.
Порядок действий: Приоритеты: что делать в понедельник и на что можно забить — схема
Порядок действий: Приоритеты: что делать в понедельник и на что можно забить. Открыть схему в полном размере

Частые вопросы

Можно ли изменить ashift существующего пула без переливки данных?

Нет. Внутренний ashift верхнего vdev фиксируется при его создании и не меняется никогда — ни при замене диска, ни при ресильвере, ни при обновлении версии ZFS. Документация zpoolprops(7) говорит об этом прямо: изменение свойства не модифицирует существующие vdev, даже при замене диска. Единственный рабочий путь — создать новый пул с нужным ashift и перегнать данные через zfs send/recv или восстановить из бэкапа.

Зачем тогда вообще нужно свойство ashift у пула?

Оно работает как значение-подсказка по умолчанию для последующих операций add, attach и replace. То есть влияет на новую геометрию, которую вы создаёте: новый top-level vdev через zpool add или новое зеркало. На уже существующий vdev оно не влияет никак.

Как посмотреть настоящий ashift моих пулов?

Командой `zdb -C имя_пула | grep -w ashift` — она показывает фактическое значение по каждому top-level vdev. Дополнительно можно посмотреть read-only свойство vdev: `zpool get ashift пул vdev-name`, и метку конкретного диска через `zdb -l /dev/disk/by-id/...`. Команда `zpool get ashift пул` показывает только подсказку для будущих операций, а не текущее состояние.

Что ставить — ashift=12 или ashift=13?

Единого мнения нет. Документация OpenZFS для флеш-памяти допускает оба значения, поскольку страница современной NAND — 8 КиБ и больше. На практике на NVMe разница обычно теряется в погрешности, а вот потери ёмкости на RAIDZ при ashift=13 заметны. Я по умолчанию ставлю 12 и отступаю от этого только при документированной 8-килобайтной странице и подходящем профиле нагрузки.

Насколько сильно на самом деле падает производительность при ashift=9 на 4К-дисках?

Зависит от нагрузки. На последовательных операциях крупными блоками — обычно 10–20 %, это терпимо и можно дожить до планового обновления. На синхронной записи мелкими блоками (базы 1С и SQL, NFS-датастор гипервизора, почта) деградация на шпинделях доходит до трёх-четырёх раз, потому что каждая запись превращается в чтение-модификацию-запись.

Поможет ли расширение RAIDZ или zpool remove, чтобы обойтись без миграции?

Нет. Расширение RAID-Z добавляет диск в существующую группу, и новый диск наследует ashift этой группы. А zpool remove требует, чтобы в пуле не было top-level raidz/draid и чтобы у всех top-level vdev был одинаковый ashift — то есть именно пул со смешанной геометрией эвакуировать vdev и не сможет.

Как защититься от повторения ошибки на новых серверах?

Два действия. Первое — всегда создавать пул с явным ключом: `zpool create -o ashift=12 ...`. Второе — поднять параметр модуля `zfs_vdev_min_auto_ashift` до 12 через /etc/modprobe.d/zfs.conf, чтобы даже пул, созданный без ключа, не получил 512-байтную геометрию. По умолчанию этот параметр равен 9.

Как задать ashift=12 по умолчанию на FreeBSD или TrueNAS CORE?

Через sysctl `vfs.zfs.vdev.min_auto_ashift=12` (в старых FreeBSD до перехода на OpenZFS — `vfs.zfs.min_auto_ashift`). По FreeBSD Handbook это действует на создание пула и на последующие `zpool add` и `zpool attach`. Уже существующие vdev параметр не трогает — проверяйте результат через `zdb -C`.

Можно ли вставить 4Kn-диск в старый пул с ashift=9?

Нет. У 4Kn логический сектор 4096 байт, а ZFS не открывает устройство, чей ashift больше ashift верхнего vdev: `zpool replace` завершится ошибкой «new device has a different optimal sector size». Для дожития такого пула нужны 512e-диски, а правильное решение — новый пул с ashift=12.

Столкнулись с похожей задачей? Обращайтесь — решим

Если у вас происходит что-то из описанного в этой статье — или любая другая проблема с ИТ-инфраструктурой, — обращайтесь в любое время. Мои специалисты и я лично разберём ситуацию, найдём настоящую причину и доведём до решения.

Возьмёмся и за разовую задачу, и за постоянное обслуживание. Первичная консультация — бесплатно и без обязательств.

📞 +7 903 729-62-41 💬 MAX: +7 903 729-62-41 ✈ Telegram @ITfresh_Boss

С уважением, Семёнов Евгений Сергеевич, директор «АйТи Фреш» — IT-аутсорсинг для компаний до 50 рабочих мест, 15+ лет практики

Источники

© ООО «АйТи-Фреш» · Москва · Все статьи