Изменения

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

47 369 байтов добавлено, 15:34, 21 мая 2023
Нет описания правки
[[en:Ceph performance]][[File:Ceph-funnel.svg|500px|right]]
Ceph — это SDS (по-русски — программная СХД), которая по некоторым параметрам является уникальной в своём роде, и в целом, умеет очень многое — S3, диски виртуалок, кластерную FS + огромный багаж дополнительных фич.
 
И всё было бы хорошо — бери, ставь, запускай своё облако и руби бабло — если бы не один маленький нюанс: ПРОИЗВОДИТЕЛЬНОСТЬ. Терять 95 % производительности в Production-е разумным людям обычно жалко. «Облакам» типа AWS, GCP, Яндекса, по-видимому, не жалко — у них тоже собственные крафтовые SDS и они тоже тормозят примерно так же :-) но этот вопрос оставим — кто мы такие, чтобы их судить.
 
В данной статье описано, каких показателей производительности можно добиться от цефа и как. Если вкратце, то примерным ориентиром служит доклад Nick Fisk «Low-Latency Ceph», в его исполнении Low Latency это 0.7 мс (на запись). Лучший результат с Ceph-ом получить практически невозможно (худший — легко). При этом 0.7 мс — это всего лишь примерно ~1500 iops в 1 поток. На чтение в идеальной ситуации можно получить где-то раза в 2 больше, то есть где-то до 3000 iops в 1 поток.
 
Для сравнения: любой самый дешёвый серверный SSD-диск раз в 10 быстрее, средний порядок задержки SSD на запись — 0.01-0.04 мс, на чтение — 0.1 мс.
 
'''UPDATE: Догнать (почти догнать) SDS-кой локальной диск можно, я это сделал в своём собственном проекте — 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] — смотрите по ссылке.'''
 
== Бенчмаркинг ==
Задержки обычно важнее простой пиковой производительности случайного чтения/записи, так как далеко не каждое приложение может загрузить диск при большом параллелизме / глубокой очереди (32-128 запросов).
 
Ceph — это SDS, его задержки всегда выше, чем у устройств при прямом доступе, и от этого никуда не денешься. В интернете есть доклад Nick Fisk «Low-Latency Ceph», в его исполнении Low latency это 0.7ms, то есть на лучший результат рассчитывать особенно не приходится. 0.7ms — это всего лишь примерно ~1500 iops в 1 поток (хорошая новость — другие SDS и просто SAN-ы тоже тормозят :)).
=== Тестирование дисков ===
 
