Изменения

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

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

2669 байтов добавлено, 16:08, 15 июля 2019
Нет описания правки
== Почему вообще Bluestore такой медленный? ==
{{Note}} По итогам дополнительных изысканий хейтспич несколько подправленТретья редакция hatespeech’а.
Речь о random write iops. Ведь вроде старались-старались, уходили от двойной записи и «журналирования журнала» в filestore…
Все мы держим в уме, что 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. Как так?
Окей, дальше нам говорят — эээ, неОтчаиваемся и по советам знатоков прикручиваем туда SSD под wal+db. 120 random iops с 1 HDD — это без syncИ думаем: ну, случайная запись с sync — примерно 50-60 iops. Окей, говорим мы, но во-первых теперь у нас же глубина очереди 128быстрая SSD с конденсаторами под журналом, значит, параллелизмлатенси записи 50 микросекунд, значит, операции должны пролезать между sync-ами и должно быть быстрее — а во-вторыхмного иопсов — ну, 50*в устоявшемся режиме хотя бы 300 (9* 100 /13).5/3 — это всё равно 100Тестируем. Ну хоть 100 В 1 поток получаем ну… 60 иопс. Во много — где-то должно у нас быть на запись? А у нас 30200. Опять плохо.
Дальше мы отчаиваемся и по советам знатоков прикручиваем туда SSD под wal+db. И думаем: нуСмысл в том, теперь-то что собственной реализации журнала у нас запись идёт на SSDблюстора нет, SSD хорошаяесть очередь отложенной записи, с конденсаторамиживущая прямо в RocksDB. Теперь суммарно у нас должно быть не меньше 300 иопс (N * скорость шпинделя / фактор репликации)RocksDB — это LSM keyvalue база, да и в 1 поток должно быть столько же. Тестируемпо сути база-журнал. В 1 поток получаем ну… 60 иопспринципе, это достаточно разумно, так как всё равно нужно журналировать изменения метаданных, которые там держит блюстор. Во много — гдеКогда очередь отложенной записи засунута туда же, изменение можно коммитить одной транзакцией (соответственно, одним fsync-то 200. Опять медленноом).
Вариант решения № 1: у наших HDD обнаруживается media cacheИ в этой схеме есть одно большое отличие от filestore — оно заключается в том, мы его включаемчто в filestore журнал работал как буфер для временного повышения нагрузки на запись. Пока в журнале было место, получаем нормальную производительность случайная запись была очень быстрой, а журналы обычно делали размеров в несколько гигабайт. В bluestore же «очередь отложенной записи» очень маленькая и успокаиваемся сбрасывается через каждые 64 запроса. То есть, bluestore не пишет быстрее, чем в среднем может медленное устройство (хотя осадочек-то осталсяHDD). Вариант № 2: медиакэша у наших дисков нет и мы продолжаем ломать голову «почему ж так медленно-то».
Так вотПлюс к этому на практике (при просмотре strace) оказывается, что fsync-ов на каждую операцию записи делается не 1, а 2. Журнала у блюстора собственного нетВторой fsync — это лишняя транзакция записи в журнал BlueFS, вместо него сводящаяся к обновлению размера лог-файла RocksDB. Это как бы keyvalue база, но она же LSMнафиг не нужно, она же так и работает — типа до лимита пишет как в память+журнал, потом когда упирается опциях RocksDB в лимит — делает compaction цефе по уровням. По сути как бы БДумолчанию стоит wal_recovery_mode=kTolerateCorruptedTailRecords и recycle_log_number=4, но это так, потому что без этого у них из-журналза другого бага корраптятся данные при падении OSD. Вот Что на самом деле исправляется легко, я им даже отправил фикс — https://tracker.ceph.com/issues/38559 https://github.com/ceph/ceph/pull/26909 - и они её даже вроде как журнал и юзаютобещают его влить. В той же RocksDB метаданныеС фиксом на HDD ускорение случайной записи при глубине очереди 1 — двукратное (с 33 % до 66 % возможностей самого HDD, и их дохрена, ибо виртуальные клоны и всякое такоеобычно как раз с 33 до 66 иопс). Плюс чексуммы. Плюс два варианта записи — прямой и отложенныйПри глубине очереди 128 — почти нулевое.
Теоретически в этом ничего плохого нет. НаоборотОК, хорошо то, что ладно. В конце концов мы решаем — гулять так гулять и метаданные, и данные записываются собираем кластер на серверных SSD (или вообще NVMe). Думаем — ну теперь-то?!… Бенчим в 1 транзакциейпоток.300 иопс. Охреневаем окончательно и идём гуглить эту статью :)
Однако Здесь смысл в том, что в голове у всех сидит мысль «а, ну да, оно медленное, потому что слишком много пишет на практике (при просмотре straceдиск — диск же относительно медленный, а софт быстрый». А вот хрен. :) оказывается, что Ceph довольно сложно разогнать до latency < 1 ms, и виной тому не диски, а сам Ceph. То есть да, Ceph при записи 4к-мелкими блоками OSD демонстрируют фактор порождает WA (Write Amplification от ) 3 до 5 плюс делают огромное количество commit-ов. Запись делается двумя системными вызовами — pwritev и io_submit. Commit — тоже двумя5 на каждой OSD — это легко посчитать через тот же strace. Но на хороших SSD это практически не занимает времени, sync_file_range и fdatasyncодна операция 4кб записи занимает условно 20 микросекунд. Проблема именно в С++ коде Ceph.
НапримерПричём даже не до конца понятно, по итогам простого теста с SSD-настройками получаетсячто конкретно там тормозит — такое ощущение, что эта тварь на 6193 запроса всё целиком. Выявить какие-то «горячие точки» при профилировании трудно, просто при записи делает 18585 записей (выполняется много всякой C++ной мелочи, которая суммарно записывая 21674 4к-блокаотъедает достаточно много времени. Одно горячее место — вычисление цифровых подписей пакетов (включено по умолчанию, можно отключить) и 24776 коммитов , другое — сериализация/десериализация (большекод обрабатывает каждое поле пакета, чем запросов записичуть ли не каждый байт, отдельным вызовом функции)! Итого Write Amplification = 3.5Дальше идут уже malloc-и, которых тоже происходят тонны. Причём всё это происходит в несколько потоков. На это ещё навёрнута какая-то странная смесь буферизованного и прямого I/O.
Тот же тест RocksDB не виновата — её я пробовал бенчить быстрая, ~8000 транзакций в секунду на HDD: на 1183 операции 3020 запросов записи суммарным объёмом 4926 * 4 кб NVMe в 1 поток она даёт и 3664 sync-адаже в 256 потоков масштабируется до ~120000 tps. Итого WA = 4.16 (4926/1183), а syncНа той же NVMe Ceph OSD даёт только 10-ов опять больше, чем запросов записи20 тысяч iops даже во много потоков.
Причины найдено две:Сеть тоже не виновата — её я пробовал бенчить с помощью nbd (network block device). При прямом доступе диск выдаёт 50000 iops, при пробросе диска с одного сервера на другой через nbd — 8000 iops. То есть, добавленная latency сети — примерно 0.1ms. Это не много.* И даже Bluestore не совсем виноват. На HDD — блюстор NVMe Bluestore с некоторыми тюнами всё время «едет на ручнике» из-таки осиливает завершить запись примерно за совершенно идиотской проблемы, которую я не далее чем вчера зарепортил сюда https://tracker0.ceph3мс.com/issues/38559 - при каждой записи И в журнал RocksDB происходит дополнительная «ненужная» транзакция записи то же время код самого Ceph сжирает ещё 0.4мс. Авторы сейчас пытаются пилить новую реализацию OSD на асинхронном фреймворке Seastar (Crimson OSD). Но проблема в журнал BlueFSтом, сводящаяся к обновлению размера лог-файла RocksDB. Теоретически это не нужночто, так как RocksDB настроена с wal_recovery_mode=kTolerateCorruptedTailRecords и recycle_log_number=4скорее всего, это им поможет слабо. Но практически — Проблема не в коде багтом, из-за которого журнал при этом не syncчто многопоточный код плохо работает с вводом-ается. На HDD ускорение случайной записи при глубине очереди 1 — двукратное. При глубине очереди 128 — почти нулевое.* На SSD — блюстор жёстко упирается выводом — проблема в том, что он сам по себе сильно жрёт CPU и блокировки. Чтобы всё это работало быстрее, нужно упрощать логику.
== DPDK и SPDK ==

Навигация