Cassandra на собеседовании Data Engineer

Проверь себя · 1/3разбор после ответа
Поле age_text хранится как текст и иногда содержит пробелы, например 18. Вы хотите отобрать пользователей 18+ через WHERE. Какой вариант наиболее корректен?

Почему Cassandra спрашивают

Cassandra всплывает на собесах DE каждый раз, когда в вакансии есть слова «высокие нагрузки», «запись миллионов событий в секунду» или «геораспределённая база». Это одна из самых популярных NoSQL-баз для сценариев с колоссальным потоком записи: логи, метрики, ленты, история сообщений. Интервьюер проверяет не столько знание синтаксиса CQL, сколько понимание того, чем Cassandra принципиально отличается от реляционной БД — и почему её нельзя проектировать «как Postgres, только распределённый».

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

Архитектура

Cassandra — распределённое wide-column хранилище без мастера: все узлы равноправны (masterless, peer-to-peer). Нет выделенного «главного» узла, чья смерть уронит кластер, — это даёт высокую доступность и линейное горизонтальное масштабирование.

Кольцо (ring topology). Каждый узел владеет диапазоном токенов.
Replication factor (RF) — сколько копий каждой строки хранится в кластере.

Узлы организованы в кольцо: пространство хеш-ключей разбито на диапазоны токенов, и каждый узел отвечает за свой участок. Строка попадает на узел по хешу её partition key. Copies этой строки (по числу RF) кладутся на соседние узлы кольца. За счёт этого Cassandra изначально спроектирована под линейное масштабирование и работу в нескольких дата-центрах (multi-DC).

Модель данных

Таблицы описываются с составным первичным ключом:

CREATE TABLE events (
  user_id UUID,
  event_time TIMESTAMP,
  event_type TEXT,
  payload TEXT,
  PRIMARY KEY (user_id, event_time)
) WITH CLUSTERING ORDER BY (event_time DESC);

Здесь user_id — partition key: он определяет, на каком узле лежат данные. event_time — clustering column: он задаёт порядок строк внутри партиции (в примере — по убыванию времени, то есть свежие события первыми).

Ключевой принцип, который обязательно спросят: в Cassandra моделирование идёт от запросов, а не от данных (query-first). Сначала выписывают, какие запросы должны быть быстрыми, и только под них проектируют таблицы. Одни и те же данные при этом часто денормализуют и дублируют в несколько таблиц — по одной под каждый паттерн доступа. Джойнов в Cassandra нет, поэтому «собрать данные из разных таблиц на лету» не получится.

Partition key

Partition key определяет, на какой узел попадёт строка. Все строки с одинаковым ключом лежат на одном узле (плюс его реплики), поэтому запрос по partition key быстрый — он идёт на один узел:

SELECT * FROM events WHERE user_id = '...';  -- одна партиция, быстро
SELECT * FROM events WHERE event_type = '...';  -- ALLOW FILTERING, медленно, анти-паттерн

Запрос без partition key (по event_type в примере) заставляет Cassandra сканировать все узлы и требует ALLOW FILTERING — это анти-паттерн, который на проде убьёт кластер. Если такой запрос действительно нужен, под него делают отдельную таблицу с правильным partition key.

Hot partition (горячая партиция). Если у одного user_id накопятся миллионы событий, вся нагрузка по этому ключу ляжет на один узел — получится перекос. Лечится это бакетированием ключа: в partition key добавляют, например, день или час ((user_id, day)), чтобы данные одного пользователя размазались по разным партициям.

Готовишься к собесу Data Engineer?
Spark, Airflow, ClickHouse, SQL для DE — вопросы с разборами в Telegram
Тренировать DE в Telegram

Consistency levels

Consistency level в Cassandra настраивается на каждый запрос отдельно — это её фишка (tunable consistency). Вы для каждой операции выбираете компромисс между скоростью и согласованностью:

  • ONE. Ответ от одной реплики. Быстро, но данные могут быть устаревшими (eventual consistency).
  • QUORUM. Ответ от большинства реплик (N/2 + 1). Баланс между скоростью и согласованностью.
  • ALL. Ответ от всех реплик. Максимально строго, но медленно и уязвимо к падению любого узла.
  • LOCAL_QUORUM. Кворум в пределах локального дата-центра — типичный выбор для multi-DC, чтобы не ходить через океан.
  • EACH_QUORUM. Кворум в каждом дата-центре сразу (для запросов, где важна согласованность между DC).