[https://docs.google.com/spreadsheets/d/1E9-eXjzsKboiCCX-0u0r5fAjjufLKayaut_FOPxYZjc SSD Bench Google Docs]
Сначала прогоните fio на голом диске:
* Задержка случайной записи: {{Cmd|1=fio -ioengine=libaio -sync=1 -direct=1 -invalidate=1 -name=test -bs=4k -iodepth=1 -rw=randwrite -runtime=60 -filename=/dev/sdX}}
«А почему так мало…» — см.нижесагу про конденсаторы.
[[Файл:Warning icon.svg|32px|link=]] Когда разворачиваете Ceph OSD на SSD — очень разумно не отдавать её под Ceph целиком, а оставить небольшой раздел (10-20 гб) пустым для будущего использования под бенчмаркинг. Ибо  Ибо SSD имеют свойство со временем (или при забивании данными под 80%) начинать тормозить. Очень удобно иметь возможность гонять fio на пустом никем не используемом разделе. ==== Лирическое отступление ==== Почему нужно тестировать именно так? Ведь в целом производительность диска зависит от многих параметров:* Размер блока* Режим — чтение, запись или смешанный режим чтение+запись в разных пропорциях* Параллелизм — размер очереди и число потоков, то есть, в целом число одновременно запрашиваемых у диска операций* Длительность теста* Исходное состояние — пуст, заполнен линейной записью, заполнен случайной записью, заполнен случайной записью на протяжении какого-то времени и т. п.* Распределение данных — например, 10% горячих данных и 90% холодных — или, например, определённое расположение горячих данных (в начале диска)* Другие смешанные режимы тестов, например, тестирование одновременно с разными размерами блоков Также и результаты можно интерпретировать с разной степенью детализации — вместо простого среднего числа операций или мегабайт в секунду можно также приводить графики, гистограммы, перцентили и так далее — это, естественно, даст больше информации о поведении тестируемого образца. Есть и философская сторона тестов — например, производители серверных SSD иногда заявляют о необходимости подготовки диска к тестам путём 2-х кратной полной случайной перезаписи, чтобы нагрузить слой трансляции адресов диска, а я считаю, что это на самом деле ставит SSD в неправдоподобно плохие по сравнению с реальной нагрузкой условия; есть сторонники рисования графиков формата «задержка в зависимости от числа операций в секунду», что я считаю немного странным, но тоже возможным подходом — в нём, по сути, строится график F1(q) в зависимости от F2(q) и график обычно получается достаточно замысловатый — но для каких-то применений, может быть, и тоже разумный. В общем, бенчмаркингом заниматься можно бесконечно, и уж несколько дней, чтобы предоставить полную информацию, точно уйдёт. Этим обычно и занимаются ресурсы типа 3dnews в своих обзорах SSD. А мы не хотим сидеть несколько дней. Мы хотим обозначить набор тестов, которые можно провести быстро и сразу составить примерное представление о производительности. Посему общая идея — выделить несколько наиболее «крайних» режимов, протестировать диск в них и представить, что остальная часть «амплитудно-скоростной характеристики» диска является некоторой гладкой функцией в пределах изменения параметров между крайними точками. Тем более, что каждому из крайних режимов соответствует и реальное применение в своей категории приложений:# Использующих в основном линейный или крупноблочный доступ. Для таких приложений наиболее важная характеристика — производительность линейного доступа в мегабайтах в секунду. Отсюда режим тестирования линейным доступом 4 МБ блоком со средней очередью — 16-32 операции. Результаты — только в МБ/с.# Использующих случайный доступ мелким блоком и при этом способных к распараллеливанию. Отсюда — режимы тестирования случайным доступом 4 КБ блоком (стандартный блок для большинства ФС и, плюс-минус, СУБД) с большой очередью — 128 операций или, если диск не удаётся нагрузить одним потоком CPU с глубиной очереди 128 — тогда в несколько (2-4-8 или больше) потоков по 128 операций. Результаты — только в iops. Задержку (latency) указывать не нужно, так как в данном тесте её можно произвольно увеличить, просто подняв размер очереди — задержка жёстко связана с iops формулой latency=queue/iops.# Использующих случайный доступ мелким блоком и при этом НЕспособных к распараллеливанию. Таких приложений больше, чем вы могли подумать — например, в части записи сюда относятся все транзакционные СУБД. Отсюда вытекают режимы тестирования случайным доступом 4 КБ блоком с очередью 1 и, для записи, с fsync после каждой операции, чтобы диск/СХД не могли нас обмануть и положить запись во внутренний кэш. Результаты — iops или latency, по желанию — но выберите что-то одно, так как числа, опять же, жёстко связанные.
=== Тестирование кластера Ceph ===
Как тестировать Ceph после сборки:.
* fio -ioengine=rbd. Нужно сделать следующее:*# fio -ioengine=rbd -direct=1 -name=test -bs=4M -iodepth=16 -rw=write -pool=rpool_hdd -runtime=60 -rbdname=testimg*# fio -ioengine=rbd -direct=1 -name=test -bs=4k -iodepth=1 -rw=randwrite -pool=rpool_hdd -runtime=60 -rbdname=testimg*# fio -ioengine=rbd -direct=1 -name=test -bs=4k -iodepth=128 -rw=randwrite -pool=rpool_hdd -runtime=60 -rbdname=testimg*: И потом то же самое для read/randread.*: Смысл в том, чтобы протестировать а) задержку в идеальных условиях б) линейную пропускную способность в) случайные iops-ы.*: Образ сначала нужно заполнить линейной записью, так как чтение из пустого образа очень быстрое :)*: Запускать оттуда, где будут реальные пользователи RBD. В целом, с другого узла результаты обычно лучше.* Всё то же самое через krbd.*# fio -ioengine=libaio -sync=1 -direct=1 -name=test -bs=4M -iodepth=16 -rw=write -pool=rpool_hdd -runtime=60 -rbdname=testimg*# fio -ioengine=rbd -direct=1 -name=test -bs=4k -iodepth=1 -rw=randwrite -pool=rpool_hdd -runtime=60 -rbdname=testimg*# fio -ioengine=rbd -direct=1 -name=test -bs=4k -iodepth=128 -rw=randwrite -pool=rpool_hdd -runtime=60 -rbdname=testimg* Всё то же самое изнутри виртуалки или через krbd:*# fio -ioengine=libaio -direct=1 -name=test -bs=4M -iodepth=16 -rw=write -runtime=60 -filename=/dev/rbdX*# fio -ioengine=libaio -direct=1 -sync=1 -name=test -bs=4k -iodepth=1 -rw=randwrite -runtime=60 -filename=/dev/rbdX*# fio -ioengine=libaio -direct=1 -name=test -bs=4k -iodepth=128 -rw=randwrite -runtime=60 -filename=/dev/rbdX*: Заметьте, что при тестировании задержки добавилась опция -sync=1. Это не случайно, а соответствует режиму работы СУБД (транзакционная запись в 1 поток). В ioengine=rbd понятие sync отсутствует, там всё всегда «sync».* ceph-gobench*: Или 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
Примечанияfio -ioengine=rbd. Нужно сделать следующее:# fio -ioengine=rbd -direct=1 -name=test -bs=4M -iodepth=16 -rw=write -pool=rpool_hdd -runtime=60 -rbdname=testimg# fio -ioengine=rbd -direct=1 -name=test -bs=4k -iodepth=1 -rw=randwrite -pool=rpool_hdd -runtime=60 -rbdname=testimg# fio -ioengine=rbd -direct=1 -name=test -bs=4k -iodepth=128 -rw=randwrite -pool=rpool_hdd -runtime=60 -rbdname=testimg# ...и потом то же самое для read/randread.
Смысл в том, чтобы протестировать а) задержку в идеальных условиях б) линейную пропускную способность в) случайные iops-ы. Перед тестами чтения образ сначала нужно заполнить линейной записью, так как чтение из пустого образа очень быстрое :) Запускать нужно оттуда, где будут реальные пользователи RBD. В целом, с другого узла результаты обычно лучше. Также всё то же самое можно повторить изнутри виртуалки или через krbd:# fio -ioengine=libaio -direct=1 -name=test -bs=4M -iodepth=16 -rw=write -runtime=60 -filename=/dev/rbdX# fio -ioengine=libaio -direct=1 -sync=1 -name=test -bs=4k -iodepth=1 -rw=randwrite -runtime=60 -filename=/dev/rbdX# fio -ioengine=libaio -direct=1 -name=test -bs=4k -iodepth=128 -rw=randwrite -runtime=60 -filename=/dev/rbdX Заметьте, что при тестировании задержки через libaio добавилась опция -sync=1. Это не случайно, а соответствует режиму работы СУБД (транзакционная запись в 1 поток). В ioengine=rbd понятие sync отсутствует, там всё всегда «sync». ==== Отдельные OSD ==== ceph-gobench: https://github.com/rumanzo/ceph-gobench/ Либо 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/vitalif/hsbench hsbench] — ссылка дана на исправленную версию (!). Максимально простой, консольное Golang приложение. Оригинальная версия пока что имеет 2 неприятных бага: во-первых, вместо чтения объектов целиком читает только первые 64 КБ, во-вторых, производит последовательное, а не случайное, чтение. Что, например, с minio приводит к слишком оптимистичным результатам тестов. В моей данные баги исправлены. [https://github.com/intel-cloud/cosbench cosbench] — очень толстый, Java с Web-интерфейсом, XML-настройки. [https://github.com/minio/warp minio warp] — тестов чуть больше, чем в hsbench, но зато тестирует только 1 бакет и при каждом тесте загружает данные заново. ==== Что использовать не надо ==== * dd и hdparm для бенчмаркинга не использовать вообще никогда.!!!* rados bench использовать тоже не надо, т.к. так как он создаёт для тестирования очень мало объектов (в 1 поток всего 2, в 128 — 128 — несколько сотен). "Случайная" «Случайная» запись в такое число объектов не очень-то и случайная.* rbd bench лучше тоже не использовать можно. В принципе, он адекватен, но fio всё равно лучше.* Не надо удивляться, что если Ceph не может загрузить диски на 100 100 % при случайной записи. Он тормоз :) ==== Про RBD и параллелизм ==== [[File:Warning icon.svg|32px|link=]] Тестировать запись несколькими параллельными процессами (fio numjobs > 1) в один RBD-образ бесполезно. Из-за особенностей реализации RBD, в частности, из-за object-map, при параллельной записи из нескольких источников производительность СИЛЬНО проседает (в 2-10 раз). Можно отключить object-map, но это будет некорректный тест, т.к. в реальной эксплуатации в 99% случаев он нужен, так что с отключенным object-map вы лишь получите неправильный (слишком хороший) результат. Если вы не можете загрузить кластер одним процессом fio, то нужно создать несколько отдельных RBD-образов и запустить несколько процессов fio параллельно, каждый на своём RBD-образе. === Тестирование сети === sockperf. На одной ноде запускаем сервер: <tt>sockperf sr -i IP --tcp</tt>. На другой клиент в режиме ping-pong: <tt>sockperf pp -i SERVER_IP --tcp -m 4096</tt>. ВНИМАНИЕ: В выводе фигурирует '''половина''' задержки (задержка в одну сторону). Таким образом, для получения RTT её стоит умножить на 2. Нормальный средний RTT - в районе 30-50 микросекунд (0.05ms). <s>Также qperf. На одной ноде просто <tt>qperf</tt>. На второй <tt>qperf -vvs -m 4096 SERVER_IP tcp_lat</tt>.</s> qperf написан криво: 1) всегда использует для tcp_lat размер сообщения 1 байт!!! 2) не использует TCP_NODELAY. Так что его юзать, только если возьмёте его с моим патчем отсюда: [[Мой Debian репозиторий]]. [[Файл:Warning icon.svg|32px|link=]] Внимание: в Ubuntu на сетевую задержку негативно влияет AppArmor, его лучше отключить. Картина примерно такая (Intel X520-DA2): * centos 3.10: rtt min/avg/max/mdev = 0.039/0.053/0.132/0.012 ms* ubuntu 4.x + apparmor: rtt min/avg/max/mdev = 0.068/0.163/0.230/0.029 ms* ubuntu 4.x: rtt min/avg/max/mdev = 0.037/0.071/0.157/0.018 ms
== О транзакционности записи ==
[[Файл:Warning icon.svg|32px|link=]] Плохая новость!
Важная особенность Ceph — ''вся запись, даже та, для которой никто этого явно не просит, ведётся транзакционно''. То есть, никакая операция записи не завершается, пока она не записана в журналы всех OSD и не сделан fsync() диска. Так сделано, чтобы предотвращать [[#RAID WRITE HOLE]]-подобные ситуации рассинхронизации данных между репликами при отключении питания, потере сети и т.п…
Это приводит к тому, что типичная настольная SSD под журналом в Ceph выдаёт '''неприлично низкие IOPS-ы''' — обычно от 500 до 2000. И это при том, что при обычном тестировании почти любая SSD выдаёт > 20000 iops. Даже самый паршивый китайский noname выдаёт не менее 10000 iops. NVMe легко выжимает 150000 и больше. Но стоит начать использовать fsync… и та же NVMe выдаёт 600 iops (на 2.5 порядка меньше).
 
<s>Без буфера записи, кстати, и 7200 rpm HDD — это не 120 иопс, а всего 40-50.</s> Сорри, наврал.
В общем, чтобы понять, сколько у вас теоретически может быть IOPS-ов на запись в Ceph, диски под него нужно тестировать с опциями fio '''sync=1 iodepth=1'''. Это даст «журнальные» иопсы (производительность последовательного коммита операций по одной).
== Конденсаторы ==
Нас спасёт такое чудо инженерной мысли, как '''SSD с конденсаторами''' (точнее, обычно или с суперконденсаторами — ионисторами). Которые на M.2 SSD, кстати, прекрасно видны невооружённым глазом(только тут это не ионисторы :)):
[[File:Micron 5100 sata m2.jpg]]
То есть, под Ceph следует закупать '''только''' SSD с конденсаторами. Даже если рассматривать NVMe — NVMe без конденсаторов хуже, чем SATA с оными.
И ещё один вариант — Intel Optane. Это тоже SSD, но они основаны не на Flash памяти (не NAND и не NOR), а на Phase-Change-Memory «3D XPoint». По спецификации заявляются 550000 iops при полном отсутствии необходимости в стирании блоков, кэше и конденсаторах. Но если даже задержка такого диска и равна 0.01мс005мс (она действительно равна), то задержка Ceph всё равно как минимум в 50 раз больше0.5-1мс, соответственно, с Ceph оптаны использовать чуть менее, чем бессмысленно — за большие деньги (1500$ за 960 гб, 500$ за 240 гб) вы получите не сильно лучший результат.
== Bluestore vs Filestore ==
Блюстор — «новое» хранилище. От «нового» хранилища честно ожидаешь лучшей или хотя бы не худшей производительности в любых во всех сценариях. Однако это, увы, не совсем так.
И таки да, при линейной записи Что лучше в Bluestore фактически в 2 раза быстрее Filestore — двойную запись там честно ликвидировали, крупные блоки пишутся только 1 раз — сразу на устройство, а не 2 (в журнал и потом на устройство).?
Но вот со * Ликвидирована двойная запись при линейной записи. Линейная запись быстрее в честных 2 раза практически в любых конфигурациях.* Отложенная запись, эффективная для HDD (и, частично, для очень плохих SSD). iops случайной записью всё записи в HDD-only конфигурациях почти в 2 раза больше, чем в Filestore. Правда, речь об iops на HDD не идёт в принципе, поэтому вся разница — 33 или 66 iops на 1 HDD.* Возможность использования EC под CephFS и RBD благодаря реализованной частичной перезаписи объектов в EC-пулах.* Эффективные снапшоты (благодаря «виртуальным клонам»): после снятия снапшота iops практически не падают, в отличие от Filestore, в котором они падают до считанных сотен даже на NVMe, так как при перезаписи даже 4 КБ после снятия снапшота в Filestore копируется целый 4 МБ объект.*: [[Файл:Warning icon.svg|32px|link=]] Увы, это относится только к '''rbd snapshot''', но не к '''rbd clone'''. Клоны неэффективны в Bluestore точно так же, как и в Filestore. Запись 4 КБ в клон точно так же выливается в копирование 4 МБ.* Это не так однозначнокритично, но в Bluestore есть поддержка сжатия и контрольных сумм данных.
* А что хуже? В HDD-only конфигурациях (по крайней мерецелом, если «снять ручник» httpsпретензии сводятся к производительности://tracker.ceph.com/issues/38559) по random 4k write iops Bluestore тоже в честных 2 раза быстрее, чем Filestore.*: Фактически можно сказать, что для HDD и плохих SSD схема записи Bluestore по-настоящему оптимальна и выжимает максимум, который возможно выжать из диска в транзакционном режиме* В HDD+SSD кластерах Гораздо хуже производительность у Bluestore идеально стабильная, но сильно меньшая, чем у Filestore в пике. От блюстора невозможно добиться «сглаживания пиков» случайной записи через на SSD+HDD, SSD-журналраздел не работает как буфер для быстрой записи. Он устроен так, что отказывается писать Bluestore не пишет быстрее, чем может в среднем может писать сам HDD. То есть даже , с SSD-журналом вы получите лишь 100—200 iops и Filestore будет 1000—2000 иопс случайной записи, а с 1 диска — в то времяBluestore (и без bcache) — 200—300. 1000—2000, как в конечно, упадёт до 100 или даже ниже, когда у Filestoreзабьётся журнал и его придётся сбрасывать — но тем не менее, пока в журнале есть место, можно иметь 1000—2000 iops«буфер» для сглаживания пиков Filestore предоставляет. А Bluestore — нет.
*: И проблема не только в том, что параметры по умолчанию — deferred_batch_ops и max_deferred_txc — задают частый сброс операций на медленный диск (раз в 64 операции). Проблема ещё в том, что в Bluestore отсутствуют механизмы фоновой очистки «журнала» (очереди отложенной записи). Поэтому, когда очередь забивается, производительность просто падает до HDD-шной до перезапуска OSD. Ну и сама очередь находится в RocksDB, поэтому сильно поднимать её размер, по идее, неполезно.
* В До 1.5-2 раз хуже latency случайной записи на SSD/NVMe (All-Flash кластерах (то есть), ибо накладных расходов на быстрых дисках) каждую операцию записи у Bluestore латентнее больше.* Жор памяти больше. Да, у Filestoreмного занимал pagecache, возможно, на 30-50 %но Bluestore меньше 2 ГБ памяти не жрёт вообще никогда. Однако эти 30Причиной тому — RocksDB (одни только memtable-50 % относятся к latency именно самого блюстора, в абсолютном выражении составляют ~0.ы с дефолтными настройками съедают 1 мс ГБ памяти) и на фоне общей задержки Ceph-а практически собственный кэш метаданных и данных (Bluestore не заметны. Кроме того, latency ничего не говорит о параллельной пиковой пропускной способности, а она по крайней мере не хуже, чем в Filestore (обычно чуть лучше, +5..10 %может использовать pagecache). Жор CPU тоже чуть меньше.* Жор памяти у Bluestore ощутимо больше, потому что RocksDB и потому что кэш у него собственный вместо использования системного page cache-а, как в FilestoreФрагментация приводит к снижению скорости чтения.
Также BlueStore делает огромное количество fsync-ов (что очень смешно — даже больше, чем запросов записи), из-за чего не терпит десктопных SSD под журналом. Но FileStore работает похоже, и кардинальных различий производительности это не вносит. Как полечить медленный коммит высокие задержки на SSD+HDD?
* Либо вместо журнала (или рядом с журналом) сделать на SSD bcache для HDD.
* Либо использовать HDD с SSD Cache, Media Cache или аналогом (перманентным кэшем случайной записи на пластинах). Например, в старых дисках HGST это включается при отключении волатильного кэша командой `hdparm -W 0 /dev/sdXX`. В новых, похоже, включено всё время.
Также BlueStore делает огромное количество fsync-ов (что очень смешно — даже больше, чем запросов записи), из-за чего не терпит десктопных SSD под журналом. Но FileStore работает похоже, и кардинальных различий производительности это не вносит.=== Тест на 1 NVMe ===
Ну и ещё FileStore отстаёт от BlueStore по функциональности:* Снапшоты там работают со скоростью LVMThreadripper 2920X, то естьNVMe Intel P4500, при записи 4 кб после снятия снапшота копируется весь 4 Мб объектlocalhost. То есть1 OSD без репликации, после снятия снапшота 8 PG, чтобы не упираться в блокировки, 1 маленький RBD ВМ тормозятобраз 10 Гб.* Плюс отсутствуют некоторые другие фичи BlueStore: нет частичной перезаписи в EC-пулах (соответственноЖурнал Filestore 1 GB, EC нельзя использовать под CephFS чтобы в тестах успевал начинаться сброс. Bluestore 4k — это min_alloc_size и RBD), нет сжатия prefer_deferred_size = 4096 (хотя оно и не особо нужно4k запись идёт через redirect-write), нет контрольных сумм Bluestore 16k — 16384 (4k запись идёт через deferred). <tab sep="bar" head="topleft" class="wikitable">| Filestore | Bluestore 16k | Bluestore 4k |bs=4M iodepth=16 rw=write | 950 MB/s | 1700 MB/s | 1700 MB/s |bs=4M iodepth=16 rw=read | 1250 MB/s | 1300 MB/s | 1300 MB/s | После полной линейной перезаписи + drop_cachesbs=4M iodepth=16 rw=read | 1250 MB/s | 450 MB/s | 320 MB/s | После 33 % случайной перезаписи блоком min_alloc_sizebs=4k iodepth=1 rw=randwrite | 3900 iops | 3200 iops | 2500 iops |bs=4k iodepth=128 rw=randwrite | 19100 iops | 19500 iops | 25500 iops |bs=4k iodepth=1 rw=randwrite | 180 iops | 2800 iops | 2500 iops | Сразу после снятия snapshot-а вот они полезны, в частности, изRBDbs=4k iodepth=128 rw=randwrite | 180 iops | 8800 iops | 15600 iops | Сразу после снятия snapshot-за их отсутствия нельзя использовать sizeа RBDbs=4k iodepth=1 rw=randread | 3900 iops | 4500 iops | 4500 iops | После drop_caches / перезапуска OSDbs=4k iodepth=1 rw=randread | 6300 iops | 4500 iops | 4500 iops | Прогретый кэшbs=4k iodepth=128 rw=randread | 33000 iops | 32000 iops | 33000 iops |RAM | 270 MB | 2).GB + | | Filestore также использует произвольный объём page cacheCPU randwrite Q=128 | 600 % | 550 % | |</tab>
=== Про размер block.db ===
В общем'''Внимание:''' актуально до Ceph 14. Начиная с Ceph 15, благодаря добавленным «allocation hints» RocksDB, Bluestore стал нормально утилизировать раздел block.db. Для истории — это коммит 5f72c376deb64562e5e88be2f22339135ac7372b, там добавили опцию bluestore_volume_selection_policy. Дальше стоит читать, только если у вас всё ещё проблемы со spillover-ами. Спилловер — это когда вы собрали Bluestore на SSD+HDD, выделив SSD под базу (block.db), но при этом эта самая база постоянно частично утекает на HDD. При этом она, вроде бы, даже влезает в SSD с запасом — но всё равно утекает. Начиная с Ceph 14 Nautilus о спилловерах предупреждает <tt>ceph -s</tt>. Когда случается спилловер в 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 база]).
Дефолтные настройки цефа:
* 1 Гб WAL = 4x256 Мб
* max_bytes_for_level_base и max_bytes_for_level_multiplier не изменены, поэтому равны 256 Мб и 10 соответственно
* соответственно , L1 = 256 Мб
* L2 = 2560 Мб
* L3 = 25600 Мби т. д.
…Соответственно!
Rocksdb положит L2 на block.db, только если раздел имеет размер хотя бы 2560+256+1000 Мб (Мб — округлим вверх до '''4 ГбГБ'''. А L3 она положит на block.db, только если block.db размером хотя бы 25600+2560+256+1000 МБ = около '''30 ГБ'''. А L4, соответственно, если ещё +256 ГБ, то есть итого '''286 ГБ'''. Иными словами, имеют смысл только размеры раздела block.db 4 ГБ, 30 ГБ, 286 ГБ. Все промежуточные значения бессмысленны — место сверх предыдущего граничного значения использоваться не будет. Например, если БД занимает 10 ГБ, а раздел SSD — 20 ГБ, то фактически на SSD ляжет только WAL (1 ГБ), L1 и L2 (256 МБ + 2.56 ГБ). L3, составляющий бОльшую часть базы, уедет на HDD и будет тормозить работу. При этом 4 ГБ — слишком мало, 286 ГБ — слишком много. Так что, по сути, правильно делать block.db размером 30 ГБ для OSD любого размера. Ещё раз повторюсь: это актуально до Ceph 14, с Ceph 15 уже не актуально. Кстати, из этого же следует то, что официальная рекомендация — выделять под block.db то ли 2 %, то ли 4 % от размера устройства данных — полный отстой. Но что делать, если у вас разделы другого размера? Например, 80 ГБ, и вы по каким-то причинам не хотите делать bcache, но хотите использовать эти 80 ГБ по максимуму. В этом случае можно поменять базовый размер уровня RocksDB (max_bytes_for_level_base). multiplier менять не будем, оставим по умолчанию 10 — его значение влияет на итоговое количество уровней RocksDB, а это уже более тонкая материя. Теоретически, меньшее число уровней снижает read и space amplification, но замедляет compaction и из-за этого может сильно повысить итоговый write amplification. Также есть тема с уменьшением размера отдельных memtable и кратным увеличением общего их числа, то есть, например, установки 32*32 МБ вместо дефолтных 4*256 МБ и min_write_buffer_to_merge=8, но эффект от этого тоже не совсем понятен (возможно, немного экономится CPU при compaction-е), так что это тоже пока лучше не трогать. Так как каждый уровень отличается от предыдущего в 10 раз, общий размер раздела БД должен быть равен k*X, где k — коэффициенты из ряда: 1, 11, 111, 1111 и т. п. (по числу уровней RocksDB). Значит, мы можем взять размер нашего block.db, вычесть из него 1 ГБ WAL (лучше даже вычесть с запасом 2 ГБ) и делить его последовательно на каждую из цифр до тех пор, пока не получим значение, близкое к 256 МБ … 1 ГБ. Это значение округлить вниз, принять за базовый размер уровня RocksDB и прописать в конфиг как max_bytes_for_level_base. База компактится по 256 МБ за раз, так что меньше 256 МБ размер первого уровня ставить точно смысла нет. Например, для 80 ГБ раздела это будет 719 МБ, только не забываем считать всё в двоичных мегабайтах — MiB. Остаётся прописать это значение в конфигурацию (bluestore_rocksdb_options = …,max_bytes_for_level_base=719MB), перезапустить OSD и сделать ручной compaction (можно дважды). '''Нюанс № 2:''' При ручном compaction-е RocksDB переписывает уровни целиком. Если при этом на SSD нет запаса места в размере этого уровня, то уровень, опять-таки, утечёт на HDD и так там и останется, ибо перемещать после compaction-а его обратно она не умеет. Теоретически, если после этого сделать compaction ещё раз, то уровень должен вернуться на SSD (поэтому выше дана рекомендация делать ручной compaction дважды). Однако по сведениям из чата якобы бывает так, что один-два файла *.sst на SSD не возвращается. Чтобы это побороть на 100 %, можно предусмотреть на SSD-разделе ещё и запас в размере первого + последнего уровня БД. В этом случае коэффициенты вместо 1-11-111-1111 превращаются в 2-22-212-2112 и т. п. == RGW vs Minio == Вопрос частый, так как Ceph и Minio — две наиболее распространённые реализации S3. Сравнение, как всегда, не совсем честное, так как в Minio «бесконечного масштабирования» и произвольных схем избыточности нет. Есть только erasure коды, которые оперируют группами дисков, кратными по количеству 4 или 16 дискам. Расширения кластера в Minio раньше не было вообще, потом в каком-то смысле появилось через создание дополнительных зон. Таких же гарантий целостности, как в Ceph, в Minio тоже нет. Minio работает поверх обычных ФС, даже не делая fsync данных. На практике ext4, правда, делает sync автоматически раз в 5 секунд, да и Minio пишет с O_DIRECT, так что не совсем всё плохо — но тем не менее, потенциально небольшие потери при отключении питания возможны. Особенно классный перл был в баге 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> Короче, всё работает как надо, в минио нет возможности расширения, если у вас будут ломаться диски — не меняйте, просто дождитесь, пока из строя выйдет половина дисков и пересоздайте кластер. На самом деле всё не так печально, можно заменить диск и запустить heal, но, конечно, без той же прозрачности, что в Ceph — оно будет просто сканировать все объекты и проверять отсутствующие. Если дисков много, это очень накладно. Ещё Minio хранит объекты в виде обычных файлов, даже не шардируя каталоги (соответствующие бакетам) по подкаталогам, плюс на каждый объект ещё создаёт директорию с парой файлов метаданных. Ну а директории в ФС по миллиону файлов — это, естественно, удовольствие ниже среднего. Хотя просто для раздачи оно, благодаря всяким dir_index-ам, работает. Для представления о производительности проведём простой тест Ceph (bluestore) vs Minio (ext4) на 1 HDD. Да, я знаю, что это тупо и нужно ещё хотя бы посравнивать их на SSD. Но всё-таки результаты довольно показательны. Да и объектное хранилище чаще холодное/прохладное и строится на HDD, а не на SSD. Тест делался через [https://github.com/vitalif/hsbench hsbench]. Заключался в заливке примерно 1.1 миллиона объектов в 1 бакет, потом сброса кэшей и перезапуска Ceph/Minio, и потом — их раздачи в случайном порядке, а также проверки скорости выполнения операций листингов. Результаты:* Заливка в 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 (как обычно все и делают), а если же вам совсем не нужны листинги, синхронизация и прочее, в Ceph бакеты можно сделать безиндексными (indexless), и тогда оверхед bucket index-а вообще исчезает, как и возможные проблемы с его шардированием. == Снапшоты == В реализации снапшотов в Ceph есть целый ворох проблем из-за количества параллельных реализаций и общего накопленного архитектурного бардака: * На уровне RADOS снапшоты свои и их уже 2 вида: снапшоты пулов и снапшоты объектов.* На уровне RBD тоже свои снапшоты, причём они отличаются от RADOS-снапшотов, хоть внутри и реализованы частично через них. RBD снапшоты, можно сказать, не юзабельны ни для чего, кроме быстрого снятия бэкапов, за которым тут же следует удаление снапшота. Откат к RBD снапшотам очень медленный и реализован не просто ужасно, а отвратительно — копированием содержимого снапшота поверх образа, ''даже неизменённых частей''. Кроме того, при откате цепочка последующих снапшотов уничтожается. Кроме того, есть прикол с жором места — см. на 2 пункта ниже.* В Bluestore снапшоты эффективны — после снятия снапшота случайная запись практически не замедляется, в отличие от Filestore, где принцип работы снапшотов схож со старым LVM и при записи даже 4 КБ после снятия снапшота соответствующий 4 МБ объект копируется целиком.* Но при этом эта оптимизация снапшотов — «виртуальные клоны» — реализована именно на уровне Bluestore, ни клиент, ни OSD о ней ничего не знают и поэтому она… ломается при ребалансе. Выглядит это так: ты добавляешь в кластер диск, он заполняется, а доступного места больше не становится. Почему? Потому что изначально, при записи, Bluestore получил запрос «клонировать 4 МБ объект в новую версию» и сделал это внутри себя, реально не копируя данные, а потом перезаписал 4 КБ. А при ребалансе эта связь порвалась и объект стал занимать все 4 МБ… Fail.* Также на уровне RBD есть клоны, которые, с одной стороны, более юзабельны — реализованы они через ссылку на родительский образ, соответственно, откат к такому «снапшоту» быстрый — достаточно просто создать новый клон. С другой стороны, для клонов не работает эта самая блюсторовская оптимизация, поэтому они опять-таки копируют объекты целиком при любой записи… что выливается в 40 иопс на запись (QD=1) в свежий клон даже в NVMe кластере.* В CephFS ещё одна реализация снапшотов, и там отката нет вообще. В общем, наговнокодили — мама не горюй… == EC == EC ещё больше снижает iops-ы, так как добавляется цикл Read-Modify-Write. [[#RAID WRITE HOLE]] в цефе закрыт, поэтому при записи все OSD сначала делают вторые копии объекта (по-видимому, виртуальные, через тот же механизм virtual clone bluestore), а потом удаляют старые.
А L3 она положит В моём примере на block.dbNVMe-шках — write iops с репликацией Q=1 примерно 1500, только если blockа с EC — примерно 500.db размером хотя бы 25600+2560+256+1000 Мб Q= около 30 Гб128 — примерно 25000 с репликацией и 10000 с EC.
А L4, соответственно, если ещё +256, то есть итого 286 Гб.=== Про вероятность потери данных ===
Иными словами, имеют смысл только размеры раздела block.db 4 Гб, 30 Гб, 286 Гб. Все промежуточные значения бессмысленны — место сверх предыдущего граничного значения использоваться не будетСмотрите мой калькулятор вероятности потери данных в кластере: https://yourcmc.ru/afr-calc/
== Контроллеры ==
* …Но менять их бесполезно, поднять производительность таким образом не получается абсолютно, дефолтные значения (1x5 на HDD и 2x8 на SSD) оптимальны. kv_sync_thread-то всё равно только один.
* Есть одна мера, которая помогает поднять производительность сразу раза в 2-3: отключение экономии энергии процессором:
** <tt>cpupower idle-set -D 10</tt> — отключает C-States (либо опции ядра processor.max_cstate=1 intel_idle.max_cstate=0)** <tt>cpupower frequency-set -g performance</tt> или (старое) <tt>for i in $(seq 0 $((`nproc`-1))); do cpufreq-set -c $i -g performance; done</tt> — отключает снижение частоты через множитель
* После этих двух команд процессор начинает греться как ПЕЧ, но iops-ы увеличиваются сразу раза в 2 (а то и 3)
* Также жор CPU — одна из причин НЕ делать из Ceph «гиперконвергентное облако» (в котором совмещены узлы хранения и запуска виртуальных машин)
* Ещё можно отключить все mitigation-ы аппаратных уязвимостей: noibrs noibpb nopti nospectre_v2 nospectre_v1 l1tf=off nospec_store_bypass_disable no_stf_barrier
 
== Сеть ==
 
* Разумеется, 10 Гбит/с или быстрее
* MTU 9000: ip l set enp3s0f0 mtu 9000
* Отключить оффлоады: ethtool -K enp3s0f0 gro off gso off tso off lro off sg off
* Отключить объединение прерываний: ethtool -C enp3s0f0 rx-usecs 0
* Самый дешёвый 10G свитч с Ebay: Quanta LB6M / Brocade TurboIron 24X — но говно старое унылое и жрёт под 200 ватт, и греется и жужжит соответственно
* UPD Самый дешёвый свитч с Aliexpress: [https://aliexpress.ru/item/1005004429524441.html TP-LINK TL-ST5008F]. На чипе [https://www.realtek.com/en/products/communications-network-ics/item/rtl9303-cg Realtek RTL9303-CG]
 
Если совсем задолбала латенси, как отключить ВСЕ оффлоады?
 
<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>
== Настройка виртуалок и ФС ==
* С дефолтными опциями qemu подключает RBD, увы, криво.* Криво — это значит, что а) используется медленная эмуляция lsi-контроллера б) используется режим с кэшированием чтения, но без кэширования записи.* Кэш в qemu регулируется опцией, собственно, cache. Бывает <не указано>, writethrough, writeback, none, unsafe, directsync. С RBD эта опция регулирует работу rbd cache, т.е. кэша на стороне клиентской библиотеки Ceph (librbd).* Но cache=unsafe с RBD не работает, операции записи всё равно ждут подтверждения. А writethrough, <не указано> и directsync, по сути, эквивалентны.* RBD cache сильно помогает на HDD, но на SSD-кластере наоборот вносит заметное торможение. Что-то там сделано с блокировками, что-то там однопоточное, всё это оптимизируют, но пока не оптимизировали.* Есть следующие способы эмуляции дисков: lsi (самый медленный), virtio-scsi (достаточно быстрый), virtio (самый быстрый, но до QEMU 4.0 не умел TRIM). Вообще virtio-scsi умеет multiqueue и поэтому на быстром хранилище (например, при прямом доступе к локальной NVMe) должен быть быстрее virtio — но в случае с Ceph multiqueue, по-видимому, значения не имеет.* А ещё тормозит файловая система! Конкретно, если у вас не включена опция lazytime, то при каждой мелкой записи ФС обновляет mtime, то есть время модификации inode-а. Так как это метаданные, а ФС журналируемые — это изменение журналируется. Из-за этого при тесте <tt>fio -sync=1 -iodepth=1 -direct=1</tt> поверх ФС без lazytime iops-ы уменьшаются в 3-4 раза.* А если у вас (не дай бог) внутри Oracle, то ему надо обязательно поставить опцию FILESYSTEMIO_OPTIONS=SETALL.
ПоэтомуКриво — это значит, что:: а) используется медленная эмуляция lsi-контроллера: б) неправильно настроен кэш === Драйвер виртуального диска и ФС === В qemu есть следующие способы эмуляции дисков:* Для HDD / SSD+HDD крайне желательно lsi — самый медленный* virtio — самый быстрый, но до QEMU 4.0 не умел TRIM. Юзать надо его.* virtio-scsi — достаточно быстрый. На самом деле, умеет multiqueue и поэтому на уровне виртуалок включать опцию qemu быстром хранилище (например, при прямом доступе к локальной NVMe) должен быть быстрее virtio — но в случае с Ceph это не так, так как цеф не настолько быстрый, чтобы multiqueue играл роль* nvme — тоже достаточно быстрый, но немного медленнее virtio. Принцип работы похожий — и там, и там кольцевые буферы. Можно использовать для тех образцов ПО, которые не умеют virtio, потому что не уметь nvme сейчас совершенно точно не может никто. Например, если хочется потестировать VMWare ESXi с вложенной виртуализацией внутри QEMU, то nvme — для вас! === cache=writeback=== Кэш дисков в qemu регулируется опцией, собственно, cache. Этот режим безопасныйБывает <не указано>, так как fsync-writethrough, writeback, none, unsafe, directsync. С Ceph RBD эта опция регулирует работу rbd cache, то есть кэша на стороне клиентской библиотеки Ceph (librbd). RBD cache маленький (32 МБ) и от гостевых ВМ заставляют qemu сбрасывать кэш является аналогом буфера записи на HDD, то есть, предназначен исключительно для группировки операций записи перед, собственно, отправкой их в хранилище. Режимы writethrough, <не указано> и directsync с RBD, по сути, эквивалентны и означают отсутствие кэширования записи (каждая операция отправляется сразу в Ceph). Режим writeback означает «честное» (безопасное) кэширование записи. То есть, транзакционно записываемые данные не теряютсяоперации записи без fsync ложатся в кэш и отправляются оттуда либо раз в rbd_cache_max_dirty_age (по умолчанию 1 сек), либо когда ВМ просит fsync.* Для SSD-only лучше выключать Режим unsafe означает «нечестное» (чреватое потерей данных) кэширование записи. Операции записи также ложатся в кэш вообще , но fsync от ВМ игнорируются. Транзакционность в виртуалке отсутствует, но и производительность повышается. Использовать этот режим можно только для виртуалок, не содержащих ценные данные (например, для каких-нибудь тестов или CI). При среднем применении правильный режим — '''cache=none)writeback'''. Грубо говоря, максимальные параллельные iops на запись от этой процедуры растут cache=writeback увеличивает результат следующего теста:  fio -name=test -ioengine=libaio -direct=1 -bs=4k -iodepth=1 -rw=randwrite -filename=/dev/vdb # без -fsync и без -sync …примерно приводя его к результату того же теста с примерно 11000 до ~25000<tt>iodepth=32</tt>{{Note}} ОДНАКО, есть НЮАНСЫ (как всегда с цефом…): * Лучше всего использовать драйвер virtio. Как всё это настраивается в вашем GUI виртуалок Если RBD-образ пустой и при этом на нём включён object-map (Proxmoxпо умолчанию включён, Opennebulaсм. <tt>rbd info <pool>/<image></tt>) — отдельная песня :, то сброс кэша становится однопоточным И ФИГ ВЫ ВИДИТЕ улучшение результата fio.* Если опция rbd_cache_writethrough_until_flush равна true (так по умолчанию) в опеннебуле сделано довольно, то до первого fsync кэш не работает. То есть, если вы монтируете к виртуалке диск и сразу тестируете его вышеприведённой командой — вы опять-таки через жопуне увидите хороших результатов.* Обязательно используйте Из-за той же опции, стоящей в true, cache=unsafe не работает вообще. В Proxmox включен патч, который заставляет qemu ставить эту опцию монтирования автоматически. Если у вас не Proxmox — опцию нужно прописать в конфиг глобально: rbd_cache_writethrough_until_flush=false.* Сам кэш может являться тормозом в SSD-кластерах. Что-то там сделано с блокировками, что-то там однопоточное, всё это оптимизируют, но пока не оптимизировали. Например, 4K randwrite Q128 с rbd_cache=false может достигать 20000 iops, а с rbd_cache=true — только 11000 iops. Для говнософта, который пишет на диск абы как, это торможение оправдано, а для, например, СУБД — нет. Поэтому в случае, если у вас SSD и вам нужны в первую очередь random iops, то правильный режим — '''cache=none'''. === ФС === А ещё тормозит файловая система! Конкретно, если у вас не включена опция <tt>mount -o lazytime</tt>, то при каждой мелкой записи ФС обновляет mtime, то есть время модификации inode-а. Так как это метаданные, а ФС журналируемые — это изменение журналируется. Из-за этого при тесте <tt>fio -sync=1 -iodepth=1 -direct=1</tt> поверх ФС без lazytime iops-ы уменьшаются в 3-4 раза. Для неё lazytime нужны свежие ядра: с ext4 — хотя бы 4.0, с XFS — хотя бы 4.17. Также нужны соответствующие (свежие) util-linux (подсказка: в протухшей 7-й центоси их нет, поставить можно только из исходников). А если у вас (не дай бог) внутри Oracle, то ему надо обязательно поставить опцию FILESYSTEMIO_OPTIONS=SETALL. Производительность случайной записи в CephFS почти не отличается от RBD. Производительность случайной записи в CephFS через mount -t cephfs и через ceph-fuse… при iodepth=1 почти не отличается. А вот при iodepth=128 ядерный клиент ведёт себя нормально, а ceph-fuse выдаёт столько же, сколько при iodepth=1 (то есть на порядок/порядки меньше, чем ядерный клиент).
== Оценка производительности кластера ==
* Оценка производительности кластера просто по спецификациям входящих в него SSD не совсем верна дисков — абсолютно неправильна. Речь о Bluestore. Под iops понимаются iops случайного чтения/записи блоками по 4 кб. 1 HDD (точнееобычный, 7200 rpm, скорее совсем не верна)SMR, причём в обе стороныбез ssd-кэша) — это:*~100-120 iops при QD=128* Bluestore~66 iops при QD=1* ~40 MB/s линейного чтения/записи* При недостатке памяти показатели будут хуже, видимотак как будут cache miss по метаданным 1 быстрый SSD или NVMe SSD (с конденсаторами, за счёт параллелизма, выдаёт чуть больше write iops >= 25000):* ~1000 iops-ов даже на SSD без конденсаторовзапись при QD=1, чем просто те же ssd могут выдать с fsync — я лично смог добиться в зависимости от тестового пула частоты CPU и настроек может быть от 300 до, в самом идеальном случае, ~2500 iops.* Максимум до ~10000-20000 iops на 3запись при QD=128 на 1 OSD.* На чтение показатели примерно в 2-х Intel SSDSC2KW256G8 8000 2.5 раза лучше: QD=1 ~2000 iops (случайная записьмаксимум до ~4000), хотя сами ssd с fsync выдают примерно 5500QD=128 ~20000, максимум до 50000.** И обратноЕстественно, даже если SSD мегабыстраяпоказатель QD=128 не может быть больше, цеф — это огромный оверхед, он жрёт проц и никаких 220000 iops из одной чем показатель самого диска :). Но так как хорошие SSD в параллельном режиме обычно быстрые — этого не выжметзамечаешь. См. ниже [[#Пример теста от Micron]] — там в суперкрутом сетапе у них вышло всего 8750 * Создав несколько OSD на одном диске, можно умножить число QD=128 iops в пересчёте на 1 NVMe число OSD (после небольшого тюна они улучшили результат до ~12000 iops на 1 NVMeпока диск позволяет). Естественно, ценой аналогичного увеличения жора CPU.* Можно считать, что лимит iops-ов в пересчёте на одну SSDСкорость линейного чтения/NVMe находится на уровне ~10000-15000записи примерно равна скорости линейного чтения/записи самого диска.* Большой Кардинальной разницы по iops между хорошей SATA SSD и даже NVMe в цефе — , если у обоих есть конденсаторы — нет. Это не отменяет того, что NVMe лучше, но на случайном доступе это заметить трудно.* Если SATA На актуальных SSD плохая — разница естьчтение QD=1 часто бывает медленнее записи QD=1, так как писать можно в быстрый кэш, а читать можно только из реальной памяти. Разница бывает примерно такая:) плохим можно считать всёна чтение при QD=1 8000 iops, что даёт меньше 20000 а на запись 40000 iops в один поток с sync.* <s>Лайфхак для ускорения однопоточной нагрузкиИтоговые показатели: mdadm RAID 0 * Линейное чтение из RBD-образов внутри самой виртуалки<кластера = Число OSD * MB/s> — проверено, не работает.одного OSD* Лайфхак для очень быстрых дисков: несколько Линейная запись в реплицированный пул = Число OSD / Репликация * MB/s одного OSD на одном диске — работает, но ценой сильного увеличения жора CPU.* Гипотетический монстр производительности Линейная запись в вакууме: мощные процы, Intel NVMe, сеть 25EC-пул = Число OSD / (K+ ГбитM) * K * MB/с или Infiniband, <s>SPDK/DPDK</s> (SPDK работаетодного OSD* С iops всё сложнее, но не даёт прироста, DPDK не работает вообще)так как репликация вносит нелинейный эффект в масштабирование.Но, условно говоря:** iops QD=1 — усредняются по всем OSD, а iops QD=128 — суммируются** При этом на 1 RBD клиента можно получить лишь до ~30000 iops на чтение и ~15000 iops на запись* Естественно, если что-то упирается в сеть — соответствующая цифра обрезается показателем сети
== Картина маслом «Тормозящий кэш» ==
=== O_SYNC vs fsync vs hdparm -W 0 ===
У SATA и SCSI дисков есть два способа сброса кэша: команда FLUSH CACHE и флаг FUA (Force Unit Access) на команде записи. Первый — это явный сброс кэша, второй — это указание записать операцию на диск, минуя кэш. Точнее, у SCSI оно есть, а с SATA ситуация точно не ясна: в спецификации NCQ бит FUA есть, но по факту FUA большинством дисков вроде как не поддерживается и, соответственно, эмулируется ядром/контроллером (если контроллер не кривой).
По всей видимости, fsync() отправляет диску команду FLUSH CACHE, а открытие файла с O_SYNC устанавливает бит FUA на все команды записи.
# Блюстор блокирует запись в журнал записью на HDD. Когда включен спец.кэш, HDD начинает рандомно писать сильно быстрее, и блокировки при сбросе уходят. Действует кэш, естественно, временно — когда он кончится, производительность случайной записи опять упадёт. Однако плюс в том, что в Ceph-е этого, скорее всего, не произойдёт, так как скорость случайной записи ограничивается, собственно, самим Ceph-ом и распределяется по всем дискам кластера :).
# Однако, для обычных дисков без SSD-кэша отключение кэша тоже даёт выигрыш… есть гипотеза, что из-за того же тормоза с bluefs (проверю).
 
==== Данные тестов ====
Более свежие тесты бенчилкой ceph-gobench на том же самом стенде. Версия Ceph Mimic 13.2.2, Bluestore, журналы на SSD.
osd.14 | 302 | 229 | 135 | Hitachi Ultrastar A7K2000 | HUA722020ALA330
</tab>
 
==== Примечания ====
 
Toshiba MG07ACA14TE тоже замечены в подобном поведении, см. обсуждение в списке рассылки: https://www.spinics.net/lists/ceph-users/msg60753.html
== Почему вообще Bluestore такой медленный? ==
{{Note}} Третья редакция hatespeech’а.
Речь о Вкратце ситуация такова: После того, как хранилище Ceph переписали с упоротой архитектуры с хранением объектов в ФС XFS и дополнительным журналом, в которой, по идее, был дикий оверхед — быстрее (в смысле random write iops) оно практически не стало. Ведь вроде старались-старались'''Логичный ответ на вопрос «какого х#ра» такой: то ли XFS на самом деле написана очень хорошо, уходили от двойной записи и «журналирования журнала» в filestore…то ли Bluestore на самом деле написан очень плохо.''' Сразу скажу: оба ответа верны. :-)
Все мы держим в уме, что 1x 7200rpm HDD может выдать примерно 100—120 iops. Дальше нам говорят — ну, там типа журналирование. Ну ок, как мы рассуждаем — ну, типа, есть журнал, есть диск. Значит типа вроде как синхронно записало в журнал, потом асинхронно постепенно перенесло на диск. Значит, берём 100, умножаем на число дисков в кластере, делим на фактор репликации (3), делим на 1.5-2 (данные+журнал), мы же держим в уме, что наверняка там всё асинхронно и оптимизировано… Получаем, скажем, 100 * 9 дисков / 1.5-2 / 3 = 150—200 iops. Запускаем fio iodepth=128 на собранном кластере — ОЙ, 30 iops. Как так?
Сеть тоже не виновата — её я пробовал бенчить с помощью nbd (network block device). При прямом доступе диск выдаёт 50000 iops, при пробросе диска с одного сервера на другой через nbd — 8000 iops. То есть, добавленная latency сети — примерно 0.1ms. Это не много.
И даже Bluestore не совсем виноват. На NVMe Bluestore с некоторыми тюнами всё-таки осиливает завершить запись примерно за 0.3мс. И в то же время код самого Ceph сжирает ещё 0.4мс. Авторы сейчас пытаются пилить новую реализацию OSD на асинхронном фреймворке Seastar (Crimson OSD). Но проблема в том, что, скорее всего, это им поможет слабо. Проблема не в том, что многопоточный код плохо работает с вводом-выводом — проблема в том, что он сам по себе сильно жрёт CPU. Чтобы всё это работало быстрее, нужно упрощать логику.
По сути, нужно было бы добиться ситуации, в которой Ceph бы отъедал 0.1ms и Bluestore ещё 0.1ms. Сеть съест ещё 0.1ms и тогда на хорошей NVMe получится latency ~ 0.33ms, что в 1 поток соответствует 3000 операциям записи в секунду. До локальной SSD это всё равно не дотянуло бы, но, тем не менее, было бы уже очень-очень неплохо. Тогда, скажем, можно будет бороться за CPU: поставив самолётные CPU по 20000$ каждый, настроив ядро и снизив время Ceph+Bluestore ещё в 2 раза, вы получите уже 0.23ms = ~4350 iops. А допилив поддержку Infiniband, может, получите и все 6000 iops. Пока же код не оптимизирован… всё это — мёртвому припарки.
 
Авторы сейчас пытаются пилить новую реализацию OSD на асинхронном фреймворке Seastar (Crimson OSD), так что у нас есть теоретические шансы увидеть Ceph, который будет в несколько раз быстрее. Хотя, конечно, там вопрос далеко не только в многопоточности и блокировках — по идее, много съедает именно программная логика. Но так как её они фактически тоже частично переписывают с нуля — она тоже может улучшиться.
== DPDK и SPDK ==
** Code is there, так что, вероятно, всё это можно исправить, если подебажить подольше
** Есть сообщения, что SPDK всё-таки работает из коробки, просто не даёт никакого выигрыша производительности. Но мне пока завести его не удалось
* Однако, похоже, в силу неоптимальной реализации самого сетевого кода Ceph ни от DPDK, ни от RDMA ожидать ускорения не приходится — потому приходится. Задержка Ceph в 10-100 раз выше сетевой задержки, так что один , уменьшая сетевую задержку, добиться практически нечего. Один чувак недавно даже проводил эксперимент — отрезал код AsyncMessenger-а от всего остального цефа и попробовал побенчить пробовал бенчить его отдельно: https://www.spinics.net/lists/ceph-devel/msg43555.html - html — и получил всего лишь ~80000 iops.
* В перспективе SPDK будет на хрен не нужен, так как в ядро приняли штуку под названием io_uring: https://lore.kernel.org/linux-block/20190116175003.17880-1-axboe@kernel.dk/ - с ней обычный код прокачивает через Optane-ы практически столько же iops, сколько и SPDK, при заметно меньшем объёме геморроя на поддержку работы с SPDK/DPDK
== Краткий экскурс в устройство SSD и флеш-памяти ==
Особенность NAND флеш-памяти (NAND/NOR) заключается в том, что пишется она мелкими блоками (обычно 512 байт), а стирается большими . Актуальное соотношение для Micron 3D NAND — страница (2-4 мегабайтаpage) 16 КБ, блок стирания (block) — и при этом 16 или 24 МБ (1024 или 1536 страниц, MLC/TLC соответственно). Случайное чтение страницы быстрое. Запись тоже, но писать можно только в предварительно стёртую область. Чтение блока при этом быстрое, запись тоже быстрая; область — а стирание же медленное, да ещё и число стираний каждого erase unit-а блока ограничено — после нескольких тысяч (типичное значение для 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.
 
Кстати, из размера страницы 16 КБ следует, что когда вы используете десктопную SSD под мелкую транзакционную перезапись, вы ещё и сильно снижаете срок её жизни, так как при перезаписи по 4 КБ с sync-ами write amplification составляет не менее 16 КБ / 4 КБ = 4. ''Примечание: в современных SSD распространена такая вещь, как SLC Cache — использование части той же самой флеш-памяти в SLC-режиме для первых X гигабайт записи. При SLC-записи размер той же страницы, вероятно, уменьшается в 3 раза, так как вместо 3 бит в каждой ячейке хранится только 1. С другой стороны, это всё равно та же страница, которая номинально вмещает 16 КБ, так что как тут считать WA, не совсем ясно.''
Дополнение: когда я попытался кого-то в списке рассылки полечить на тему, что «все SSD делают fsync», мне в ответ кинули статью: https://www.usenix.org/system/files/conference/fast13/fast13-final80.pdf. В общем, суть статьи в том, что в 2013 году нормой было то, что SSD вообще не сбрасывали метаданные на диск при fsync, и при отключении питания это приводило к разным весёлым вещам вплоть до (!!!) полного отказа SSD.
=== Бонус: USB-флешки ===
А почему тогда USB-флешки такие медленные? Случайная запись на флешку 512-байтными (или 4 Кб) блоками обычно идёт со скоростью 2-3 iops. А флеш-память там ровно примерно та же, что в SSD — ну, может, более дешёвые вариациии мелкие чипы с меньшими размерами страницы и блока (часто 4 КБ страница и 4 МБ блок), но разница принцип тот же и разница в скорости не на порядки. Ответ кроется в том, что на флешках тоже есть FTL (и даже Wear Leveling), но по сравнению с SSD-шным он маленький и тупой. У него слабый процессор и мало памяти. Из-за малого объёма RAM контроллеру флешки, в отличие от контроллера SSD, негде хранить полную таблицу сопоставления виртуальных и реальных секторов — поэтому отображаются не сектора, а крупные блоки где-то по мегабайту или больше, а и при записи есть лимит на количество «открытых» блоков. Как это происходит:
* Допустим, вы пишете в сектор X.
Пример самолётного сетапа от Micron с процами по полляма (2x Xeon Platinum 8168), 2x100-гбит сетью (точнее 2x2x100, так как 2 карты по 2 порта) и 10x топовыми NVMe (с конденсаторами, ага) в каждом узле, 4 узла, репликация 2x: https://www.micron.com/resource-details/30c00464-e089-479c-8469-5ecb02cfe06f
Всего 350000 367011 iops на запись в пике на весь кластер, при 100 % загрузке CPU. Казалось бы, довольно много, но если поделить 350000367000/40 osd — получится 8750 9175 иопс на 1 osd. С учётом репликации на диски нагрузка двойная, выходит, 17500 18350 иопс. Ок, журналы тоже удваивают нагрузку, итого — 35000 36700 iops на запись смог выжать ceph из одной NVMe… которая сама по спеке может 260000 иопс в одиночку. Вот такой вот overhead.
Данных по задержкам в 1 поток нет (а было бы интересно узнать).
UPDПримечание: Поправка: <s>в чём микрон неправ — они не использовали SPDK и DPDK. Есть большая вероятностьPDF-ка по ссылке обновлена, новый результат с теми же тюнами, что в их случае выигрыш мог быть в несколько разниже, составил 479882 iops на запись и 2277453 iops на чтение.</s> НетСтарая [[:Media:Micron_9200_ceph_3.0_reference_architecture.pdf|тут]]. Что и подтверждает, это бессмысленночто разница между Micron 9200 и 9300 для Ceph незаметна.
=== Апдейт ===
* cephx у них уже был отключён. В этот раз зачем-то добавили и отключение подписей — видимо, читали мою статью. Но это нафиг не надо, при отключенном cephx подписи можно уже не отключать.
* debug objecter = 0/0 и вообще отключенные дебаги у них тоже уже были
* с prefer_deferred_size и min_alloc_size они, видимо, не игрались (а зря)
* обновлённые диски не играют никакой роли гарантированно. 260000 или 310000 iops — для цефа никакой разницы нет.
 
=== Бонус: висян (vSAN) ===
 
[https://media-www.micron.com/-/media/client/global/documents/products/other-documents/micron_vsan_6,-d-,7_on_x86_smc_reference_architecture.pdf Micron Accelerated All-Flash SATA vSAN 6.7 Solution]
 
Конфигурация серверов:
 
* 384 GB RAM 2667 MHz
* 2X Micron 5100 MAX 960 GB (randread: 93k iops, randwrite: 74k iops)
* 8X Micron 5200 ECO 3.84TB (randread: 95k iops, randwrite: 17k iops)
* 2x Xeon Gold 6142 (16c 2.6GHz)
* Mellanox ConnectX-4 Lx
* Connected to 2x Mellanox SN2410 25GbE switches
 
«Соответствует конфигурации VMWare AF-6, по заявлениям дающей от 50K iops чтения на каждый сервер»
 
* 2 реплики (аналог size=2 в цефе)
* 4 сервера
* 4 ВМ на каждом сервере
* 8 диска на каждую ВМ
* 4 потока на каждый диск
Суммарный параллелизм ввода/вывода: 512
 
100%/70%/50%/30%/0% write
* «Baseline» (данные умещаются в кэш): 121k/178k/249k/314k/486k iops
* «Capacity» (не умещаются): 51k/66k/90k/134k/363k
* Задержка равна 1000*512/IOPS миллисекунд во всех тестах (1000мс * параллелизм / iops)
* '''Нет тестов задержки с низким параллелизмом'''
* '''Нет тестов линейного чтения/записи'''
 
Заключение:
* ~3800 iops на запись в пересчёте на каждый диск данных
* ~1600 iops на запись в пересчёте на диск, если данные не влезают в кэш
* ~15000 iops на чтение в пересчёте на каждый диск данных
* ~11400 iops на чтение в пересчёте на диск, если данные не влезают в кэш
* Итого: при параллельной нагрузке в данном тесте vSAN смотрится хуже, чем Ceph
* С другой стороны, vSAN гиперконвергентный, а Ceph, в идеале, нет — или тормозит сильнее, чем мог бы
== Модели ==
* Micron серий 5100/5200, 9300. Возможно также 5300, 7300
* HGST SN260
* Intel P4500
* Использовать только SSD с конденсаторами. NVMe это тоже касается. Подсказка: 99 % desktop SSD и NVMe конденсаторов не имеют.
* …и надо отключать этим SSD кэш (hdparm -W 0), если они SATA!
* В случае HDD — полезны HDD со встроенным SSD-кэшем. Например, почти все большие Seagate EXOS таковы, хоть на них это часто и не заявлено.* …и им тоже бывает полезно отключить кэш (hdparm -W 0). Только проверьте, что это улучшает iops-ы, а не ухудшает.* SMR HDD не использовать под Ceph никогда.* Отключить powersave: governor cpupower frequency-set -g performance, cpupower idle-set -D 0
* Отключить электронные подписи: <br /><tt>cephx_require_signatures = false<br />cephx_cluster_require_signatures = false<br />cephx_sign_messages = false</tt><br />(и монтировать rbd map / cephfs ядерным драйвером с опциями <tt>-o nocephx_require_signatures,nocephx_sign_messages</tt>)
* Для хороших SSD или NVMe: min_alloc_size=16384 (так и было по умолчанию, в последних версиях поменяли на 4096 и я рекомендовал 4096, prefer_deferred_size_ssd=0 (ДО создания OSDа похоже, что зря)
* Актуально для версий до Nautilus включительно — <tt>[global] debug objecter = 0/0</tt> (там большой тормоз на клиентской стороне)
* В QEMU юзать virtio* Если нужны только random write у вас All-flash кластер и вам критичны либо iops, то в userspace драйвере -ы случайной ''синхронной'' записи (напримерfsync/O_SYNC, QEMUнапример в случае СУБД) — , либо суммарные iops-ы ''параллельной'' случайной записи, то нужно отключить rbd cache(в qemu опция cache=none). Если не критичны или у вас HDD, лучше поставить cache=writeback.* Чтобы мог работать cache=unsafe, поставить <tt>[global] rbd cache writethrough until flush = false</tt>* <s>Для HDD-only или Bad-SSD-Only и версий до Nautilus включительно — снять ручник https://github.com/ceph/ceph/pull/26909</s> - уже влит* Внутри ВМ: <tt>mount -o lazytime</tt>
== Примечание ==
Написанное в статье актуально для версий Ceph, доступных на момент последней правки (см. «История» вверху страницы). Конкретно — для 12 -15 luminous-octopus. Различия между версиями минимальны, 13 mimic, да и 14 nautilus тоже — всё пока что актуально. Если вдруг в будущем что-то пофиксят и всё вдруг станет чудесно быстрым — сам побегу обновляться первым и поправлю статью :).
== См. также ==
* https://www.ixsystems.com/community/resources/list-of-known-smr-drives.141/ - список SMR дисков (вероятно, не полный)
* http://vasilisc.com/bluestore-ceph-2017 - кое-что про bluestore, местами не совсем верно, но тем не менее
* https://amarao-san.livejournal.com/3437997.html - «IOPS не существует» — сказ о latency
*: ''Прим.вред — iops существуют, но с обязательным указанием режима тестирования и параллелизма''
* https://yourcmc.ru/afr-calc/ - мой калькулятор вероятности потери данных в кластере Ceph в зависимости от размера кластера и схемы отказоустойчивости
 
== Советы лучших собаководов ==
 
Офлайн балансер:
 
<pre>ceph osd getmap -o om; osdmaptool om --upmap upmap.sh --upmap-deviation 0; bash upmap.sh; rm -f upmap.sh om</pre>
[[Category:Ceph]]