Как стать автором
Обновить

Комментарии 38

Код, где даже игнорирование результата функции прописывается явно, меня разует.
Про структуры хотелось бы подробнее, ибо привычные нам оценки скорости работы могут быть не применимы к операциям чтения/записи на диск.
Код, где даже игнорирование результата функции прописывается явно, меня разует.

В большинстве случаев, в ZFS и Solaris kernel, результат функции без контекста не даст почти ничего. Функция может быть void потому-что она меняет непосредственно один из аргументов, или что-то делает с данными на которые мы дали pointer. It's C, which explains everything. Я дал примеры кода в основном ради комментариев — без них что-то понять вообще почти нереально.
Про структуры хотелось бы подробнее, ибо привычные нам оценки скорости работы могут быть не применимы к операциям чтения/записи на диск.

Два основных принципа работы ZFS — как и огромного количества C кода в *nix — асинхронность. Например, функция zfs_vdev_io_start() запишет поинтер на структуру, в которой записано что надо сделать, в очередь исполнения; из очереди другая функция (возможно, из отдельного модуля, или из самого I/O драйвера) её подберет, и когда цепочка завершится, обработчик исполнения очереди запустит zfs_vdev_io_done(), callback pointer на которую был в struct'e, который мы послали на исполнение.

Таким образом достигается и асинхронность, и параллельность кода, но пытаться разобраться в таких цепочках очень непросто даже с DTrace.
И да, про скорость скорее всего будет отдельная статья с DTrace скриптами и измерением latency на разных уровнях.
Мне вот крайне интересно какое все же будущее у ZFS, учитывая подлый шаг оракла по закрытию OpenSolaris. Получим две несовместимые версии zpool >28?
Да, уже об этом разговоры ведутся.
Будет FreeBSD ZFS совместимая с illumos и другими клонами opensolaris и solaris zfs — проприетарщина, которая сдохнет в угоду btrfs (известно что оракловцы убьют то что будет забирать время на другие продукты).
Да, на данный момент от Оракла никто больше ничего не ждёт — работа над открытой версией ZFS на базе zpool v28 продолжается в Illumos и FreeBSD. Fork yeah.
* Практически теме же людьми, что и вели разработку раньше
а как же zpool v31 от оракла с шифрованием, например?
Просто ребята из Sun'a уходя забыли запушить куда надо.
А зачем оно? Шифрование на уровне сервера поможет только в одном случае — если сопрут сам сервер и доступ к нему. Даже если данные на сервере зашифрованы, через CIFS/NFS/iScsi/FC они передаются в открытом виде. С этой точки зрения, имеет смысл использовать софт типа TrueCrypt на клиенте.
Скорее даже, если сопрут диски из сервера, но не сам сервер. Ключ находится на сервере.
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Содраны были всё-таки не фичи, а концепты. Uberblock, Copy-on-Write, tree of blocks. Сравнивать ZFS с WAFL не совсем корректно — они похожи на самом низком уровне, но работают далеко не одинаково. На ZFS многие переходят как раз с NetApp'ов, по нескольким причинам.
Пруф:
communities.netapp.com/community/netapp-blogs/dave/blog/2007/09/05/netapp-sues-sun-for-zfs-patent-infringement
НЛО прилетело и опубликовало эту надпись здесь
Естественно, реализации у обеих систем разные, к примеру, мне бы хотелось видеть механизм нетапповской дедубликации WAFL в ZFS.


Да, с дедупликацией всё не так просто. Чтобы сделать аналог offline dedup в ZFS, необходим механизм перезаписи блоков данных и метаданных, не нарушая доступ к ним с точки зрения клиента. Для этого надо перезаписать не только сам блок, но и поинтер к нему в блоке метаданных, и поинтер к блоку метаданных, и так по цепочке АВЛ-дерева до самого uberblock'a, в процессе чего возможно придётся перебалансировать само дерево. Собственно та же причина не позволяет делать онлайн-дефрагментацию (reallocate), балансировку данных по vdev'ам (rebalance), изменение размера пула или vdev'a в меньшую сторону, эвакуацию vdev'a, и т.д.

Такой механизм называется Block Pointer Rewrite, и он уже обрёл статус мема — все говорят, что он когда-то будет написан (с 2008 года), но пока никто его не написал :) Последний раз когда я пытался его включить в roadmap, мы прикинули, что докрутить его до production quality «как надо» займёт порядка 8,000 developer/QA-часов, и на этом обсуждения заглохли. Может его на Kickstarter разместить? :)

