Изменения

Перейти к: навигация, поиск

Производительность Ceph

9449 байтов добавлено, 16:30, 9 октября 2020
Нет описания правки
В данной статье описано, каких показателей производительности можно добиться от цефа и как. Но сразу предупрежу: локальный SSD вы не догоните. Локальные SSD сейчас ОЧЕНЬ быстрые (особенно NVMe), порядок их задержки — 0.05ms. Догнать эту цифру SDS-ке крайне трудно (одна только сеть сожрёт те же 0.05ms), перегнать — наверное, вообще невозможно.
 
'''UPDATE: Догнать можно. Я это сделал в своём собственном проекте — Vitastor: https://vitastor.io :-) это блочная SDS с архитектурой, похожей на Ceph, но при этом БЫСТРАЯ — в тесте на SATA SSD кластере задержка и чтения, и записи составила 0.14 мс. На том же кластере задержка записи у Ceph была 1 мс, а чтения — 0.57 мс. Детали есть в [https://yourcmc.ru/git/vitalif/vitastor/src/branch/master/README.md README] — смотрите по ссылке.'''
== Бенчмаркинг ==
*: Или https://github.com/vitalif/ceph-bench, что примерно то же самое. Родоначальник идеи — @socketpair Марк Коренберг ([https://github.com/socketpair/ceph-bench оригинал]). Бенчилка тестирует ''отдельные OSD'', что очень помогает понять, кто же из них тупит-то.
*: Перед запуском надо создать пул без репликации {{Cmd|ceph osd pool create bench 128 replicated; ceph osd pool set bench size 1; ceph osd pool set bench min_size 1}} и с числом PG, достаточным, чтобы при случайном выборе туда попали все OSD (ну или прибить их вручную к каждому OSD upmap-ами)
* CephFS
** Нормальных инструментов для тестирования ФС, сцуко, нет!!!
** «Нормальный» инструмент — это такой инструмент, который вёл бы себя, как файловый сервер: случайно открывал, создавал/писал/читал и закрывал маленькие файлы среди большого общего количества, разбитые по набору каталогов
** Всё, что есть, какое-то кривожопое: bonnie++, например, зачем-то тестирует запись по 1 байту. iometer, fs_mark не обновлялись лет по 10, но и паттерн файл сервера не умеют. Лучшее, что умеют — это тест создания файлов.
** Пришлось написать свой ioengine для fio: https://github.com/vitalif/libfio_fileserver :)
* S3 (rgw):
** [https://github.com/intel-cloud/cosbench cosbench] — очень толстый, Java с Web-интерфейсом, XML-настройки** [https://github.com/markhpcvitalif/hsbench hsbench] — ссылка дана на исправленную версию (!). Максимально простой, консольное Golang приложение. Оригинальная версия пока что имеет 2 неприятных бага: во-первых, вместо чтения объектов целиком читает только первые 64 КБ, во-вторых, производит последовательное, а не случайное, чтение. Что, например, с minio приводит к слишком оптимистичным результатам тестов.** [https://github.com/minio/warp minio warp] — тестов чуть больше, чем в hsbench, но зато тестирует только 1 бакет и при каждом тесте загружает данные заново
Примечания:
* dd и hdparm для бенчмаркинга не использовать вообще никогда.!!!* rados bench использовать тоже не надо, т.к. так как он создаёт для тестирования очень мало объектов (в 1 поток всего 2, в 128 — 128 — несколько сотен). "Случайная" «Случайная» запись в такое число объектов не очень-то и случайная.
* rbd bench использовать можно, но fio лучше.
* Не надо удивляться, что Ceph не может загрузить диски на 100 100 % при случайной записи. Он тормоз :)
=== Тестирование сети ===
Кто задолбался со спилловерами? Все задолбались со спилловерами! :)
Спилловер — это когда вы собрали Bluestore на SSD+HDD, выделив SSD под базу (block.db), но при этом эта самая база постоянно частично утекает на HDD. При этом она, вроде бы, даже влезает в SSD с запасом — но всё равно утекает. Начиная, кажется, с Ceph 14 Nautilus, о спилловерах предупреждает <tt>ceph -s</tt>, а с Ceph 15 Octopus авторы попытались победить spillover-ы через дополнительные «allocation hint»-ы RocksDB(надо потестировать: коммит 5f72c376deb64562e5e88be2f22339135ac7372b, но, в целом, легче от всего этого не сталодобавили опцию bluestore_volume_selection_policy).
Когда случается спилловер в SSD+HDD конфигурациях, работа кластера замедляется — в большей или меньшей степени, в зависимости от размеров RocksDB и паттерна нагрузки, так как когда метаданных не очень много, они влезают в кэш OSD — либо onode cache, либо rocksdb cache, либо, если включено bluefs buffered io — то ещё и в системный page cache. Если кэш-промахов достаточно много, или если OSD упирается в compaction RocksDB, могут даже появляться slow ops-ы.
Так в чём же дело и как это победить? А дело в том, что с выбором раздела для очередного файла БД (RocksDB организована в виде набора файлов) «есть небольшой нюанс», точнее, даже два.
'''Нюанс № 1: ''' RocksDB кладёт файл на быстрый диск только когда считает, что на быстром диске хватит места под все файлы этого же уровня (для тех, кто ещё не в курсе — RocksDB это [https://github.com/facebook/rocksdb/wiki/Leveled-Compaction LSM база]).
Дефолтные настройки цефа:
Иными словами, имеют смысл только размеры раздела block.db 4 ГБ, 30 ГБ, 286 ГБ. Все промежуточные значения бессмысленны — место сверх предыдущего граничного значения использоваться не будет. Например, если БД занимает 10 ГБ, а раздел SSD — 20 ГБ, то фактически на SSD ляжет только WAL (1 ГБ), L1 и L2 (256 МБ + 2.56 ГБ). L3, составляющий бОльшую часть базы, уедет на HDD и будет тормозить работу.
При этом 4 ГБ — слишком мало, 286 ГБ — слишком много. Так что, по сути, правильно делать block.db размером хотя бы 30 ГБ для всех OSDлюбого размера.
Нюанс № 2: БываетКстати, из этого же следует то, что в момент compaction-а RocksDB требуется целиком переписать уровень целиком (не всегда, но бывает)официальная рекомендация — выделять под block. Если при этом на SSD нет запаса места в размере этого уровняdb то ли 2 %, то он, опять-таки, утечёт на HDD и так там и останется, ибо перемещать после compaction-а его обратно она не умеет. При этом одновременно могут компактиться как минимум первый и последний уровнили 4 % от размера устройства данных — полный отстой.
Из этого следует, Но что в идеале на разделе БД нужен ещё делать, если у вас разделы другого размера? Например, 80 ГБ, и запас в размере первого + последнего вы по каким-то причинам не хотите делать bcache, но хотите использовать эти 80 ГБ по максимуму. В этом случае можно поменять базовый размер уровня БДRocksDB (max_bytes_for_level_base). То multiplier менять не будем, оставим по умолчанию 10 — его значение влияет на итоговое количество уровней RocksDB, а это уже более тонкая материя. Теоретически, меньшее число уровней снижает read и space amplification, но замедляет compaction и из-за этого может сильно повысить итоговый write amplification. Также есть примерно 30 ГБ превращаются в примерно 60тема с уменьшением размера отдельных memtable и кратным увеличением общего их числа, то есть, например, установки 32*32 МБ вместо дефолтных 4*256 МБ и min_write_buffer_to_merge=8, но эффект от этого тоже не совсем понятен (возможно, немного экономится CPU при compaction-е), так что это тоже пока лучше не трогать.
Но что делать, если вам надо выделить под базы по 30 ГБ? Делать SSD разделы по 550 ГБ Так как-то уж очень жирнокаждый уровень отличается от предыдущего в 10 раз, но и спилловеров иметь не хочется. В этом случае можно поменять базовый общий размер уровня RocksDB (max_bytes_for_level_base). multiplier менять не будемраздела БД должен быть равен k*X, оставим где k — коэффициенты из ряда: 1, 11, 111, 1111 и т. п. (по умолчанию 10 — его значение влияет на итоговое количество числу уровней RocksDB). Значит, а это уже более тонкая материямы можем взять размер нашего block. Теоретическиdb, меньшее число уровней снижает read и space amplification, но замедляет compaction и вычесть из-за этого может сильно повысить итоговый write amplification. Также есть тема него 1 ГБ WAL (лучше даже вычесть с уменьшением размера отдельных memtable запасом 2 ГБ) и кратным увеличением общего их числаделить его последовательно на каждую из цифр до тех пор, то естьпока не получим значение, напримерблизкое к 256 МБ … 1 ГБ. Это значение округлить вниз, установки 32*32 принять за базовый размер уровня RocksDB и прописать в конфиг как max_bytes_for_level_base. База компактится по 256 МБ вместо дефолтных 4*за раз, так что меньше 256 МБ и min_write_buffer_to_merge=8размер первого уровня ставить точно смысла нет. Например, но эффект от этого тоже для 80 ГБ раздела это будет 719 МБ, только не совсем понятен забываем считать всё в двоичных мегабайтах — MiB. Остаётся прописать это значение в конфигурацию (возможноbluestore_rocksdb_options = …, немного экономится CPU при compaction-еmax_bytes_for_level_base=719MB), так что это тоже пока лучше не трогатьперезапустить OSD и сделать ручной compaction (можно дважды).
Итак'''Нюанс № 2:''' При ручном compaction-е RocksDB переписывает уровни целиком. Если при этом на SSD нет запаса места в размере этого уровня, помня про необходимость запаса под первый то уровень, опять-таки, утечёт на HDD и последний уровни выводимтак там и останется, ибо перемещать после compaction-а его обратно она не умеет. Теоретически, если после этого сделать compaction ещё раз, то уровень должен вернуться на SSD (поэтому выше дана рекомендация делать ручной compaction дважды). Однако по сведениям из чата якобы бывает так, что общий размер раздела БД должен быть равен kодин-два файла *X.sst на SSD не возвращается. Чтобы это побороть на 100 %, где X — размер можно предусмотреть на SSD-разделе ещё и запас в размере первого + последнего уровня, а k — БД. В этом случае коэффициенты из ряда: вместо 1-11-111-1111 превращаются в 2 (1 уровень), -22 (2 уровня), -212 (под 3 уровня), -2112 (под 4 уровня) и т. п.
Соответственно== RGW vs Minio == Вопрос частый, берём целевой максимальный размер нашей БД: 30 ГБтак как Ceph и Minio — две наиболее распространённые реализации S3. Это будет размер последнего уровня Сравнение, как всегда, не совсем честное, так как в Minio «бесконечного масштабирования» и произвольных схем избыточности нет. Делим его на 10 до тех порЕсть только erasure коды, пока значение которые оперируют группами дисков, кратными по количеству 4 или 16 дискам. Расширения кластера в Minio раньше не приблизится гдебыло вообще, потом в каком-то к гигабайту и принимаем это за размер первого уровнясмысле появилось через создание дополнительных зон. Компактится база по 256 МБ за  Таких же гарантий целостности, как в Ceph, в Minio тоже нет. Minio работает поверх обычных ФС, даже не делая fsync данных. На практике ext4, правда, делает sync автоматически разв 5 секунд, да и Minio пишет с O_DIRECT, так что меньше 256 МБ размер первого уровня ставить точно смысла не совсем всё плохо — но тем не менее, потенциально небольшие потери при отключении питания возможны. Особенно классный перл был в баге https://github.com/minio/minio/issues/3478: <blockquote>Minio in this case is working as intended, minio cannot be expanded or shrinkable in this manner. Minio is different by design. It is designed to solve all the needs of a single tenant. Spinning minio per tenant is the job of external orchestration layer. Any addition and removal means one has to rebalance the nodes. When Minio does it internally, it behaves like blackbox. It also adds significant complexity to Minio. Minio is designed to be deployed once and forgotten. We dont even want users to be replacing failed drives and nodes. Erasure code has enough redundancy built it. By the time half the nodes or drives are gone, it is time to refresh all the hardware. If the user still requires rebalancing, one can always start a new minio server on the same system on a different port and simply migrate the data over. It is essentially what minio would do internally. Doing it externally means more control and visibility. Minio is meant to be deployed in static units per tenant.</blockquote> Короче, всё работает как надо, в минио нетвозможности расширения, если у вас будут ломаться диски — не меняйте, просто дождитесь, пока из строя выйдет половина дисков и пересоздайте кластер. После этого число делений+1 принимаем за число уровнейНа самом деле всё не так печально, домножаем размер первого уровня можно заменить диск и запустить heal, но, конечно, без той же прозрачности, что в Ceph — оно будет просто сканировать все объекты и проверять отсутствующие. Если дисков много, это очень накладно. Ещё Minio хранит объекты в виде обычных файлов, даже не шардируя каталоги (соответствующие бакетам) по подкаталогам, плюс на соответствующий коэффициенткаждый объект ещё создаёт директорию с парой файлов метаданных. Ну а директории в ФС по миллиону файлов — это, накидываем +1 ГБ естественно, удовольствие ниже среднего. Хотя просто для WALраздачи оно, округляем чуть вверх благодаря всяким dir_index-ам, работает. Для представления о производительности проведём простой тест Ceph (bluestore) vs Minio (ext4) на 1 HDD. Да, я знаю, что это тупо и получаем необходимый размер раздела нужно ещё хотя бы посравнивать их на SSD. В случае с 30 ГБ — размер первого уровня будет 300 МБ, число уровней 3 Но всё-таки результаты довольно показательны. Да и требуемый размер объектное хранилище чаще холодное/прохладное и строится на HDD, а не на SSD раздела — около 65 ГБ. Прописываем это  Тест делался через [https://github.com/vitalif/hsbench hsbench]. Заключался в конфигурацию (bluestore_rocksdb_options = …заливке примерно 1.1 миллиона объектов в 1 бакет,max_bytes_for_level_base=300MB)потом сброса кэшей и перезапуска Ceph/Minio, деплоим OSD и радуемся жизнипотом — их раздачи в случайном порядке, а также проверки скорости выполнения операций листингов. НуРезультаты:* Заливка в 32 потока: Minio — 305 объектов в секунду, почти радуемсяRGW — 135 объектов в секунду. RGW indexless — 288 объектов в секунду.* Раздача в 32 потока: Minio — 45 объектов в секунду, так RGW — 78 объектов в секунду* Листинги в 32 потока: Minio — после сброса кэша 35 сек, после прогрева — 2.9 сек с разбросом от 0.5 до 16 сек. RGW — стабильно — 0.4 сек Да, заливка в Minio быстрее. Но, во-первых, меньшая скорость заливки — это цена, во-первых, консистентности (fsync), а во-вторых, bucket index-а и bucket index log-а, которые позволяют RGW, например, делать геосинхронизацию (multisite), чего в Minio нет. Кроме того, индексы в RGW можно положить на отдельные SSD (как 50 % этого раздела у нас используется только обычно все и делают), а если же вам совсем не нужны листинги, синхронизация и прочее, в момент компакшенаCeph бакеты можно сделать безиндексными (indexless), и тогда оверхед bucket index-а остальное время простаивает…вообще исчезает, как и возможные проблемы с его шардированием.
== Снапшоты ==
* Отключить объединение прерываний: ethtool -C enp3s0f0 rx-usecs 0
* Самый дешёвый 10G свитч с Ebay: Quanta LB6M / Brocade TurboIron 24X
 
Если совсем задолбала латенси, как отключить ВСЕ оффлоады?
 
<pre>
for i in rx tx tso ufo gso gro lro tx nocache copy sg txvlan rxvlan; do
/sbin/ethtool -K eth3 $i off 2>&1 > /dev/null;
done
</pre>
== Настройка виртуалок и ФС ==
Особенность NAND флеш-памяти заключается в том, что пишется она мелкими блоками, а стирается большими. Актуальное соотношение для Micron 3D NAND — страница (page) 16 КБ, блок стирания (block) — 16 или 24 МБ (1024 или 1536 страниц, MLC/TLC соответственно). Случайное чтение страницы быстрое. Запись тоже, но писать можно только в предварительно стёртую область — а стирание медленное, да ещё и число стираний каждого блока ограничено — после нескольких тысяч (типичное значение для MLC) блок физически выходит из строя. В более дешёвых и плотных (MLC, TLC, QLC — 2-4 бита на ячейку) чипах лимит стираний меньше, в более дорогих и менее плотных (SLC, один бит на ячейку) — больше. Соответственно, при «тупом» подходе — если при записи каждого блока его просто стирать и перезаписывать — случайная запись во флеш-память, во-первых, будет очень медленной, а во-вторых, она будет быстро выводить её из строя.
Но почему тогда SSD быстрые? А потому, что внутри SSD на самом деле есть очень мощный и умный контроллер (1-2 гигагерца, типично 4 ядра или больше, примерно как процессоры мобильников), и на нём выполняется нечто, называемое Flash Translation Layer — прошивка, которая переназначает каждый мелкий логический сектор в произвольное место диска. FTL всё время поддерживает некоторое количество свободных стёртых блоков и направляет каждую мелкую случайную запись в новое место диска, в заранее стёртую область. Поэтому запись быстрая. Одновременно FTL делает дефрагментацию свободного места и Wear Leveling (распределение износа), направляя запись и перемещая данные так, чтобы все блоки диска стирались примерно одинаковое количество раз. Кроме того, во всех SSD некоторый % реального места зарезервирован под Wear Leveling и не виден пользователю («overprovision»), а в хороших серверных SSD этот процент весьма большой — например, в Micron 5100 Max это +60 % ёмкости (в Micron 5100 Eco — всего лишь +7.5 %, 1.92 ТБ SSD содержит 10 чипов NAND по 1.5 терабита и 2 по 768 гигабит).
Именно из наличия FTL вытекает и проблема с энергонезависимостью и «power loss protection»-ом. Карты отображения секторов — это метаданные, которые при сбросе кэша тоже нужно сбрасывать в постоянную память, и именно этот сброс и вносит торможение в работу настольных SSD с fsync.

Навигация