Про ZFS prefetch

Вынесу из комментариев, потому что это важное, чтобы потом самому было легче найти.

АХТУНГ. Все описанные ниже эксперименты (и прошлая серия экспериментов) - относятся ТОЛЬКО к FreeBSD-12. На 10.3-11.0 (релизных! со -stable все сложно) картина принципиально другая и деградации скорости чтения при маленькой глубине префетча нет.

Собрал я тут ZFS массив на следующие (я надеюсь) лет пять: 6x6Tb, в RAIDZ2 (2 - потому что я устал срочно бегать в магазин, покупать замену вылетевшему диску), диски HGST, правда разные (три гелиевых, два 7k6000, один Deskstar NAS), но довольно близкие по характеристикам (гелиевые похолоднее и помедленнее).

Достал линейку, стал мерять перформанс. И удивился:

  • С записью все OK, длинные файлы пишутся примерно ~600-650Mb/sec. Ну хотелось бы 700, ну да ладно.
  • С чтением все не OK:
    • dd if=/zdata/bigfile of=/dev/null читает ~200Mb/sec
    • zfs send zdata@1 (датасет на котором кроме этого бигфайла ничего нет) - опять медленно
    • zfs send zdata/realdataset - ну ок, 500+
  • Ладно, плюнул, временно пересобрал страйп из 6 этих же дисков:
    • запись ~1100Mb/sec
    • чтение ~550Mb/sec

В комментариях мне подсказали про vfs.zfs.zfetch.max_distance. И действительно, после увеличения его раз в 20 (со стандартных 8Mb до 160, пробовал и больше) - скорость чтения большого файла наладилась, стало 500-600Mb/sec, в пиках и побольше бывает (речь про raidz2, что там у страйпа - не тестировал и уже не буду). Цена тоже понятная, если мы читаем мало, то нам попрефетчат эти самые 80-160-... мегабайт, даже если они нам не нужны (ну там есть какая-то логика когда префетчить, но она скорее всего может ошибочно предсказывать).

Ну, казалось бы, все понятно, ну префетч, ну да.

Однако.

Я потестировал того же самого на других массивах:

  • RAIDZ2 из восьми терабайтников ("рабочие данные")
  • RAIDZ2 из пяти 4-терабайтников (не, я понимаю что нужно 6, но не было)

И в обоих случаях увеличение глубины prefetch практически не влияет на скорость линейного чтения большого файла. Стандартных 8Mb вполне хватает, увеличивать не нужно.

Правда есть разница и ее больше чем одна:

  • Другая версия FreeBSD: на проблемном ящике была 10.3, потом 11 (от апгрейда ничего не изменилось)
  • Другой контроллер, на проблемном ящике LSI-9211 (в dumb-mode, без BIOS для ускорения загрузки), на тестовом на котором все в порядке Adaptec 5805
    Впрочем, когда на "проблемном" ящике был предыдущий массив (6 дисков в RAIDZ1), там скорость чтения была какой-то близкой к ожидаемой (в районе 500Mb/sec, но мерял давно), т.е. разница явно не только в адаптеке.
  • Другой процессор: на "проблемном" i3-2120, на втором i5-2400.

В общем, остаюсь пока в недоумении:

  • То ли дело в Адаптеке (который в свой полугиговый кэш всегда читает дорожку целиком), а с 9211 - вот такие странные проблемы (но этих проблем нет с контроллером SATA на материнке)
  • То ли дело в 6-терабайтных дисках (ну там увеличился размер дорожки и то что раньше влезало в эти 8Mb префетча - теперь не влезает)

Но мораль простая: если со скоростью чтения что-то не так, крутите префетч.

P.S. Крутил еще вот эти параметры на "проблемном" ящике, большой разницы в длинных линейных чтениях не увидел:

vfs.zfs.vdev.cache.size=64M
vfs.zfs.vdev.cache.max="16384"
vfs.zfs.vdev.cache.bshift="18"

 

Comments

Судя по: "Ладно, плюнул, временно пересобрал страйп из 6 этих же дисков: запись ~1100Mb/sec, чтение ~550Mb/sec" с дисками всё нормально. Смущает конечно чтение, но чтобы снять все подозрения с аппаратной части:
#zpool export ***
#fio ./test_all | grep iops