Зато есть другой вариант, который ускоряет online-dedup больше чем на порядок для реальных нагрузок, и почти готов. Stay tuned.
НЛО прилетело и опубликовало эту надпись здесь
Так же опасаюсь, что Ваш вариант ускорения мы увидим нескоро, так как пока актуальный zpool появится в ОС отличных от Solaris, пройдет немало времени.


Зависит от того, что Вы подразумеваете под «увидим». Поиграться с ним в виде беты скорее всего можно будет уже в Q1'2013, но пока он дойдёт upstream до Illumos, а оттуда портанётся в FreeBSD, может пройти достаточно много времени.

Пока же приходится выкручиваться или объемом RAM+процессором, благо это недорого либо использовать сжатие — зависит от характера использования.


Сжатие (lzjb) кстати имеет смысл использовать почти всегда — оно занимает очень мало CPU ресурсов, а декомпрессия добавляет <0.5мс задержки в read pipeline для 128К блоков.

root@myhost:/# dtrace -qn 'lzjb_decompress:entry{self->t = timestamp} lzjb_decompress:return/self->t/{self->t=(timestamp - self->t)/1000; @=quantize(self->t); @a=avg(self->t)} tick-60sec{printa("Latency in microseconds: %@d\nAvg latency: %@d us",@,@a); trunc(@); trunc(@a); exit(0)}'      

Latency in microseconds:
           value  ------------- Distribution ------------- count
               4 |                                         0
               8 |                                         54
              16 |@                                        385
              32 |                                         131
              64 |                                         39
             128 |@@@@@@@                                  1789
             256 |@@@@@@@@@@@@@@@@@@@@@@@                  6289
             512 |@@@@@@@@                                 2149
            1024 |                                         32
            2048 |                                         1
            4096 |                                         0

Avg latency: 361 us

root@myhost:/# prtdiag | head -10 | tail -2
Intel(R) Xeon(R) CPU           E5620  @ 2.40GHz CPU 1
Intel(R) Xeon(R) CPU           E5620  @ 2.40GHz CPU 2


А для дедупликации, да, объём RAM критичен, хотя в Illumos недавно закоммитили async destroy, который решает главную проблему dedup — долгое и очень печальное для продакшн удаление данных.
НЛО прилетело и опубликовало эту надпись здесь
Да, логично. Я бы сказал, что сжатие имеет смысл если в результате ratio будет 1.05х и выше. Дедуп — 3.0х и выше.

Про async destroy можно почитать в багтрекере — www.illumos.org/issues/2619 и www.illumos.org/issues/2747 (второй — SPA feature flags, фактически уход от zpool версий).

В FreeBSD вроде тоже уже есть, но не в stable:

[1] r236884: zfs feature support, June 11, MFC after 1 month
[2] r238422: fixes for defer-destroy, July 13, MFC after 1 week
[3] r238926: fixes for zpool feature support, July 30, MFC after 2 weeks
НЛО прилетело и опубликовало эту надпись здесь
Зато есть другой вариант, который ускоряет online-dedup больше чем на порядок для реальных нагрузок, и почти готов

интересно, что имелось в виду?

Пока все хорошо, продолжайте писать, пожалуйста.

Спасибо.
Не понял, почему onboard write cache работает, только если диск выделен полностью? Контроллеру не все равно ли, что кэшировать, особенно если у него батарейка?

Смысл в том, что для каждой синхронной записи надо делать DKIOCFLUSHWRITECACHE() для гарантии сохранности данных, а на partition/slice/файл его сделать нельзя.

ZFS не нужен RAID-контроллер, так что батарейки может не быть. Для сохранности данных используется ZFS Intent Log на быстрых SSD, если они есть; если нет — синхронная запись идет прямо на диски, что сильно тормозит I/O. Конечно, можно отключить sync полностью, но лучше не надо.
PS В принципе для ZFS должна работать схема дефрагментации «скинул все на стриммер, отформатировал диск, вернул назад».

Дефрагментация таким образом работает, с помощью zfs send/receive например. Но для этого нужен downtime.
Но вопрос в другом — является ли фрагментация проблемой для ZFS?

В некоторых случаях да, является. На сильно фрагментированном пуле страдает скорость записи из-за скорости прохода по space map и free map. Может разберусь с этим — там есть пара вариантов использовать другие аллокаторы, или написать новый — прототип у меня уже есть.
два вопроса