Важный вопрос на собесе: как получить строгую согласованность на eventually consistent базе? Ответ — правило R + W > RF. Если сумма реплик, подтверждающих чтение (R) и запись (W), больше фактора репликации, чтение гарантированно увидит последнюю запись. Например, при RF=3 запись QUORUM (W=2) и чтение QUORUM (R=2) дают 2 + 2 > 3 — согласованность обеспечена.

Repair и восстановление

Из-за eventual consistency реплики со временем расходятся: где-то запись дошла, где-то нет. Cassandra умеет их синхронизировать тремя механизмами.

Anti-entropy repair. Плановая сверка реплик через Merkle-деревья: узлы сравнивают хеши диапазонов данных и досылают друг другу расхождения. Запускается вручную или по расписанию:

nodetool repair

Рекомендуется гонять регулярно (обычно раз в неделю, в пределах gc_grace_seconds), иначе удалённые данные могут «воскреснуть» из отставшей реплики.

Read repair. Когда при чтении Cassandra видит, что реплики отдали разные версии, она на лету исправляет отставшие, возвращая клиенту самую свежую по timestamp.

Hinted handoff. Если узел-реплика недоступен в момент записи, координатор сохраняет «подсказку» (hint) и досылает пропущенные данные, когда узел вернётся в строй.

Частые ошибки

Проектировать схему как в реляционной БД. Нормализация и вера в джойны — самая частая ошибка. В Cassandra моделируют от запросов и денормализуют данные под каждый паттерн доступа.

Запросы без partition key. ALLOW FILTERING на проде — красный флаг: полный скан по кластеру. Нужен новый паттерн доступа — заведите под него отдельную таблицу.

Горячие и слишком большие партиции. Партиция без бакетирования разрастается и перегружает один узел. Держите размер партиции в разумных пределах (ориентир — сотни МБ, не гигабайты).

Cassandra как источник аналитических ad-hoc запросов. Она заточена под известные заранее запросы по ключу, а не под произвольные агрегации и GROUP BY по всей таблице. Для аналитики данные выгружают в OLAP-хранилище (ClickHouse, Spark).

Игнорировать нюансы удаления. Удаление создаёт tombstone (маркер), а не стирает данные сразу. Большое число tombstone в партиции резко замедляет чтения — про это любят спрашивать.

Связанные темы

FAQ

Чем Cassandra отличается от реляционной БД?

Cassandra — распределённое NoSQL-хранилище без мастера, заточенное под огромный поток записи и горизонтальное масштабирование. В ней нет джойнов, транзакций в привычном смысле и произвольных запросов: схема проектируется от заранее известных запросов, а данные денормализуются и дублируются. Реляционная БД, наоборот, нормализует данные и позволяет строить любые запросы поверх, но хуже масштабируется на запись горизонтально.

Когда выбирать Cassandra, а когда Postgres?

Cassandra берут, когда нужна очень высокая скорость записи, линейное масштабирование и геораспределённость, а паттерны запросов известны заранее (логи, метрики, ленты, история). Postgres выбирают, когда нужны транзакции, джойны, гибкие ad-hoc запросы и объёмы данных умещаются в вертикально масштабируемую БД. Ключевой вопрос — известны ли запросы заранее и важнее ли масштаб записи, чем гибкость чтения.

Что такое tunable consistency?

Это возможность выбирать уровень согласованности на каждый отдельный запрос, а не на всю базу. Одно чтение можно сделать быстрым и «примерным» (ONE), другое — строгим (QUORUM или ALL). Строгую согласованность получают, когда сумма реплик на чтение и запись превышает фактор репликации: R + W > RF.

Как бороться с горячими партициями?

Горячая партиция возникает, когда на один partition key приходится непропорционально много данных или запросов. Лечится это изменением ключа: в него добавляют дополнительное измерение (день, час, хеш-бакет), чтобы нагрузка размазалась по разным узлам. Проектировать ключ так, чтобы данные распределялись равномерно, — часть работы DE.

Это официальная информация?

Нет. Статья основана на документации Apache Cassandra и опыте кандидатов. Конкретные требования зависят от компании, команды и уровня позиции.


Тренируйте Data Engineering — откройте тренажёр с 1500+ вопросами для собесов.