Про ZFS и манипулирование данными

Таскал тут данные туда-сюда, RAIDZ1 разобрать, RAIDZ2 собрать.

Но так как дисков/питания на "поднять оба массива сразу" не хватало, делал это хитровывернутым образом - скопировал на одиночные диски, потом собрал degraded-массив без этих дисков (подстановкой файликов из нулей вместо них), скопировал обратно, восстановил четность.

И смотрю я теперь на iostat -x 100 и не радуюсь:

device     r/s   w/s    kr/s    kw/s qlen svc_t  %b
da0      330.3  10.1 11156.0   104.6    0   3.9  20
da1      330.2  10.4 11152.1   107.8    0   3.7  19
da2      672.3  10.0 22010.3   108.0    0   3.6  47
da3      318.2   9.5 10771.8   103.2    0   3.9  19
da4      318.1   9.7 10769.0   104.5    0   4.0  19
da6      672.3  10.2 22008.4   106.6    8   4.5  55

 

da5 - еще один диск на который сейчас идет копирование (tar cvf с массива) убрал его из показа, дабы не смущал, da2 - часть изначального массива,da6 (и da0) - добавлен потом.

И вот I/O как-то сильно неравномерно лежит по дискам, я конечно еще попробую, но есть ощущение что теперь придется еще и все датасеты перекопировать еще раз, дабы поравномернее разлеглись.

Пока писал, прошли очередные 100 секунд. Опять неравномерно, но по другим дискам.

device     r/s   w/s    kr/s    kw/s qlen svc_t  %b
da0      945.4  10.1 30800.0    93.9    0   2.4  43
da1      457.2  10.1 15194.0    93.8    0   2.8  19
da2      456.9   9.6 15193.8    91.8    0   2.9  20
da3      945.1   8.7 30800.4    87.4    1   2.4  42
da4      466.6   9.6 15519.9    92.2    0   3.0  21
da6      466.7  10.6 15519.9    96.5    0   2.8  19

Буду пока продолжать наблюдение, ерунда какая-то. На 4-терабайтниках такого не было.

Из существенного: это tar-ятся примерно полмиллиона файлов на 400Gb. Карты. Половина - единицы мегабайт (gif,png), половина - крохотные текстовые (.map и подобные). Т.е. там много мельчайших кусочков, не занимающих полный блок.

UPDATE: с большими файлами (их чтением) та же ерунда - нагрузка не равномерна по дискам, а плавает, на двух больше - на четырех меньше и так по кругу по дискам.

Похоже, что делать degraded-массив было не самой удачной идеей, теперь всю компанию еще раз - скопировать на внешний/восстановить/сравнить/старое убить. Но хоть диски перетыкать не надо (и запас места есть), можно скриптом.

Comments

А почему не zfs send/receive кстати?

Я тут играюсь с zfs-on-linux, выглядит интересно, если взлетит -- буду думать, как переехать с lvm+md на zfs mirror (видимо тоже подегрейдить md, zpool attach /dev/вторая-половина, и после resilvering заменить так же первую, выдернув из под него lvm.

Я не понимаю, что будет с блоками после этого, не останутся ли они такие же перекошенные.
Поэтому по старинке, tar

При "нормальном" чтении с raidz контрольные блоки не читаются, а если "там много мельчайших кусочков, не занимающих полный блок", то как ляжет патерн чтения на диски ещё тот вопрос. Наверно аномалии (биения) по чтению в таких условиях и на таких временных интервалах возможны.

а что вообще происходит при
а) записи на массив raidz2 у которого не хватает пары дисков (по идее, для полных блоков четность не пишется, а для фрагментов?)
б) если мы записали такой массив, а потом добавили дисков и resilver - не выйдет ли так, что контрольные блоки все лягут на новые диски?

Я не разбирался с работой raidz, поэтому не знаю. Нужно смотреть код. Кроме блоков данных (полных или фрагментов) есть ещё метаданные. А сколько их и каков у них размер? Думаю, перед raidz стоит фундаментальная задача - как наиболее равномерно размазать блоки данных по всем дискам, а так как размеры блоков данных не фиксированы, то наверняка это усложняет задачу. Предположу, что даже после перезаливки возможны биения (неравномерность) при чтении с дисков raidz. Нужно только выбрать походящие файлы и интервал для статистики :-).

с массива, который делался без этих извращений - все хорошо, загрузка равномерная.

