Discord перешел от MongoDB к Cassandra, затем к ScyllaDB — почему?

Discord перешел от MongoDB к Cassandra, затем к ScyllaDB — почему?

27 апреля 2023 г.

Привет, как дела?

Итак, на днях я наткнулся на блог Discord под названием КАК DISCORD ХРАНИТ ТРИЛЛИОНЫ СООБЩЕНИЙ. Название вызывает у нас интерес и дает ощущение удивления тем, что в мире они достигают того и этого с масштабируемостью.

Итак, я подытожу для вас приведенный выше пост в блоге, потому что мне пришлось прочитать его несколько раз, чтобы понять все.

Приступим.

Прежде всего, что такое MongoDB, Cassandra и ScyllaDB? В чем между ними разница?

Объяснение MongoDB, Cassandra и ScyllaDB

  1. MongoDB: это система управления базами данных NoSQL, основанная на документах. В MongoDB создаются документы, подобные JSON, и, поскольку он относится к семейству NoSQL, он не совместим с ACID. В MongoDB есть модели Master-Slave, а модель данных здесь неструктурирована, что обеспечивает поддержку вариантов использования, в которых требуется модель Rich Data.

2. Cassandra: она также принадлежит к семейству NoSQL, а ее модель данных структурирована и основана на столбцах, поэтому она подпадает под базу данных NoSQL типа хранилища с широкими столбцами. Cassandra обеспечивает высокую доступность за счет наличия нескольких главных узлов в кластере и, таким образом, поддерживает варианты использования, когда требуются запросы к базе данных на основе первичного ключа и когда система интенсивно записывает данные.

3. ScyllaDB: это также база данных NoSQL с широкими столбцами на базе хранилища, как и Cassandra, а также API-совместимость с Amazon DynamoDB и Cassandra. Основное различие между ScyllaDB и Cassandra заключается в том, что она написана на C++, а Cassandra написана на JAVA, и вместо того, чтобы полагаться на кеш страниц, она хранит кеш строк, что делает ее более оптимизированной и быстрой, чем Cassandra.

Хорошо, давайте совершим путешествие во времени; пойдем со мной

Текущее время — май 2015 г.

В этом месяце запущен Discord, и все хранится в одном наборе реплик MongoDB.

Текущее время — ноябрь 2015 г.

Бум, Discord теперь хранит 100 миллионов сообщений в БД, но знаете что, данные и индекс больше не помещаются в ОЗУ, а задержка становится непредсказуемой.

Что теперь? Discord решил перейти на новую БД, и им нужна БД, отвечающая хотя бы этим требованиям:

  1. Линейная масштабируемость
  2. Автоматический переход на другой ресурс
  3. Низкие эксплуатационные расходы
  4. Предсказуемая производительность
  5. Открытый код
  6. Не магазин BLOB-объектов.

Потому что теперь компания знает некоторые общие шаблоны, такие как:

  1. Соотношение операций чтения/записи на платформе составляет 50/50.

2. В целом у них есть 3 типа групп — Voice Heavy, Private Groups и Public Groups, и все они имеют разное поведение для дискового кеша.

3. В Discord есть некоторые функции, такие как закрепленное сообщение, полнотекстовый поиск, упоминания за последние 30 дней и т. д.

И они дорабатываются и идут с Кассандрой, которая подходит по вышеуказанным пунктам.

Теперь возникает ситуация, как они должны моделировать данные.

В MongoDB они индексировали сообщения, используя channel_id и created_at.

Но в Cassandra они идут с составным первичным ключом ((channel_id, Bucket), message_id). Почему?

  1. Cassandra — это своего рода хранилище KKV, где первая буква K – это ключ раздела, а вторая – ключ кластеризации.

2. Channel_id был достаточным для ключа раздела; тогда почему они выбрали ведро? А при чем тут ведро? См. пункт 6.

3. Но created_at недостаточно для кластеризации, потому что в канале два сообщения могут иметь одно и то же значение created_at.

4. Поскольку они создавали message_id, который представляет собой SnowFlake, этот 64-битный идентификатор имеет состав временной метки. Узнайте больше о Snowflake здесь https://blog.twitter.com/2010/announcing-snowflake. 5. Таким образом, message_id был самодостаточен для кластеризации.