test_all:

; job fio
[global]
rw=read
direct=1
bs=1M
runtime=100
group_reporting
thread
gtod_reduce=1

[0]
filename=/dev/da0

[1]
filename=/dev/da1

[2]
filename=/dev/da2

[3]
filename=/dev/da3

[4]
filename=/dev/da4

[5]
filename=/dev/da5

Диски (или разделы) поставь соответственно входящие в пул. Тест безопасный (будет одновременно читать 100 сек все диски с максимальной скоростью). Желательно проконтролировать (gstat) во время чтения загрузку дисков (должна быть близкой к 100%). Затем покажешь выведенную строчку.
Предположу, что будет ещё одна перезаливка данных :-).

Я их dd почитал по одному. ~210Mb/s обычные, 185 - гелиевые, гелиевые чуть помедленнее - но это и ожидалось.

По одному - это по одному, а все вместе - это все вместе :-). За одно сверим с этой цифрой 210+210+210+185+185+185=1185.

Ну вот сумма на 30 больше даже.

По iostat -x/gstat у всех дисков 99% и ожидаемая скорость: ~215 у обычных, 200 (из того что ниже - получается 190) у He8
Вот результаты двух прогонов:
fiolog: read : io=121780MB, bw=1214.4MB/s, iops=1214, runt=100310msec
fiolog2: read : io=121780MB, bw=1214.3MB/s, iops=1214, runt=100294msec

А вот без group reporting:
fiolog3: read : io=21694MB, bw=221511KB/s, iops=216, runt=100287msec
fiolog3: read : io=21694MB, bw=221925KB/s, iops=216, runt=100100msec
fiolog3: read : io=18814MB, bw=192605KB/s, iops=188, runt=100026msec
fiolog3: read : io=18878MB, bw=193108KB/s, iops=188, runt=100105msec
fiolog3: read : io=18942MB, bw=193363KB/s, iops=188, runt=100312msec
fiolog3: read : io=21758MB, bw=222502KB/s, iops=217, runt=100135msec

He8 - на 4-6 градусов холоднее при одинаковом охлаждении, у меня (летом) это место близко к критичному бывает.

Ну вот и доказали, что с аппаратной частью у тебя всё хорошо. У меня ещё такой пропускной способности в руках не было, но думаю можно попробовать настроить последовательное чтение до 1GB/s (какая символическая цифра :-)). Если всё таки надумаешь перезаливать данные, то предлагаю потратить дополнительные 30 мин для проверки данного допущения (и количество дисков подходящее и скорости дисков распределились как надо :-)).
По существу. Так как я не эксплуатирую raidz, то могу только сделать предположение. Похоже ты попал с данной конфигурацией raidz в "устойчиво не хорошее сочетание разных факторов". Предполагаю самое простое решение убрать один диск из конфигурации raidz или добавить. Для проверки можно воспользоваться и составным диском.

>> устойчиво не хорошее сочетание разных факторов"

Ну вот казалось бы, 2^N+R (R-избыточность) - это ровно рекомендованное количество дисков.
При этом - хотелось бы конкретнее про "сочетание факторов", страйп то тоже не показал себя с default-настройками как я ожидал.

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

Можно ли, собирая массив из них, подвердить или опровергнуть гипотезу с "сочетанием факторов"?

Думаю, что можно и это самый лучший вариант. Я бы без чёткого понимания ситуации даже бы и не дёргался. Единственное на чём бы я заострил внимание - это разница в скорости дисков. Не уверен, но она тоже могла бы немного "посодействовать". Из твоего iostat однозначно видно, что два диска из шести получали в два раза больше запросов, то есть данные так уже лежали на дисках. Наверно это самое важное. Меня тогда же ещё смутил средний размер запроса чтения с диска (в районе 32k). Вроде из твоих описаний про 1M recordsize на диски должны приходить в основном запросы в 128k. Откуда взялись эти средние ~32k?

Про "в два раза больше" - это был исходный вопрос, с которого все и началось.
Тогда мы решили, что чексуммы не читаются - и так и надо.
Размер чтения зависит, вероятно, еще от драйвера?

>> получали в два раза больше запросов

И вот эта загрузка она в моменте (без префетча) у двух дисков из 6 вообще 0. Но незагруженные диски - меняются.

