CassandraDB – она же просто Кассандра – хорошо зарекомендовала себя в нише высокопроизводительных NoSQL баз данных. Но вот её активно стала вытеснять ещё более быстрая, надежная и легко масштабируемая ScyllaDB - этакая Кассандра++. Как тут удержаться и не проверить, так ли прекрасна эта зверушка, как про неё говорят её создатели? Тем более вендоры других популярных баз данных того и гляди закроют поддержку для российских пользователей. Нужно иметь под рукой пару-тройку запасных вариантов. Сегодня мы рассмотрим, как одноглазый монстрик приживается в диких условиях кровавого энтерпрайза, и насколько целесообразно его использовать.
Об этом расскажет Илья Орлов, техлид компании STM Labs. Вместе с командой он разрабатывает высоконагруженные решения для всевозможных задач: бизнес-порталов с использованием собственной платформы, мониторинга фискальных данных и прочее. Они любят экспериментировать с разными БД, поэтому статья будет об использовании ScyllaDB на промышленных мощностях.
Зачем нужна другая СУБД?
Представим крупную трек&трейс систему, отслеживающую судьбу каждой единицы товара от момента регистрации до продажи конечному пользователю. В качестве оперативного хранилища была выбрана MongoDB. Объём информации в ней рос неумолимо и стремительно, потому что нельзя было просто так взять и удалить товар из системы, даже если он завершил свой жизненный цикл.
Почему? Да по той же причине, по которой не выкидывается гора ненужных бумажек. Стоит что-то выбросить, как мы тут же с болью осознаём, что там же, к примеру, был гарантийный талон от внезапно сломавшейся посудомойки. Это всё данные, вероятность обращения к которым близка, но не равна нулю. Удалять их нельзя, но и загромождать ими оперативные хранилища — непозволительная роскошь.
Такие данные можно отправлять в архив.
Требования к архиву существенно мягче, чем к основному хранилищу. Читают оттуда, как правило, редко. Скорость записи должна быть сопоставима со скоростью перехода товаров в конечное состояние, то есть 3-4 мегабайта в секунду вполне достаточно. Главное, чтобы данные хранились максимально компактно.
Это и стало хорошим поводом для Ильи и его команды опробовать альтернативную СУБД, чтобы, как гласит народная мудрость, не класть все яйца в одну Mongo. Рассмотрев несколько подходящих СУБД, они наткнулись на ScyllaDB.
Почему ScyllaDB?
Заявленная производительность ScyllaDB (или просто Сциллы) — 12 500 запросов в секунду на физическое ядро. Учитывая, что один запрос предполагает payload в 1 килобайт, на 32-ядерном сервере система получит RPS 400 000, что равно примерно 400 мегабайт в секунду. Понятно, что это как с заявленным расходом бензина у автомобиля в автосалоне. Но у команды, привыкшей к RPS в 40 000, такие цифры вызывали, если не уважение, то профессиональный интерес. Тем более было разумное обоснование такой производительности — реализация на С++.
И хотя на плюсах можно реализовать так, что получится усердный бобер, команда была настроена оптимистично, так как о Сцилле было множество восторженных отзывов (на официальном сайте), причём от известных, в том числе отечественных компаний. В одном из таких отзывов рассказывалось о возможности деплоя Сциллы на HDD-дисках с RPS записи 240 000, а не SDD, как указано в официальной рекомендации. Такой эконом-вариант.
Кроме того, интерфейс ScyllaDB заявлялся как аналогичный интерфейсу старой доброй Кассандры, с которой у команды был существенный опыт работы. При этом, перфоманс тесты, по отзывам, показывали, что у Сциллы скорость записи вдвое выше, чем у Кассандры. К тому же, официальной документации по Сцилле в открытом доступе море. А если чего нет по Сцилле, наверняка есть по родственной ей Кассандре.
И, наконец, у этого монстрика есть открытое сообщество и поддержка в Slack.
Богатый внутренний мир ScyllaDB
ScyllaDB — это колоночная СУБД с собственным алгоритмом утилизации памяти и CPU, на который, как оказалось, повлиять извне особо нельзя, в отличие от Кассандры. Дело в том, что Сцилла рассматривает весь кластер подключённых серверов, как общую совокупность доступных процессорных ядер и распределяет данные именно между ядрами. То есть одно ядро — один шард.
Это позволяет для каждого сервера обеспечить нагрузку, сопоставимую с его мощностью. Конечно, ни о каком ручном перераспределении потоков между задачами речь не идёт. Сцилла, как коробка-автомат, всё знает за вас.
Инфраструктура
Определившись с СУБД, Илья с командой стали готовить инфраструктуру. Развернули кейспейс — логическое объединение данных — в кластере из пяти 32-ядерных серверов, каждый из которых имеет оперативную память в 312 гигабайт. Затем установили фактор репликации 3 и решили начать с эконом-варианта: выбрали HDD диски, а не SSD. Ведь, если что, в любой момент можно переехать на SSD, думали они. Сцилла же легко позволяет добавлять новые мощности на горячую...
Схема данных
Схема данных, которую разработчики планировали архивировать, идеально ложилась на концепцию key-key-value, обозначенную в официальной документации Сциллы в качестве образцовой. Иными словами, словарь словарей. Выглядела эта схема следующий образом:
Первичным ключом записи и по совместительству ключом партиции стал product_id — уникальный идентификатор продукта. По этому ключу располагался набор атрибутов, описывающих состояние продукта на момент его выхода из оборота. Получалась такая таблица – products.
На неключевые поля exec_date — типа дата, owner — типа строка, сразу повесили индексы. Мало ли, вдруг потом по ним придётся поиск выполнять. Лучше уж сразу проиндексировать, чем потом по миллиардам записей с нуля индексы строить.
Алгоритм архивации
Команда решила архивировать в три этапа:
Копирование из основного хранилища в архив;
Валидация, проверка того, что ранее продукты были скопированы;
Удаление из основного хранилища.
Операция удаления сильно тормозила основное хранилище, поэтому выполнять её можно было только в периоды наименьшей нагрузки на систему. Валидацию разработчики добавили, руководствуясь правилом «Доверяй, но проверяй», и ведь, как в воду глядели, пригодился этот этап.
Проблемы
Прежде чем выкатывать решение в прод, разработчики провели множество тестов. В частности, нагрузочное тестирование с использованием стандартной кассандровской утилиты — cassandra-stress-test.
Оно показало, что данные в Сциллу лучше отправлять пачками. Отправили запись размером 10 килобайт и получили производительность 5 000 запросов в секунду, то есть примерно 45 мегабайт в секунду. Это не 400 и даже не 240 мегабайт, но всё равно более чем достаточно для выкатки в прод.
Если бы архивация на production-сервере проходила с такой же скоростью, как в cassandra-stress-test, то получалось бы 400 миллионов записей в сутки. На деле же скорость одного только копирования составила 138 миллионов. А с учётом последующих этапов получалось вообще 20 миллионов записей в сутки. Это меньше скорости перехода товаров в конечное состояние, их выхода из оборота. Разработчики думали, что скорость получится увеличить, отказавшись от этапа валидации, когда система стабилизируется. Но не тут-то было: когда размер архива перевалил за терабайт, всё пошло… совсем не туда:
→ Более 50% операций записи стали завершаться по таймауту.
Во-первых, более 50% операций записи в Сциллу стали завершаться по таймауту. Сцилла не успевала ни записать, ни переварить отправленные в неё данные. Из-за этого скорость копирования деградировала более чем в 5 раз: со 138 до 26 миллионов записей в сутки.
→ Падала скорость копирования, валидации (чтения) и архивации в целом (до 3 млн. записей в сутки).
Во-вторых, скорость архивации в целом снизилась даже не до 3 мегабайт в секунду, а ещё больше из-за сильного замедления этапа валидации.
→ Автокомпактификация занимала до 100% CPU и оказалась неуправляемой.
В-третьих, Сцилла, как и многие другие NoSQL СУБД, реализует компактификацию данных. И компактификация эта занимала до 100% ресурсов Сциллы. Разработчики думали вмешаться и ограничить количество потоков под эту операцию, но сделать это оказалось нельзя. Пока чудовище не переварит всё, что съело, пусть весь мир подождёт.
→ Индексирование перестало работать.
В-четвёртых, в логе Сциллы стали появляться многочисленные сообщения об ошибке сохранения партиции со слишком большим количеством записей.
Речь шла о так называемых materialized view, на основе которых Сцилла строит индексы. Иными словами, если значение индексируемого поля совпадает у слишком большого количества записей, такой индекс строить нельзя.
Решения
Первым шагом на пути к решению проблемы должен был стать переезд на SSD диски. Но когда разработчики провели архивацию на SSD на тестовых серверах, к их великому разочарованию, число таймаутов практически не уменьшилось, да и особого прироста в скорости копирования не получилось. Более того сам процесс переезда на SSD принёс множество сюрпризов, борьба с которыми вполне заслуживает отдельного доклада. Например, у Сциллы есть конфигурационный параметр auto_bootstrap, от которого во многом зависит, будет ли добавляемая в кластер машина с пустой базой подтягивать данные с других машин кластера (auto_bootstrap = True) или сама станет источником данных (auto_bootstrap = False), что приведёт к затиранию информации на всём кластере. Документация гласила, что по умолчанию, auto_bootstrap = True, но… не уточняла, с какой версии…
Следующим шагом разработчики попробовали отключить автокомпактификацию, но оно помогло лишь отчасти. Число таймаутов чуть сократилось, но сама компактификация стала занимать несколько дней. Это очень напоминало дилемму с отключением автовакуума в PostgreSQL. В итоге пришлось обратно включать автокомпактификацию.
Почему нельзя было просто увеличить время до таймаута? Дело в том, что завершение операции копирования по таймауту вовсе не означало, что отправленные в Сциллу записи не сохранились. Наоборот, как показал весьма пригодившийся этап валидации, большая часть данных успевала записаться. Валидация позволила даже в условиях многочисленных таймаутов продолжать перемещать данные в архив, не увеличивая время операции до таймаута.
Что касается индексов… От них пришлось отказаться. В описываемом эксперименте, по счастью, они действительно были балластом. Но потенциальным пользователям Сциллы стоит иметь в виду, что этот существенный недостаток так и не был исправлен на данный момент.
Итак, проблема медленной архивации никуда не делась. После многочисленных профилирований и брейнштормов разработчики пришли к выводу, что Сцилла просто не тянет установленную ими компрессию данных. Поэтому они поменяли алгоритм сжатия с перестраховочного ZSTD на приемлемый — LZ4.
Тут-то и случился прогресс. Число таймаутов сократилось до нуля, возросла скорость копирования (до 200 миллионов записей в сутки) и компактификации. Более того, Сцилла даже позволяла проводить компактификацию параллельно с копированием. Решение проблемы с таймаутами позволило отказаться от этапа валидации, нагружавшего многочисленными запросами на чтение не приспособленную для этого Сциллу.
Новый алгоритм архивации стал значительно проще.
В итоге после применения вышеуказанных действий удалось добиться скорости архивации – 300 миллионов записей в сутки, то есть примерно 34 мегабайта в секунду, что в разы превышало требуемые значения.
Резюме
Во-первых, Сцилла подходит для хранения только таких данных, которые убираются в формат словарей. Ни больше, ни меньше. И стоит забыть про индексы.
Во-вторых, есть смысл начать с максимальной компрессии и менять алгоритм сжатия, когда начнутся таймауты. Это позволит, по крайней мере, на начальном этапе экономить место. По счастью, Сцилла позволяет поменять алгоритм сжатия легко и безболезненно.
В-третьих, компактификация в Сцилле практически неуправляемая. Можно выбрать стратегию, самая оптимальная — инкрементная — доступна только в платной версии. Для большинства же задач вполне пойдёт дефолтная STCS. Но она особой погоды не делает. Стоит сказать только что, автокомпатификацию лучше не отключать и настраивать Сциллу так, чтобы она одновременно и кушала, и переваривала.
В-четвёртых, завершение операции по таймауту вовсе не означает, что операция не выполнилась. Поэтому валидация, особенно на начальном этапе, будет не лишней. Это позволит предотвратить многократное копирование одних и тех же записей.
И, наконец, в-пятых, не верьте документации на слово и обязательно проверяйте любое действие на тестовых серверах. Особенно, если это действие связано с изменением инфраструктуры. Даже простое добавление сервера в кластер может привести к потере всех данных.
Таким образом, Илья не стал рекламировать и рекомендовать ScyllaDB, но подчеркнул, что наличие таких решений, особенно опенсорсных, очень важно. Это развивает конкуренцию и ПО. Можно и нужно исследовать новые СУБД и делиться опытом. Илья считает, что такое исследование должно быть предусмотрено в бюджете любого программного продукта. Ведь это же хорошо, когда есть альтернатива.
Комментарии (4)
ivankudryavtsev
06.06.2023 09:46+1Писали бы
Kafka > {Mongo/C* (OLTP), ClickHouse | HDFS (archive)}
И было бы вам счастье. Ну и TTL на коллекции в OLTP базе. И да, вот так новость C* - это просто KVS, который притворяется полноценной БД.
QtRoS
06.06.2023 09:46ScyllaDB — это колоночная СУБД
Стоит уточнить, что это wide-column, а не columnar БД в чистом виде.
Вопрос по резюме: получается, для Кассандры не характерны никакие из этих проблем?
ivankudryavtsev
Типичная C*, все как и ожидалось - шаг влево, шаг вправо, выстрел в ногу... Где-то мне знатоки заливали, что вот ничего такого не бывает))
Вот оно - бывает)