На вскидку из vdev_raidz.c:
/*
* If all data stored spans all columns, there's a danger that parity
* will always be on the same device and, since parity isn't read
* during normal operation, that that device's I/O bandwidth won't be
* used effectively. We therefore switch the parity every 1MB.
*
* ... at least that was, ostensibly, the theory. As a practical
* matter unless we juggle the parity between all devices evenly, we
* won't see any benefit. Further, occasional writes that aren't a
* multiple of the LCM of the number of children and the minimum
* stripe width are sufficient to avoid pessimal behavior.
* Unfortunately, this decision created an implicit on-disk format
* requirement that we need to support for all eternity, but only
* for single-parity RAID-Z.
*
* If we intend to skip a sector in the zeroth column for padding
* we must make sure to note this swap. We will never intend to
* skip the first column since at least one data and one parity
* column must appear in each row.
*/

Ну это известное место.
Но как оно себя ведет на degraded-массиве - не буду читать.

Проще еще раз send/recv, раз уж играем в 15, значит играем

Я вот подумал - в данном наблюдении основным критерием является производительность чтения. Если оттолкнуться от - "UPDATE: с большими файлами (их чтением) та же ерунда - нагрузка не равномерна по дискам, а плавает, на двух больше - на четырех меньше и так по кругу по дискам.", то возникает вопрос что быстрее читать одинаковый объём с 4 дисков непрерывно или с 6 с дырками? Даже интересно стало узнать результат.

Вопрос в том, что я не могу прочитать одни и те же данные разными способами.

Вот другой массив на другом ящике (zfs send >/dev/null), за 10 секунд. Ну ровно же висит:

device     r/s   w/s     kr/s     kw/s  ms/r  ms/w  ms/o  ms/t qlen  %b
aacd0      474     0  80423.2      0.0     5     0     0     5    0  83
aacd1      473     0  80296.8      0.0     5     0     0     5    0  90
aacd2      472     0  80122.0      0.0     5     0     0     5    3  84
aacd3      476     0  80781.2      0.0     5     0     0     5    0  94
aacd4      471     0  79995.6      0.0     5     0     0     5    3  89
aacd5      474     0  80424.0      0.0     5     0     0     5    0  87
aacd6      473     0  80295.2      0.0     5     0     0     5    3  89
aacd7      475     0  80514.8      0.0     5     0     0     5    3  87

Из общих соображений, если у нас узкое место диски - то читать следует со всех

И когда узкое место - приемник, то ситуация та же:

device     r/s   w/s     kr/s     kw/s  ms/r  ms/w  ms/o  ms/t qlen  %b
aacd0      207     0  35263.6      0.0     3     0     0     3    0  43
aacd1      207     0  35263.2      0.0     3     0     0     3    0  42
aacd2      207     0  35334.8      0.0     3     0     0     3    0  42
aacd3      207     0  35317.2      0.0     4     0     0     4    0  44
aacd4      207     0  35310.8      0.0     3     0     0     3    3  41
aacd5      208     0  35465.6      0.0     5     0     0     5    0  54
aacd6      206     0  35074.0      0.0     3     0     0     3    0  41
aacd7      206     0  35073.6      0.0     3     0     0     3    0  40

 

Здесь красивая картинка, но здесь 8 дисков, а не 6. Если предположить, что здесь тоже raidz2, то сдвиг блоков чётности будет всегда, даже без применения "нужных" алгоритмов (recordsize/6).

"Из общих соображений" - при многопоточном (или случайном) доступе согласен. А при однопоточном последовательном чтении не уверен. Получается при чтении с 4 дисков каждый диск пролетит над filesize/4 информации, а при чтении с 6 каждый диск пролетит над теми же filesize/4 информации :-).

Возможно важно (а может и достаточно), что нагрузка при чтении движется по кругу?

Да, возможно что это все фича "правильного количества дисков", 2^N+Z - и тогда чтение всегда будет такое кривое.
Но меня уже не остановить, я уперся, сейчас спишу опять все на дискетки, благо процесс налажен, и еще раз переделаю.

Оно особо не мешает, только диском грохочет.

Дня через три будет рассказ :)

Перед началом новой заливки, можно будет "достать линейку" и, зная скорости дисков, на пустом пуле проверить гипотезы и предположения :-).

Именно
На пустом пуле создать файлик на полтерабайта и почитать. И посмотреть на раскладку по дискам.

Но сначала надо
а) подвигать данные
б) уж заодно - сделать чексумминг всех копий которые уже есть, чтобы точно знать когда и что разошлось (если разошлось)

Дискам теперь долго грохотать

Достал линейку, сильно удивлен:
1) Ну как и подозревалось, и на новом пуле (собранном нормально) и на старом (залитом с двумя missing members) все одинаково, единомоментно два диска в чтении не участвуют. Ну, ок.

