← назад к разделу

«Возьмём Cassandra, она же масштабируется» — фраза, за которой часто нет понимания, чем Cassandra отличается от привычной базы и какой ценой даётся её масштаб. Cassandra решает вполне конкретный класс задач и в других делает только хуже. Разберём, что она такое, и сравним с двумя другими популярными вариантами — реляционной PostgreSQL и документной MongoDB (их сравнение между собой — в отдельной статье). Это статья про выбор; подробный разбор устройства Cassandra — в отдельном разделе.

Вопрос 1: последние заказы клиента 42 PostgreSQL MongoDB Cassandra индекс клиента 41 → #4 42 → #7,#9 добор таблица orders #7 42 1200 #9 42 800 сначала индекс, потом добор строк 42 → #7,#9#7 42 1200#9 42 800 индекс клиента 41 → #4 42 → #7,#9 целиком документ заказа { клиент: 42, сумма: 800, позиции: [3] } одно чтение — документ приходит целиком 42 → #7,#9{ клиент: 42, сумма: 800, позиции: [3] } ключ раздела клиент 42 хеш N1 N2 N3 партиция клиента 42 12:05 #9 800 11:40 #7 1200 ключ раздела → сразу нужный узел, порядок готов N212:05 #9 80011:40 #7 1200 Вопрос 2: заказ #9найти по номеру✓ ещё один индекспо номеру заказа✓ индекс по полюдокумент тот же✗ не тот ключorders_by_idвторая таблицас копией данных

Вопрос один, а пути разные: PostgreSQL находит клиента в индексе и добирает строки, MongoDB отдаёт документ целиком вместе с позициями, Cassandra по ключу раздела попадает сразу на нужный узел и читает готовый порядок. Цена видна на втором вопросе: реляционной и документной базе хватает ещё одного индекса на тех же данных, а Cassandra под каждый новый вопрос нужна своя таблица с копией — поэтому сначала выписывают запросы и только потом рисуют таблицы.

Обязательно

Что такое Cassandra

Лента событий растёт на миллионы записей в сутки, и один PostgreSQL перестаёт успевать писать. Apache Cassandra сделана ровно под это: распределённая NoSQL-база с моделью «широких строк» (wide-column), где запись размазана по десяткам узлов без главного. Название путает: с колоночными базами вроде ClickHouse, где значения одного столбца лежат на диске подряд, у неё общего мало. Здесь «широкая строка» означает другое — у каждой строки может быть свой набор колонок, а физически рядом хранятся строки одной партиции. Она выросла из двух идей: модель данных взята у Google Bigtable, а способ распределения по узлам — у Amazon Dynamo. Отсюда две её определяющие черты:

  • Модель данных «широкая строка». Данные лежат в таблицах с языком запросов CQL, но устроены иначе, чем в реляционной базе: по ключу раздела (partition key) хранится группа строк, сгруппированных и упорядоченных колонками кластеризации. Одна партиция может содержать от одной строки до многих тысяч упорядоченных строк — это и называют wide-column. Проектируют такие таблицы не «от сущностей», а от запросов.
  • Отсутствие главного узла (masterless). В кластере Cassandra все узлы равноправны — нет ведущего, к которому идут все записи. Данные распределены по кольцу по хешу ключа раздела, каждый узел принимает и чтение, и запись. Это и даёт её главное свойство.

Главное свойство — линейная горизонтальная масштабируемость записи. Добавили узлы — пропорционально выросла пропускная способность, без единой точки, в которую упирается нагрузка. Плюс встроенная репликация по нескольким дата-центрам в режиме «активный-активный»: кластер продолжает принимать запись, даже если целый дата-центр отвалился.

Cassandra против PostgreSQL

PostgreSQL — реляционная база с одним первичным узлом на запись. Её сила — строгая схема, JOIN между таблицами, произвольные запросы и ACID-транзакции: перевод денег между счетами либо проходит целиком, либо не проходит вовсе.