Длинный префетч это размазывает, естественно.

Была констатация факта, что при "нормальном" чтении контрольные блоки не читаются. Этот факт говорит только о "мгновенном" неравномерном чтении. Как оно там дальше я не знаю. Из твоих описаний можно предположить, что raidz2 ведёт себя, как набранный из кусочков raid4, причём довольно больших. Что является поводом для смены положения контрольных блоков - малелькая запись (допустим метаданных) или принудительное смещение мне не известно.
Шедуллер zfs все запросы меньше 128k пытается агрегировать (объединять). При попадании запроса в подсистему geom все большие запросы нарезаются по модулю MAXPHYS (128k).

Так как я опасаюсь адаптека (там при смене дисков надо их "инициализировать" и хрен знает что оно при этом затирает) - я заказал еще один 9211, благо копейки стоит, придет (через дней 10, я надеюсь) - и буду развлекаться.

Откуда взялись эти средние ~32k?

А вот вам с другого ящика (tar cf - | mbuffer -o /dev/null   mbuffer - чтобы видеть мгновенные скорости):

                        extended device statistics
device     r/s   w/s     kr/s     kw/s  ms/r  ms/w  ms/o  ms/t qlen  %b
aacd0      529     0  90353.0      0.0     1     0     0     1    0  40
aacd1      529     0  90301.5      0.0     1     0     0     1    2  41
aacd2      531     0  90628.0      0.0     2     0     0     2    0  39
aacd3      528     0  90267.1      0.0     7     0     0     7    5  74
aacd4      532     0  90902.8      0.0     5     0     0     5    0  68

У меня получается ~170kb на запрос. Что тоже интересно.

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

recordsize=1m, 5 дисков в raidz2


 

На счёт скорости дисков. Вполне нормально, если скорости будут отличаться. Просто при жесткой увязке (как у raidz) быстрые диски будут привязаны к скорости более медленных и будут потери производительности. Но моя мысль была связана с полосатостью патерна чтения. Допустим нужно прочитать блок данных (recordsize), как в твоём последнем случае. Будет сформирован запрос на чтение (zio) 1MB, затем опускаясь по стеку будут сформированы три дочерних запроса (zio) по ~340kB и так далее. К моменту прихода запроса на физический диск может сложиться такая ситуация, что допустим один диск может прочитать сектора сразу, а два других должны будут пролететь перед чтением контрольные блоки. То есть один диск будет опережать два других. Возникла мысль, а может ли возникнуть в процессе чтения ситуация, что один диск прочитал всю свою порцию чтения из окна префетчинга, а один ещё только читает свою первую часть порцию. Тогда наверно возможна ситуация, что следующий запрос на чтение придет на, выполнивший свою работу, диск когда тот уже пролетит над этими данными и ему потребуется сделать лишний оборот. Это конечно предположение и возможно диск всегда читает дорожку и складывает данные в свой кэш. Поэтому я написал, что разница скоростей могла бы немного "посодействовать" подобной ситуации. Кстати, у зеркала при чтении нет такого влияния разницы скоростей дисков, потому что алгоритм балансировки построен на загрузке дисков и также нет жёстких связей (весь блок (recordsize) читается только с одного диска). Поэтому при чтении может быть выбрана почти вся пропускная способность. Мало того, в zfs предусмотрена возможность работы в зеркале ssd и hdd одновременно. Специально подстроен алгоритм балансировки. Для этого даже сделали автоматическое определение типа диска (non_rotating), пока правда только во FreeBSD.

Размер запроса на диск. При входе в подсистему geom, в твоём случае запрос (zio) ~340kB, Будут сформированы три дочерних запроса (bio) - 128kB, 128kB и ~84kB. Почему средний размер запроса ~170kB ума не приложу :-). Хотя он конечно коррелирует с ~340kB.

Кстати, если ядро собрано с MAXPHYS=256k, то получится средний размер запроса в ~170kB.

defaults

И, удивительным образом, не нашел как этот параметр посмотреть у собранного. Ищу вот...

/sys/sys/param.h

#define MAXPHYS (128 * 1024) /* max raw I/O transfer size */

У меня других мыслей нет. Разве, что я отстал от жизни :-).