2) Моя стандартная линейка какая-то херовая, негодная:
dd if=zdata/test/file bs=1G of=/dev/null читает ~200Mb/sec
и zfs send zdata/test@1 >/dev/null - опять 200Mb/sec
А вот нормальный пул, с кином (там файлы тоже большие, но не по 200G конечно), восстановленный zfs recv - zfs zend шлет с более нормальной скоростью, 500Mb/sec. 125 со шпинделя, не 160 как на записи, но OK.

Я в недоумении - получается что нормально скорость чтения померять я не могу.

Да совсем не густо, но не зная всех ньюансов (настроек), посоветовать что-то сложно. Но всё таки, что-то совсем мало, возможно даже причина не в zfs либо в случайной глупой настройке (у меня такое случалось). Мои последние опыты по настройке zfs говорят, что на больших файлах (размер файла в два раза и более превосходит размер оперативной памяти) при холодном (первое чтение после импорта пула) последовательном чтении следует ожидать около 80% от пропускной способности всех дисков входящих в пул. Если у тебя 6 дисков, допустим со скоростью 170 MB/s в начале диска, то холодное чтение файла расположенного вначале должно быть в районе 800 MB/s. Повторное чтение (метаданные уже в кеше) около 90% - получается около 900 MB/s. Понятно, что если в кеше на момент чтения осталась часть данных, то скорости будут ещё выше. Правда мои результаты получены на страйпе зеркал и отношения к raidz не имеют. Да ещё, всё мерялось dd и настройки по умолчанию дают приблизительно на 40% меньше результат.

Да ещё обратил внимание на bs=1G. Префетчинг по умолчанию работает при запросах менее или равном 1M.

А вот "настройки zfs" - это про что речь, что там реально можно настраивать?

Собирал вчера вечером и страйп (больше уже не буду, потому что половина данных уже вернулась на пул за ночь и еще раз я это не переживу).
Запись: ~1.15Gb/sec (170-180 со шпинделя)
Чтение: 550-600Mb/sec. (соответственно, до сотки со шпинделя).
Пробовать туда восстанавливать реальные данные и их читать zfs send - не делал.

Заодно отвечу и на остальное, то что ниже
- выключение префетча (для raidz2): скорость чтения тестового большого файла падает еще раза в полтора
- уменьшение блока для dd при чтении (до мегабайта) - скорость не меняется практически
- уменьшение recordsize (до стандартных 128k с 1m) - скорость чтения падает, но цифры уже не помню, я особо не записывал

sysctl -a | grep zfs :-))) (это конечно издевательство делать доступным столько настроек).
Ещё раз повторюсь я не разбирался с raidz, но довольно глубоко просмотрел цепочку чтения с mirror, поэтому это гарантированно касается только страйпа из зеркал.
Допустим нужно настроить максимальную скорость последовательного чтения.
Префетчинг - сюда я сильно не влазил, но окно префетчинга для каждого потока в FreeBSD 11 сделали 8MB (в FreeBSD 10.1 было 256 блоков (recordsize), как и в Ubuntu 16.04). Для насыщения всех дисков в пуле (добиться отсутствия простоев) желательно создать очередь чтения к каждому диску. А если дисков много ;-). Например, увеличивая окно до 32MB добавляем 10-20% производительности последовательного чтения.
Алгоритм балансировки зеркала - здесь немного посложнее, но скажу, что немного подправив алгоритм можно получить ещё плюс 20-30%. Кстати, в Ubuntu 16.04 остался старый алгоритм балансировки зеркала "по загрузке" и старые настройки окна префетчинга. Как результат на 1MB recordsize неприлично большой выигрыш в производительности, хотя при других значениях recordsize имеется отставание от FreeBSD.
Шедулер ввода-вывода. Настройка длины активной очереди асинхронного чтения (чтение данных префетчинга) тоже влияет. Но я впоследствии отказался от этой настройки.
Важен размер recordsize. И не всегда больше значит лучше :-). Я остановился на 128kB.
Также общее правило - на диски нужно писать необходимый и достаточный минимум информации что бы головки дисков не летали над дырами (настройки sync, logbias, redundant_metadata).

Ага, понятно почему оно так по разному на двух ящиках себе ведет: 12-current и 10-3

Да, но зато два параллельных потока чтения - в отличие от того к чему я привык ранее - друг другу не мешают.

2x200 - пожалуйста (из разных больших файлов)