Cassandra устроена ровно наоборот там, где это нужно для масштаба:

  • Нет JOIN, и с произвольными запросами туго. Запрос должен бить по ключу раздела; «а покажи теперь под другим углом» без заранее спроектированной под этот угол таблицы работает плохо. С версии 5.0 к этому добавились вторичные индексы нового образца — SAI, storage-attached indexes: они позволяют спросить по обычной колонке, не заводя вторую таблицу. Но запрос без ключа раздела всё равно опрашивает узлы кластера и собирает ответ по кусочкам, так что для частого чтения по-прежнему делают отдельную таблицу, а индекс оставляют для редких обращений.
  • Нет полноценных транзакций между строками. Есть облегчённые условные операции, но переводить деньги между счетами, как в PostgreSQL, сегодня здесь нельзя. Слово «сегодня» тут не для красоты: общие транзакции для Cassandra разрабатывают (замысел называется Accord), и через пару релизов формулировку придётся переписывать. Пока же планировать на это нельзя.
  • Согласованность настраивается на каждый запрос. Cassandra не «всегда несогласованная»: уровень согласованности задают отдельно для чтения и записи. Читаете и пишете с одной репликой — быстро, но чтение может ненадолго отставать (итоговая согласованность). Читаете и пишете с кворумом — получаете строгое чтение (правило R + W > RF), но с большей задержкой. Это осознанный выбор баланса скорости и свежести, а не жёсткая жертва согласованностью.

Вывод: PostgreSQL берут, когда важны транзакции, связи и гибкие запросы на данных, помещающихся на один мощный сервер (плюс реплики для чтения). Cassandra — когда объём записи и требование «всегда доступна» перерастают то, что тянет один первичный узел.

Cassandra против MongoDB

MongoDB — документная база: данные хранятся как JSON-подобные документы с гибкой схемой. Обе — NoSQL и обе умеют масштабироваться шардированием, но природа разная:

  • Топология. У MongoDB есть первичный узел на каждый шард (replica set с автоматическим переключением при сбое). У Cassandra первичного узла нет вообще — запись принимает любой узел. Для сценария «активная запись в нескольких регионах одновременно» Cassandra устроена удобнее.
  • Запросы и индексы. MongoDB богаче: вторичные индексы, гибкие запросы по полям, агрегации, многодокументные транзакции. Cassandra в запросах жёстче — всё вокруг ключа раздела.
  • Ниша. MongoDB — универсальная база под изменчивую предметную область и разнообразные запросы. Cassandra — узкий инструмент под огромный поток записи и постоянную доступность.

Если упрощать: MongoDB гибче в модели и запросах, Cassandra — сильнее в масштабе записи и мультирегиональной доступности.

Модель данных: сначала запросы, потом таблицы

Главная ошибка новичка в Cassandra — проектировать таблицы как в реляционной базе, «по сущностям», а потом удивляться, что нужный запрос невозможен. В Cassandra проектирование идёт от запросов: сначала выписывают, какие именно чтения будут в проде, и под каждое строят свою таблицу, сознательно дублируя данные (денормализация — норма, а не грех). Ключ раздела (partition key) определяет, на каком узле лежат данные и по какому ключу их можно достать; колонки кластеризации задают порядок внутри раздела.

Отсюда практическое правило: если заранее не известно, как будут спрашивать данные, или запросы разнообразны и меняются — Cassandra противопоказана. Она вознаграждает предсказуемые обращения по ключу и наказывает за произвольную аналитику.

Чем три базы различаются

PostgreSQLMongoDBCassandra
Модельреляционная (таблицы)документная (JSON)широкая строка (wide-column)
Схемастрогаягибкаяполустрогая, под запросы
Топология записиодин первичный узелпервичный на шардбез главного узла
Транзакцииполный ACIDна документ и многодок.ограниченные
JOIN/произвольные запросыдаограниченнонет
Согласованностьзависит от уровня изоляции, на репликах чтение отстаётнастраиваемаянастраиваемая, по умолчанию итоговая
Сильна всвязи, транзакции, аналитикагибкая модель, разные запросыогромный поток записи, постоянная доступность