6. Теперь идет Ведро. Итак, после того, как команда начала импортировать сообщения в Cassandra, они получили некоторые ошибки из-за размера раздела более 100 МБ.

7. Теперь, чтобы сделать разделы меньше 100 МБ, им потребовались некоторые изменения в ключе раздела, чтобы размер раздела был меньше 100 МБ. Итак, изучив шаблоны, команда решила, что если они будут хранить сообщения за 10 дней, размер раздела будет меньше 100 МБ. Именно по этой причине ключ раздела имеет вид (channel_id, Bucket).

Пришло время запустить Cassandra

Они запустили Cassandra, но сделали двойное чтение/запись как для MongoDB, так и для Cassandra, чтобы проверить, как Cassandra ведет себя с производственными данными.

Но команда допустила некоторые ошибки, и причина этого была -

  1. Cassandra – это разновидность базы данных NoSQL, которая обеспечивает доступность, а не согласованность. Итак, проблема возникает, если два пользователя выполняют действие над одним и тем же сообщением, например, когда один пользователь редактирует сообщение, а другой удаляет его одновременно.

2. Затем пользователи получали ошибки при редактировании.

3. Как упоминалось выше, Cassandra обеспечивает доступность, а не согласованность, поэтому для решения проблемы команда добавила проверку того, что author_id имеет значение null (что означает, что сообщение удалено); затем они создают надгробие. И эта надгробная плита — ничто, просто удаленное сообщение.

4. И при чтении базы пропускались надгробия.

5. У этого надгробия есть время на 10 дней, которое позже было перенесено на 2 дня из-за проблем, с которыми они столкнулись с одним клиентом после запуска.

Таким образом, Discord запустил и успешно сделал первичную БД — Cassandra с производительностью менее 1 мс при записи и менее 5 мс при чтении.

Сейчас, где-то в 2022 году

Теперь Discord приближается к отметке в триллион с примерно 177 узлами Cassandra, но опять же, БД страдает от различных проблем, и даже задержка была непредсказуемой.

Помимо различных проблем, база данных столкнулась с двумя основными проблемами:

  1. Горячий раздел: этот термин Discord использует, когда возникает ситуация, когда на определенный раздел поступает большой трафик, что приводит к неограниченному параллелизму, что приводит к задержке. Проще говоря, предположим, что есть два раздела: один для небольшой группы друзей с меньшим количеством операций чтения/записи, а другой — широко распространенная общедоступная группа с большим количеством операций чтения/записи.

Чтение обходится дороже, чем запись в Cassandra, поэтому эта ситуация с горячим разделом возникает, когда выполняется много операций чтения, а конкретный раздел отстает и вызывает всплески задержки во всех других операциях.

2. Проблемы со сборщиком мусора: команда также потратила много времени на настройку JVM, потому что это также приостанавливает операции и вызывает большие задержки.

Итак, как они решили эту проблему?

Мы уже знаем, что у них есть вариант ScyllaDB (альтернатива Cassandra, но на C++), который решит проблемы с GC. Но горячие разделы все еще могут возникать и в ScyllaDB.

Чтобы решить эту проблему и уменьшить огромный трафик базы данных, Discord добавил службу данных — слой между монолитным API-сервером и кластерами БД.

Этот сервис написан на Rust.

Эта служба данных выполняет две основные задачи:

  1. Объединение запросов. Если несколько пользователей обращаются к одному и тому же запросу на чтение, то в БД попадает только первый запрос, а задачи/запрос сохраняются в службе данных. Другие подобные запросы возвращают значения из самой службы данных.

2. Восходящий поток служб данных: здесь они внедрили маршрутизацию на основе хэшей, что означает, что для каждого запроса служба данных предоставляет ключ маршрутизации. Для сообщений это channel_id. Таким образом, каждый запрос сообщений в одном и том же канале обращается к одному и тому же экземпляру службы данных, что также предотвращает горячие разделы.

Вот и все.

Именно так Discord обрабатывает триллионы данных.

Хорошо, небольшая просьба.

Если вы нашли вышеизложенное полезным или даже плохим, дайте мне знать.

Вы можете прокомментировать здесь или связаться со мной по адресу @ShubhInTech

фин.


Впервые опубликовано здесь


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE