Как стать автором
Обновить

Как мы создаём почтовую систему нового поколения Mailion. Архитектура кластера DOS

Время на прочтение18 мин
Количество просмотров6.4K
Всего голосов 14: ↑14 и ↓0+14
Комментарии3

Комментарии 3

Виталий, спасибо за статью, очень круто. Столько всего интересного рассмотрено, и это только одна статья.

Можно нетехнический вопрос? А не разрабатываете ли вы случайно еще одну Cassandra (Rocksandra), или ScyllaDB? Очень много вещей, описанных в статье, реализованы и там. Я думаю, что есть что-то важное, почему вам пришлось писать вашу базу данных, но я не нашел этого в этой статье.

Благодарю за отклик!

В первой статье мы провели краткое сравнение опенсорсных объектных хранилищ (Ceph, Minio, Elliptics и других) и немного поговорили о том, почему было принято решение в пользу собственной разработки. Сейчас постараюсь более развёрнуто об этом рассказать.

В DOS есть два независимых слоя хранения - слой данных и слой метаданных. В первом хранятся бинарные фрагменты, а во втором - различная служебная информация в формате KV. Архитектура слоя метаданных действительно восходит к Amazon Dynamo, прообразу многих распределённых KV баз, в том числе и Cassandra. Это такое же DHT с поддержкой eventual consistency, а для шардирования и репликации используется консистентное хеширование. Поэтому вопрос об использовании готового решения для хранения метаданных вполне закономерен, и я бы перефразировал его и разбил на две части:

При разработке сложной распределённой системы что лучше - строить более однородную систему с нуля или более гетерогенную из готовых кубиков?

На мой взгляд, в каждом из подходов есть свои плюсы и минусы. Своя разработка в краткосрочной перспективе выглядит более долгой и дорогой, но в горизонте нескольких лет оказывается дешевле в поддержке из-за правильно принятых на этапе проектирования решений. На выходе появляется однородная система с чётким набором функций, которую вы полностью контролируете.

Ориентация на готовые компоненты позволяет ускорить старт продукта, но нередко приводит к необходимости доработки внешних компонентов. Когда компонент работает не так, или хочется расширить функциональность, приходится своими силами его допиливать. И тут могут возникнуть сложности с принятием нового кода в апстрим (порой возникает необходимость форка внешнего проекта со всеми вытекающими отсюда последствиями). Доработки сами по себе могут быть очень дорогими или совсем невозможными из-за архитектурных ограничений внешних компонентов (например, реализация дедупликации в большинстве существующих хранилищ - почти нерешаемая задача).

Часто возникают интеграционные проблемы на стыке между компонентами. Проиллюстрирую их следующим примером. В распределённых базах данных краеугольной проблемой является консистентность. Чтобы в том или ином виде обеспечить консистентность различных фрагментов распределённой СУБД, внутри СУБД обычно реализуют механизм внутренних транзакций. Возвращаясь к архитектуре DOS, можно было бы для хранения метаданных использовать какую-то распределённую KV базу, для загрузки и отдачи данных, например, Nginx. Если бы потребовался единый источник консистентости или центр принятия решений, можно было бы прикрутить Etcd, Consul, Zookeeper. Но разработка связующего слоя распределённых транзакций поверх всего этого могла бы стать серьёзной проблемой. Принимая во внимания эти соображения, мы пришли к собственной разработке.

Но представим, что гетерогенная система из готовых кубиков лучше. Какие кубики в этом случае можно использовать?

Здесь хотелось бы разобрать конкретно Cassandra. Не ставя под сомнение её огромный вклад в развитие распределённых СУБД, хочется, пусть и субъективно, её покритиковать.

Первая проблема - отсутствие вариабельности в паттернах применения. В Cassandra очень важным процессом является компактизация. Если она редкая, то можно активно писать в базу, но читать с хорошими таймингами не получится. Если она частая, то получится много и быстро читать, но с записью будет всё плохо. Третьего здесь не дано, и всё ещё осложняется проблемами сборки мусора в JVM.

Вторая проблема - масштабирование кластера. Выглядит этот процесс примерно так. Добавляется новая нода в состоянии Bootstrapping. Вручную ей назначается токен на кольце. Вручную назначается нода-координатор стриминга - процесса перелива данных между нодами при ребалансировке. При этом новая нода сразу же участвует в обработке кворумных запросов на запись. Стриминг заканчивается, нода переходит в состояние Normal. Здесь может возникнуть две беды. Во-первых, координатор и новая нода могут неконсистентно видеть кольцо (кажется, это связано с асинхронностью протокола cluster membership в кластере). Если в момент расхождения колец начать стриминг, это приведёт к очень печальным последствиям. Во-вторых, в кластере одновременно может происходить только один стриминг, то есть даже в огромные кластера можно добавлять только по одной ноде. Эту существенное ограничение на масштабирование, но при этом внутреннего контроля единственности этого процесса в кластере, видимо, не предусмотрено - надо это обеспечивать внешними средствами.

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

Я думаю, что из приведённых примеров очевидно, что для того, чтобы использовать готовый компонент наподобии Cassandra в действительно крупных проектах, потребуется стать экспертом в разработке и эксплуатации этого компонента. В "Одноклассниках" работает один из крупнейших кластеров Cassandra, и я думаю, что разработчики "Одноклассников" в итоге стали контрибьюторами в Cassandra. Это тоже один из возможных вариантов развития, но мы решили пойти другим путём.

Понял вас, спасибо за ответ!
Зарегистрируйтесь на Хабре, чтобы оставить комментарий