Когда что брать

  • PostgreSQL — выбор по умолчанию: связи, транзакции, гибкие запросы, данные на одном сервере. Большинству сервисов её хватает надолго.
  • MongoDB — изменчивая предметная область, документная модель, разнообразные запросы; нужен горизонтальный рост, но не экстремальный поток записи.
  • Cassandra — телеметрия и события интернета вещей, ленты активности, логи, счётчики, сообщения: огромный поток записи, предсказуемые обращения по ключу, требование «всегда доступна» и запись в нескольких регионах сразу.
поток записи запросы известны заранее десятки тысяч/с Cassandra транзакции не нужны MongoDB схема меняется PostgreSQL нужны связи и отчёты тысячи в секунду PostgreSQL

Слева направо: сначала отсеивает поток записи, дальше вопрос о предсказуемости запросов, и только на последнем шаге решают транзакции; нижняя строка это путь по умолчанию.

Сколько стоит владение Cassandra

Половина решения — не возможности, а эксплуатация, и здесь Cassandra дороже обеих альтернатив.

Минимальный кластер — три узла, и это не рекомендация, а следствие модели: при трёх копиях и кворуме двух кластер переживает потерю одного узла. Один или два узла не дают ни отказоустойчивости, ни смысла всей архитектуры. Для мультирегиональной установки это уже три узла в каждом ЦОД.

Обязательное регулярное восстановление. Плановую сверку реплик (nodetool repair) надо запускать чаще, чем истекает срок хранения меток удаления, иначе удалённые данные воскресают. Это нагрузка на диск и сеть, расписание и присмотр — то, чего в PostgreSQL нет вовсе.

Уплотнение как отдельная забота. Выбор стратегии уплотнения, запас свободного места (размерная стратегия в худшем случае требует столько же места, сколько занимает таблица), контроль числа файлов на чтение. Ошибка здесь выглядит как «кластер постепенно замедляется», и лечится она не индексом, а перенастройкой хранения.

Настройка виртуальной машины Java. Cassandra написана на Java, и её задержки на хвосте распределения определяются сборкой мусора; размер кучи и выбор сборщика — часть обязательной настройки, а не тонкая оптимизация.

Две системы вместо одной. Аналитику по данным в Cassandra не сделать: произвольных запросов там нет. Поэтому рядом почти всегда стоит вторая система — ClickHouse, Spark или хранилище данных, — куда поток уезжает для отчётов. То есть «взяли Cassandra» практически никогда не означает «одна база»: это Cassandra плюс конвейер плюс аналитическое хранилище.

Отсюда честный расчёт: сравнивать надо не «PostgreSQL против Cassandra», а «один сервер PostgreSQL с репликой» против «шесть узлов Cassandra плюс аналитическое хранилище плюс человек, который умеет это обслуживать».

Пороги в цифрах

Разговоры про «огромный поток записи» становятся полезными, когда превращаются в числа. Ориентиры такие.

Один сервер PostgreSQL на обычном железе с быстрыми дисками принимает порядка нескольких тысяч транзакций записи в секунду при коротких транзакциях, и это можно поднять пакетами, COPY и отказом от лишних индексов — в разы. Десятки тысяч записей в секунду на одну машину — уже задача, которая требует настройки и обычно партиционирования; сотни тысяч — не про один сервер.

По объёму: таблицы до сотен гигабайт PostgreSQL обслуживает без разговоров, единицы терабайт требуют партиционирования и внимания к обслуживанию, десятки терабайт на одном сервере — это область, где эксплуатация становится основной работой.

Поэтому практический порог звучит так: пока поток записи измеряется тысячами в секунду, а объём — гигабайтами, вопрос о Cassandra не стоит. Он появляется, когда и запись не влезает в одну машину, и данные растут линейно и безгранично, и запросы известны заранее. Три условия одновременно, а не одно.

С кем на самом деле сравнивать

Если решение в пользу колоночного хранилища с ключом раздела принято, Cassandra — не единственный вариант, и остальные стоит знать.