Ну я собираю с MAXPHYS=1mb, ща попробуем.

С точки зрения системы это наверно не очень хорошее решение, но мне тоже интересно :-).

Ничего не изменилось

                        extended device statistics
device     r/s   w/s     kr/s     kw/s  ms/r  ms/w  ms/o  ms/t qlen  %b
aacd0      498     0  84884.6      0.0    11     0     0    11    5  94
aacd1      500     0  85200.8      0.0    10     0     0    10    6  93
aacd2      499     0  84995.4      0.0    10     0     0    10    6  94
aacd3      499     0  85062.8      0.0    11     0     0    11    6  94
aacd4      505     0  85950.7      0.0    10     0     0    10    6  95

 

Создал датасет test1M с recordsize=1M.

dd if=/dev/zero of=/pdf/test1M/test_64G_1M bs=1M count=64k (347MB/s)

dd if=/pdf/test1M/test_64G_1M of=/dev/zero bs=1M count=64k (661MB/s)

extended device statistics
device r/s w/s kr/s kw/s ms/r ms/w ms/o ms/t qlen %b
ada0 0 0 0.0 1.6 0 0 0 0 0 0
ada1 0 0 0.0 0.0 0 0 0 0 0 0
ada2 1302 0 166770.1 0.0 15 0 0 15 17 98
ada3 1192 0 152696.8 0.0 16 0 0 16 23 99
ada4 1661 0 98314.7 0.0 7 0 0 7 9 77
ada5 0 0 0.0 0.0 0 0 0 0 0 0
ada6 1597 0 98254.0 0.0 9 0 0 9 24 83
ada7 977 0 125163.8 0.0 17 0 0 17 16 86

Пул страйп из двух зеркал. В одном зеркале один диск (временно) stripe из ada4 и ada6 (stripesize=64k).
ada2, ada7 - WD4002FYYZ (195MB/s), ada3 - WD4000FYYZ (170MB/s), ada4 и ada6 WD2002FAEX (140MB/s).
Когда пул был пустой при recordsize=128k скорость чтения вначале была - холодная 605MB/s и 704MB/s (метаданные в кеше).

Заметил gstat показывает при чтении средний размер запроса чуть меньше 128k, iostat чуть больше 128k. При записи размер среднего запроса такой же.

Ну я поиграюсь с 8 дисками так, сяк, наперекосяк - когда контроллер придет.

Пока у меня есть два raidz2 (5 и 6 дисков) и один radiz (4 диска). Во, вот raidz1 посмотрим:

ada2       544     0  61741.6      0.0    10     0     0    10    0  82
ada3       544     0  61919.2      0.0    12     0     0    12    8  89
ada4       546     0  61982.8      0.0    11     0     0    11    5  88
ada5       540     0  61461.6      0.0    12     0     0    12    8  89

 

113k. Ну наверное там 128 + мелкая метадата (она не в кэше была, свежезагруженная машина, холодные данные)

(128 + 128 + 84) / 3 = 113

Ну значит 256+84 пополам равно 170

Я уже давно отказался от дополнительных контроллеров и может это у меня пробелы в их использовании. Припоминаю, что mav@ когда то писал что из устройства вычитываются какие-то индивидуальные данные. Можно будет попробовать найти. Но в любом случае geom это абстрактный слой и до физического устройства ещё длинный путь (подсистема cam, драйвер устройства). Geom-у нужно от нижлежащего блочного устройства по большому счёту только mediasize и sectorsize, ну можно ещё оценить stripesize, stripeoffset, rotationrate или другие плюшки. Можно предположить, что у дополнительных контроллеров созданный ими geom может иметь отличный от MAXPHYS максимальный размер запроса, но в принципе это легко проверить.
1. Почитать dd напрямую диск, подключённый к контроллеру, с bs=128k, 256k, 512k и посмотреть.
2. И наверно сразу напрашивается - экспортнуть пул, переключить диски (там где 6) на набортные сата порты, загрузиться с чего нибудь и посмотреть. Что то мне подсказывает, что ..., нет лучше сначала увидеть результаты пункта 1 :-).

Ну вот запросто может быть, что aac (адаптек) сам определяет request size и ему MAXPHYS не указ.
Но углубляться в это уже очень не хочется.

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