первый: zfs использует 128-ми битные указатели. Бывает ли что в старших 64-х битах содержатся не нули? Если сейчас нет, то когда (и какие конкретно) наступят условия того, что такая длина указателей окажется востребованной?

второй: когда zfs отдает данные os, маппит ли она страницу своего кеша на страницу, где os хочет видеть данные (либо передает указатель на страницу кеша, а OS делает это самостоятельно), или же только копирует данные из своего кеша в ту страницу, где хочет видеть данные os?
первый: zfs использует 128-ми битные указатели. Бывает ли что в старших 64-х битах содержатся не нули? Если сейчас нет, то когда (и какие конкретно) наступят условия того, что такая длина указателей окажется востребованной?

Точно не знаю — на 1ПБ пуле вроде используются только младшие 64 бит. Теоретически, будут использоваться старшие, когда будет 16 Exabyte данных, что пока практически недостижимо.
второй: когда zfs отдает данные os, маппит ли она страницу своего кеша на страницу, где os хочет видеть данные (либо передает указатель на страницу кеша, а OS делает это самостоятельно), или же только копирует данные из своего кеша в ту страницу, где хочет видеть данные os?

Копирует данные в страницу, где их хочет видеть ОС. В кеше (ARC) хранятся raw blocks — их надо обработать, распаковать (если они запакованы), и т.д.
Хм, похоже я ошибся немного. Более подробно:
The vdev portion of each DVA is a 32 bit integer which uniquely identifies the vdev ID containing this block. The offset portion of the DVA is a 63 bit integer value holding the offset (starting after the vdev labels (L0 and L1) and boot block) within that device where the data lives. Together, the vdev and offset uniquely identify the block address of the data it points to. The value stored in offset is the offset in terms of sectors (512 byte blocks).

Перевод с моими комментариями: DVA — Data Virtual Address — входит в состав указателя блока, blkptr_t. DVA состоит из 2х 64-бит переменных. Первая переменная указывает на vdev, в котором данные (используется 32 бит); вторая — на адрес внутри vdev'а (используется 63 бит).

#define DVA_GET_VDEV(dva) BF64_GET((dva)->dva_word[0], 32, 32)
#define DVA_GET_OFFSET(dva) BF64_GET_SB((dva)->dva_word[1], 0, 63, SPA_MINBLOCKSHIFT, 0)

Отсюда выходит, что сам указатель блока ограничивает размер адресного пространства пула до 2^105 байт, и 2^72 байт на vdev, причём если когда-нибудь этого места станет мало, можно увеличить минимальный размер сектора, или увеличить лимит на количество vdev'ов в пуле без изменения структуры ZFS. Лет через 100 наверное придётся…
Спасибо за подробное обьяснение. Немножко странный выбор размеров адресов, ведь все-таки можно было спокойно обойтись 64-х битным полным адресом первую сотню лет…