ScyllaDB — совместимая по языку запросов и драйверам реализация на C++ без виртуальной машины Java: те же модель и API, заметно меньше узлов на тот же поток и нет настройки сборки мусора. Обычно её и рассматривают первой вместо Cassandra.

DynamoDB (в облаке Amazon) — та же идея «ключ раздела плюс ключ сортировки», но как управляемая услуга: эксплуатации нет вовсе, зато есть привязка к провайдеру и оплата по операциям, которая на больших потоках считается заранее.

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

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

Типичные ошибки

  • Берут Cassandra «ради масштаба» без потока записи. Для сервиса на один сервер это лишь потеря транзакций, JOIN и гибких запросов взамен ненужного масштаба.
  • Проектируют таблицы Cassandra как реляционные. Без проектирования от запросов нужные чтения оказываются невозможны или дороги.
  • Ждут от Cassandra транзакций и аналитики. Перевод денег и произвольные отчёты — не её задача; для этого рядом держат PostgreSQL.
  • Путают «NoSQL» с «современно». MongoDB и Cassandra — разные инструменты под разные задачи, а не моднее реляционной базы.
Дополнительно: при первом чтении можно пропустить

Глубже: во что обходится вторая базарасширенное

Все развилки этого раздела сравнивают модели и гарантии, а решение «добавить Cassandra рядом с PostgreSQL» в реальной команде упирается в деньги. Их считают по трём статьям, и ни одна из них не про лицензию.

Железо. У распределённой базы нет конфигурации «один сервер». Cassandra с фактором репликации три это минимум три узла, а с запасом под выход одного из строя и уплотнение, которому нужно свободное место, пять или шесть; каждому нужны быстрые диски и память под кэш. MongoDB это три узла на реплику, а шардированный кластер начинается с одиннадцати. Elasticsearch держит копию данных в индексе плюс реплику, и его узлы упираются в память раньше, чем в диск. Для сравнения PostgreSQL с одной репликой это два сервера, и они уже есть.

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

Лицензии и облачные наценки. Здесь ситуация пёстрая, и её проверяют перед выбором, а не после. Oracle лицензируется по ядрам и стоит как отдел. Neo4j, Redis и Elasticsearch дают бесплатную редакцию с урезанными кластером и резервным копированием, а платную по узлам. Управляемый сервис в облаке снимает часть «часов людей», но берёт за это в полтора-три раза больше, чем те же виртуальные машины, и в нём нельзя поправить то, что провайдер не вынес в настройки.

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

Коротко

  • Cassandra — колоночная распределённая NoSQL без главного узла; её конёк — линейная масштабируемость записи и постоянная доступность, в том числе в нескольких дата-центрах.
  • В отличие от PostgreSQL, у неё нет полноценных транзакций, JOIN и произвольных запросов; согласованность по умолчанию итоговая.
  • В отличие от MongoDB, у неё нет первичного узла и она сильнее в потоке записи, но жёстче в модели и запросах.
  • Таблицы Cassandra проектируют от запросов, сознательно дублируя данные.
  • Ниша Cassandra узкая: телеметрия, события, логи, счётчики — большой поток записи и предсказуемые обращения по ключу. Для связей, транзакций и аналитики берут PostgreSQL.
  • Вторая база стоит железа (три узла и больше), четверти ставки инженера и лицензии или облачной наценки; сравнивают с решением в уже существующей базе, а не с нулём.
  • Владение Cassandra — это минимум три узла, плановая сверка реплик, забота об уплотнении с запасом места, настройка виртуальной машины Java и почти всегда вторая база под аналитику.
  • Порог входа — три условия одновременно: запись не влезает в одну машину (это десятки тысяч в секунду, а не тысячи), данные растут безгранично, запросы известны заранее.
  • В той же нише стоят ScyllaDB (совместима, без Java), DynamoDB и YDB; шардирование MongoDB не избавляет от выбора ключа — те же грабли перекоса.

Что почитать дальше