Я посмотрел на современные диски 6Т и вроде они имеют начальную скорость 200MB/s и выше :-).

Для страйпа зеркал для многопоточного последовательного чтения у меня получилась такая формула. Для двух потоков 90-95% от пропускной способности всех дисков. При увеличении потоков, как бы это не казалось удивительным, общая пропускная способность падает совсем незначительно. То есть общая пропускная способность дисков делится на количество потоков. Эта особенность связана с алгоритмом работы префетчера и шедуллера zfs. Также можно наблюдать отставание по времени выполнения некоторых потоков (если они запущены одновременно), но общая пропускная способность не падает.

У меня HBA может маленько убавлять. Т.е. на терабайтниках старых он дает на ~10% меньше адаптека.
На 6T - не сравнивал.

Никто ж не мешает, даже на смонтированном пуле, dd if=/dev/da0 of=/dev/zero bs=1M count=8k.
Я всегда проверяю диски перед сборкой массива. Кстати, бывают и странности, да и диски при сборке пула желательно согласовать по скоростям, а то часто и диски из разных серий и с разной скоростью.
Буквально неделю пришлось взять два WD4002FYYZ (в моей местности уже недоступны WD4000FYYZ), так для одного диска верхняя строчка стала первой и последней, хотя как бы и работает. Обещали, что завтра уже получу замену :-).

О, fetch_max_distance сильно помогает, прям в разы. 550 стали читать (и 650 писать)

Не было печали...

max_streams 8->32 => 700+ Mb/sec.

Однако блин.

Что бы не играть в пятнашки, приведу выдержки из описания работы zfetch от последнего автора mav@:
"Максимальное окно превыборки называется zfetch_max_distance (8MB) для данных и zfetch_max_idistance (64MB) для метаданных (в 10.3). zfetch_array_rd_sz это размер операций чтения выше которого prefetch не срабатывает, предполагая что приложение и так указало весь размер данных что ему нужен и больше читать не будет (спорное мнение как по мне)."
Под zfetch_max_idistance понимается:
"Делается превыборка indirect blocks необходимых для доступа к следующим 64MB данных. На практике это значит чтение наперед всего несколько блоков метаданных, но существенно повышает скорость линейных операций, как чтения так и записи, так как к моменту запроса сразу известно откуда читать и куда писать, и можно сразу слать запрос."
По поводу роста окна предвыборки:
"Увеличивает плавно, но довольно резко -- удваивает окно при каждом
попадании, причем этот алгоритм в новом префетчере поменялся."
От себя добавлю.
max_streams - количество одновременно поддерживаемых потоков чтения, поэтому от изменения их количества скорость последовательного чтения не изменяется. При бездействии (отсутствии чтения) более 2 сек (min_sec_reap) поток из zfetch удаляется.
И ещё, так как zfs претендует на роль универсальной файловой системы, то в настройках по умолчанию выбирается компромис для применения в разных сценариях. Поэтому нужно учитывать, что улучшая в одном месте можно нарваться на засаду в другом.

>> улучшая в одном месте можно нарваться на засаду в другом
Это то хорошо понятно (иначе все было бы уже выкручено в "наилучшие" значения)

Но я исхожу из того, что ускорять мне надо "большие чтения", потому что "маленькие" в любом случае происходят быстро (не в Mb/sec, а просто в sec).

id_distance у меня пока нет.
distance - оказывает понятное магическое действие.

Пойду FreeBSD обновлю до 11, посмотрим и на id_distance заодно.

У меня пока всё работает на 10.1 и только сейчас попробую перейти на 11. Поэтому я "знаком" только с этими двумя версиями. Мой опыт подсказывает, что zfs спроектирована довольно "правильно". С неё можно выжимать довольно много для некоторых конкретных задач. Поэтому (моё личное мнение) отталкиваться нужно от производительности дисков, затем проверить сколько может система (процессор, память, чипсет, контроллер) прокачать одовременно относительно полной производительности дисков. Дальше оценить теоретический порог производительности конфигурации zfs (в твоём случае raidz2). Постараться приблизиться к нему и успокоиться :-).

# uname -r
11.0-STABLE
# sysctl -a | grep dista
vfs.zfs.zfetch.max_distance: 8388608

idistance не появилась от 11.0.
И на 12-current не видать

# uname -r
11.0-RELEASE-p1

Из dmu_zfetch.c:
/*
* This tunable disables predictive prefetch. Note that it leaves "prescient"
* prefetch (e.g. prefetch for zfs send) intact. Unlike predictive prefetch,
* prescient prefetch never issues i/os that end up not being needed,
* so it can't hurt performance.
*/
boolean_t zfs_prefetch_disable = B_FALSE;