По поводу копирования данных — я спросил потому что, например, во FreeBSD именно так и происходит (возможно в соляре ситуация другая), и такой подход крайне тормознутый. Технология маппинга страниц отработана десятилетиями, она позволяет очень эффективно кешировать данные файловых систем, особенно страниц с кодом программ, которые не надо копировать от процесса к процессу, например. А так получается, что ZFS требует двойного кеширования (raw block-ов средствами zfs и страниц с данным средствами os)… ;(
Упс, не туда ответил. См. коммент ниже (2 декабря 2012 в 12:01)
По поводу копирования данных — я спросил потому что, например, во FreeBSD именно так и происходит (возможно в соляре ситуация другая), и такой подход крайне тормознутый. Технология маппинга страниц отработана десятилетиями, она позволяет очень эффективно кешировать данные файловых систем, особенно страниц с кодом программ, которые не надо копировать от процесса к процессу, например. А так получается, что ZFS требует двойного кеширования (raw block-ов средствами zfs и страниц с данным средствами os)… ;(


Такой подход имеет смысл с точки зрения cache consistency — если дать доступ на страницу памяти напрямую какому-либо процессу, особенно вне ядра, и данные в этой странице устареют (блок перезаписан чем-либо ещё), то Солярис либо не сможет его освободить без разрешения процесса (может быть дедлок из-за non-zero reference count), либо освободит без спроса и перезапишет, что тоже нехорошо. Если процесс грохнется, то опять же будет проблема с reference count.

Тут всё зависит от use case — например, если использовать ZFS для локальных баз данныx, у которых есть свой кеш, имеет смысл ограничить размер ARC, или сказать ему кешировать только метаданные (zfs set primarycache=metadata pool/fs), оставив большую часть оперативной памяти для внутреннего кеша программы. Нормальные базы данных кешируют более эффективно, чем ZFS, поскольку они знают собственно какие данные более важны для них самих.

Если использовать SAN/NAS на базе ZFS, то в userland ничего такого вообще быть не должно, и под ARC отдаётся почти вся оперативная память системы; больше нигде кеш не нужен и не используется. К тому же, в zvol'ax (ZFS Volume, блочный девайс эмулируемый средствами ZFS, используется в COMSTAR для экспорта iScsi/FC LUNов клиентам) доступ идет напрямую в ARC. Для CIFS и NFS вроде как тоже что-то такое есть, или в процессе написания — там это сделать реально поскольку они в ядре, но может быть нетривиально.

А с точки зрения скорости — я особо не замечал проблем с этим на нормальных SAN машинах; реально получить 3 ГБ/с sustained read/write, или 250к IOPs в продакшн. Latency от такого подхода если и страдает, то очень мало. В бенчмарках до 1млн IOPs, но в продакте я такого пока не видел — там будут нужны сумасшедшие размеры очереди.
Согласен, такой подход годится для случая, когда данные нужно достать и отдать единоразово, для той же базы данных, или бекап поднять… Но вот, например, если захостить на zfs раздел /usr, где данные нужно регулярно отдавать все новым и новым процессам, то производительность может очень сильно пострадать…

И ещё у меня очень серьезная претензия к многопоточной производительности zfs — async операции это правильно, но шедулер у zfs ужастный. При нескольких сотнях паралельных потоках на чтение размер очереди запросов возрастает катастрофически, что ведет к гигантстким задержкам. Обслужить один поток zfs умеет действительно хорошо, но организовать фотохостинг на ней, например, — дохлый номер (под высокой загрузкой конечно, когда от сервера требуется отдавать фотки тысячам клиентам одновременно).
А можно конфиг системы и примерное описание workload'a в студию? Из параметров интересует recordsize, zpool status, если используются какие-либо нестандартные параметры (и ZFS и ядра), то их тоже. Ну и если хостинг фоток, то средний размер и количество одновременных потоков чтения.

Я достаточно часто занимаюсь оптимизацией ZFS для очень специфических use-case'ов, может помогу разобраться. Правда если есть какие-либо различия между Illumos и FreeBSD, то здесь помочь не смогу.

Навскидку, здесь может помочь "zfs set atime=off pool/fs", а дальше надо смотреть.
Деталей сейчас не отпишу, т.к. тот сетап в продакш не пошел.
recordsize=128k
zfs тюнился по разному, под кеш памяти больше половины было выделено точно, игрался с разными настройками через sysctl, а через команду zfs, увы, не очень (
Проблема именно с многопоточной загрузкой, т.е. если тестить в небольшое кол-во потоков бенчмарком — то все ок, сервер отдает столько бендвича, сколько позволяют винты по iops. Но после запуска настоящей нагрузки, когда тысячи браузеров качают файлы одновременно — загрузка винтов зашкаливает, а отдаваемый бендвич сильно падает (скорее всего из-за очень резкого увеличения latency). Я не смог побороть эту деградацию (. Стандартная ufs2 использует ресурс iops винтов куда более экономно — на ней и остановился.
Если проблема именно в latency, можно попробовать поиграться с zfs_vdev_max_pending — этот параметр контролирует queue depth дисков. Таким образом можно уменьшить среднюю latency дисков. Зависит от модели дисков и от того, как они обрабатывают внутреннюю очередь.

Также обязательно посмотреть на iostat и zpool iostat — надо убедиться, что когда мы читаем данные, ничего не пишется одновременно — atime timestamp, например. Ну а дальше — искать bottleneck с DTrace и думать.
Хабр — торт.

На фоне оккупации линуксятиной, агиле, фрилансерами_из_таиланда, ардуинами и прочим кикстартером :) Все еще возможно почитать по-настоящему интересные вещи :) Пишите еще, непременно. И не опасайтесь капитанить, в таких предметных областях никогда не бывает «слишком просто». Кому будет просто, промотают до следующего абзаца.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории