Cassandra — широкостолбцовая распределённая база данных, которая держит запись и чтение при росте узлов почти линейно. Она не имеет единой точки отказа, переживает выпадение стоек и хорошо подходит для временных рядов, сообщений, телеметрии и каталогов с известными запросами. Но это не «PostgreSQL, только быстрее»: модель данных здесь строится от запроса, а не от нормализованной схемы. Разберём архитектуру, CQL и эксплуатацию без иллюзий.
Когда Cassandra оправдана
База выигрывает там, где много записи, данные растут горизонтально, а геораспределённость важнее строгих транзакций. Она плохо подходит для ad-hoc аналитики, сложных join-ов, отчётов по всей таблице и операций, которым нужна немедленная согласованность всех реплик.
- Подходит: события, метрики, журналы, чаты, IoT, корзины с простыми ключами.
- Не подходит: OLAP, финансовая отчётность, произвольные фильтры, малые данные без роста.
- Ключевой принцип: сначала запрос, потом таблица.
Кольцо, репликация и согласованность
Данные распределяются по кольцу с помощью consistent hashing, а virtual nodes сглаживают неравномерность. Фактор репликации RF задаёт число копий, стратегия NetworkTopologyStrategy размещает их по стойкам и дата-центрам. Координатор принимает запрос, находит реплики и собирает ответ.
Уровни согласованности ONE, QUORUM и ALL определяют, сколько подтверждений ждать. Для устойчивости к потере одной реплики при RF=3 используйте QUORUM для записи и чтения: сумма кворумов больше RF даёт пересечение наборов. Но это не транзакции: конфликтующие записи разрешаются по времени, а «последняя» запись может победить не так, как вы ожидали.
Запись сначала попадает в commit log и memtable, затем сбрасывается в SSTable. Если реплика недоступна, координатор может сохранить hinted handoff и доставить данные позже; это не отменяет repair, а лишь сокращает окно расхождения. Читать с QUORUM при свежей записи дороже, но предсказуемее. Для критических операций выбирайте уровень согласованности осознанно и проверяйте задержки на реальном профиле нагрузки.
Лаборатория в Docker
Для знакомства достаточно одного узла, но поведение кластера лучше смотреть на трёх. В лаборатории не используйте боевые данные и не открывайте порт 9042 в интернет.
docker run -d --name cass1 -p 9042:9042 cassandra:latest
docker exec -it cass1 nodetool status
docker exec -it cass1 cqlsh
docker logs --tail 50 cass1
Официальный образ стартует долго: сначала JVM, затем gossip и инициализация схемы. Если cqlsh не подключается, дождитесь статуса UN у узла, а не перезапускайте контейнер каждые полминуты.
Моделирование данных
Partition key определяет узел и должен быть равномерным. Clustering columns задают порядок внутри раздела и позволяют читать диапазоны. Слишком большой раздел — это горячая точка и долгие compaction; миллионы строк на раздел обычно — признак ошибки.
Денормализация здесь ожидаема: одна таблица под один запрос. Дублирование данных дешевле join-ов, которых Cassandra не умеет. Materialized views и вторичные индексы существуют, но имеют ограничения и не заменяют продуманную схему.
CQL на практике
CREATE KEYSPACE telemetry
WITH replication = {'class': 'NetworkTopologyStrategy', 'dc1': 3};
CREATE TABLE telemetry.events (
device_id uuid,
bucket date,
event_time timestamp,
metric text,
value double,
PRIMARY KEY ((device_id, bucket), event_time, metric)
) WITH CLUSTERING ORDER BY (event_time DESC, metric ASC)
AND default_time_to_live = 7776000;
Составной partition key из устройства и суток ограничивает размер раздела. TTL автоматически удаляет старые данные, но не освобождает место мгновенно: сначала появляются tombstones, затем их убирает compaction.
INSERT INTO telemetry.events (device_id, bucket, event_time, metric, value)
VALUES (550e8400-e29b-41d4-a716-446655440000, '2026-11-06',
toTimestamp(now()), 'temperature', 21.5)
USING TTL 86400;
SELECT event_time, metric, value
FROM telemetry.events
WHERE device_id = 550e8400-e29b-41d4-a716-446655440000
AND bucket = '2026-11-06'
LIMIT 100;
Запрос без partition key приведёт к полному сканированию и предупреждению. Это не «медленно», а потенциально смертельно для кластера. Для глобальных выборок используйте отдельные таблицы-индексы или внешнюю аналитику.
Compaction, tombstones и repair
Запись в Cassandra неизменяема: обновление создаёт новую версию, удаление — tombstone. Compaction сливает SSTable и выбрасывает устаревшие данные. Стратегия зависит от нагрузки: STCS хороша для записи, LCS — для чтения, TWCS — для временных рядов с одинаковым TTL.
nodetool compactionstats
nodetool tablestats telemetry events
nodetool repair -pr telemetry
nodetool cleanup
Repair синхронизирует реплики и обязателен до истечения gc_grace_seconds, иначе удалённые данные могут «воскреснуть». Флаг -pr ограничивает работу primary range и снижает нагрузку. Cleanup запускают после изменения топологии, когда узел перестал владеть частью данных.
Эксплуатация и бэкапы
Снимайте snapshot перед обновлением и храните копии вне кластера. Инкрементальные бэкапы включаются в cassandra.yaml, но snapshot всё равно нужен как точка восстановления. Проверяйте восстановление на отдельном стенде: наличие файлов ещё не означает, что схема и токены совместимы. Для пакетной установки остановка и запуск выполняются через systemd:
nodetool snapshot -t before_upgrade telemetry
nodetool drain
systemctl stop cassandra
systemctl start cassandra
Drain сбрасывает memtable на диск и перестаёт принимать записи; без него остановка может занять больше времени. После старта проверьте nodetool status и tpstats: рост dropped messages указывает на перегрузку координатора.
Диагностика
nodetool status
nodetool tpstats
nodetool netstats
journalctl -u cassandra --since '30 min ago' --no-pager
Ищите узлы в статусе DN, растущие pending compactions, высокий процент tombstones и ошибки в журнале. Для оценки задержек смотрите гистограммы в nodetool tablestats и метрики JVM. Не лечите перегрузку увеличением heap без анализа: слишком большой heap усиливает паузы GC.
Чек-лист перед продакшеном
- RF не меньше трёх, стойки и дата-центры учтены.
- Partition key равномерен, размер раздела контролируется.
- Запросы покрыты таблицами, а не полным сканированием.
- Настроены repair, snapshots и мониторинг tombstones.
- Проверено восстановление, а не только создание бэкапа.
- Есть план роста: добавление узла и перераспределение данных.
Итог
Cassandra даёт масштабируемость ценой дисциплины: данные моделируются под запросы, согласованность выбирается осознанно, а обслуживание включает repair и compaction. Начните с трёх узлов и реалистичной нагрузки, измерьте размер разделов и задержки, и только потом увеличивайте кластер. Если нужны join-ы и транзакции, честно выберите другую базу.