/* max # of streams per zfetch */
uint32_t zfetch_max_streams = 8;
/* min time before stream reclaim */
uint32_t zfetch_min_sec_reap = 2;
/* max bytes to prefetch per stream (default 8MB) */
uint32_t zfetch_max_distance = 8 * 1024 * 1024;
/* max bytes to prefetch indirects for per stream (default 64MB) */
uint32_t zfetch_max_idistance = 64 * 1024 * 1024;
/* max number of bytes in an array_read in which we allow prefetching (1MB) */
uint64_t zfetch_array_rd_sz = 1024 * 1024;

Таки да, данная настройка в sysctl не выведена. Но я не вижу особого смысла её менять. Хотя если хочется можно перекомпилировать zfs.ko.

>> Note that it leaves "prescient" prefetch (e.g. prefetch for zfs send) intact.

В-общем, FreeBSD kernel is very well documented. Читая комментарии можно понять, почему у zfs send нормальная производительность, а у tar cf /dev/null - не очень.

В общем, увеличить max_distance раз в 10-20-40 сильно помогает в моем случае. Какое-то такое значение и оставлю.

А как этот prefetch влияет на l2arc? (оно не будет бухать туда 8мегабайтные куски? особенно для датасетов с мелкими recordsize)

PS Пардон за тупые вопросы -- я живой zfs вижу третий день (к тому же на линуксе, и под ним еще довольно фрагментированый lvm лежит)

Префетченое оно положит в память, естественно.

По идее, в L2arc должно идти most frequently used (а MRU - нет).

Ну если только most frequently used -- то какие-то изменения в производительности я замечу только когда туда rootfs перенесу (точнее /nix/storage где лежит основной компот типа компиляторов и инклюдов от них) -- пока на zfs только maildir и buildroot от локальной сборочницы. И как я понимаю у меня сейчас кеши от остальных FS дерутся с zfs (arc/l2arc) за память/io. И разницы пока я не завершу переезд я не увижу.

PS а тут можно зарегистрироваться, чтобы не вводить капчу каждый раз?

zpool iostat -v показывает что там было с l2arc

Регистрация: http://blog.lexa.ru/user/register

arc.c:

*           head -->                        tail
 *            +---------------------+----------+
 *    ARC_mfu |:::::#:::::::::::::::|o#o###o###|-->.   # already on L2ARC
 *            +---------------------+----------+                  |   o L2ARC eligible
 *    ARC_mru |:#:::::::::::::::::::|#o#ooo####|-->|   : ARC buffer
 *            +---------------------+----------+               |
 *                 15.9 Gbytes      ^ 32 Mbytes    |
 *                               headroom          |
 *                                          l2arc_feed_thread()
 *                                                 |
 *                     l2arc write hand <--[oooo]--'
 *                             |           8 Mbyte
 *                             |          write max
 *                             V
 *          +==============================+
 *    L2ARC dev |####|#|###|###|    |####| ... |
 *              +==============================+
 *                         32 Gbytes

 

Не смог сходу найти как выбрать моноширинный шрифт, поэтому лучше смотреть в исходнике.

Я влепил.

Подумаю, может дам авторизованым средства побогаче (попробовал сейчас - нет, за секунду не делается, а немного не до того)

Может, циклическая разница в нагрузке на отдельные диски - изначально запроектрованная особенность:
- меньше вероятность вылета дисков "паровозом" (если диски из одной партии (и одной "смены"));
- когда нагружены 2, 4 оставшихся "отдыхают" - чипы работают в щадящем режиме.

Вообще, вот странная история.
Собрал - из освободившихся 4T дисков (тоже HGST) массив. На другой машине, FreeBSD12, raidz2 из пяти дисков.

И вот с ними - с ровно таким же тестом (скорость чтения из большого файла при помощи dd, массив пуст) - получается вменяемая скорость, 450-500Mb/sec. Без увеличения окна префетча, стандартные 8M работают ок.

Похоже, что это какая-то особенность 6T. Ну там вплоть до того, что дорожка не влезает в буфер у диска, не знаю что еще придумать.

Не помню в какой версии Солярки таймаут ответа при отсылке почты стоял "0". Поэтому письма ГЕОГРАФИЧЕСКИ ближе 400км доходили, дальше - отлуп по таймауту.
:-)

Да-да, очень похоже.

А Вы новые диски одинаково "готовили" или сырыми втыкали?

Там одинакового размера с одинаковым же смещением gpt-раздел