Базы данных
Cassandra: wide-column для петабайтных данных
Netflix хранит данные о 36 петабайтах просмотров в Cassandra. Когда 200 миллионов подписчиков одновременно смотрят что-то в пятничный вечер - Cassandra обрабатывает миллионы writes в секунду без единого мастер-узла, без единой точки отказа. Ни PostgreSQL, ни MySQL не масштабируются так линейно.
- **Apple iCloud**: 75000+ Cassandra узлов, хранение данных 782 млн устройств - крупнейший известный Cassandra кластер
- **Discord**: 4 триллиона сообщений в Cassandra; в 2023 мигрировали на ScyllaDB (C++ реализация Cassandra API) для лучшей производительности
- **Uber**: история поездок и GPS треки в Cassandra - миллиарды строк с предсказуемым <10ms latency
Partition Key и Clustering Key
Cassandra PRIMARY KEY состоит из двух частей: partition key определяет на каком узле хранятся данные (через Murmur3 hash), clustering key определяет порядок строк внутри партиции. Все строки с одинаковым partition key хранятся на одном узле и читаются за один disk seek.
Горячая партиция (hot partition) - главная проблема Cassandra. Если partition key - это дата, все сегодняшние записи идут в одну партицию = один перегруженный узел. Решение: добавить bucket в ключ: (date, bucket) где bucket = random(0, N).
Таблица message с PRIMARY KEY (chat_id, message_id). Что произойдёт если в чате миллион сообщений?
Gossip Protocol и Ring Architecture
Cassandra - peer-to-peer кластер без master. Узлы образуют кольцо (ring), каждый узел ответственен за диапазон токенов. Gossip protocol - механизм discovery: каждую секунду каждый узел 'сплетничает' со случайными соседями о состоянии кластера. За O(log N) раундов информация распространяется по всему кластеру.
Consistent hashing в Cassandra: при добавлении узла перемещается только 1/N данных, не весь кластер. Virtual nodes (vnodes) улучшают распределение: каждый физический узел отвечает за множество небольших диапазонов токенов, что делает балансировку почти идеальной.
Cassandra кластер из 6 узлов, replication factor = 3. Сколько узлов могут упасть без потери доступности данных?
Уровни консистентности
Cassandra жертвует строгой консистентностью ради availability (AP в CAP). Но уровень консистентности настраивается для каждого запроса. ONE - читает/пишет на 1 узел (быстро, возможен stale read). QUORUM - большинство реплик (баланс). ALL - все реплики (медленно, но строго). LOCAL_QUORUM - quorum в датацентре без cross-DC.
Cassandra LWT (Lightweight Transactions) добавляют compare-and-set операции: INSERT IF NOT EXISTS, UPDATE IF условие. Под капотом используется Paxos - дорогостоящий протокол. Использовать только когда нужна строгая консистентность (например, уникальность username).
Приложение пишет платёж с CONSISTENCY ONE и сразу читает его с CONSISTENCY ONE. Почему возможен 'not found'?
Стратегии компакции
Cassandra использует LSM-tree: сначала в memtable (память), потом flush на диск в SSTable (immutable). Со временем SSTables накапливаются, чтение замедляется. Compaction объединяет SSTables и удаляет tombstones (метки удалённых данных).
| Стратегия | Когда использовать | Trade-off |
|---|---|---|
| STCS (Size-Tiered) | Write-heavy, append-only | Быстрая запись, медленное чтение при большом объёме |
| LCS (Leveled) | Read-heavy, много обновлений | Медленная запись, быстрое чтение, предсказуемый размер |
| TWCS (Time-Window) | Time-series данные с TTL | Эффективное удаление устаревших данных целыми файлами |
Discord использует Cassandra с TWCS для хранения сообщений с TTL. Когда окно времени закрывается, весь SSTable удаляется без дорогостоящего компакции. Это позволяет хранить 4 триллиона сообщений при разумных затратах на хранение.
Таблица метрик: данные записываются непрерывно, хранятся 30 дней, потом удаляются. Какая стратегия компакции?
Data Modeling в Cassandra
Главное правило Cassandra data modeling: модель определяется запросами, а не сущностями. В SQL сначала нормализуют данные, потом пишут любые запросы. В Cassandra сначала определяют запросы, под каждый запрос создают отдельную таблицу с нужным partition key.
Cassandra не поддерживает JOINs и subqueries. Если запрос требует JOIN - нужно денормализовать данные при записи (Materialized View Pattern). Запись немного дороже, зато чтение всегда быстрое и предсказуемое.
Cassandra - просто масштабируемый MySQL
Cassandra требует полного переосмысления data modeling. Нет JOIN, нет произвольных WHERE, нет транзакций. Зато: линейное масштабирование, нет single point of failure, петабайты данных.
Разработчики с SQL бэкграундом пытаются использовать Cassandra как реляционную БД. Это приводит к ALLOW FILTERING, secondary index антипаттернам и медленным запросам. Query-first моделирование - ключевой навык.
В Cassandra нужно получить заказы пользователя за последние 7 дней. Какой подход правильный?
Ключевые идеи
- **Partition Key**: определяет узел хранения, должен иметь высокую cardinality и равномерное распределение - горячая партиция = узкое место
- **Consistency Levels**: ONE (быстро, eventual), QUORUM (баланс), ALL (медленно, строго) - выбор для каждого запроса
- **Query-first modeling**: под каждый запрос - отдельная таблица; денормализация и дублирование данных - норма, не антипаттерн
Связанные темы
Cassandra строится на нескольких фундаментальных концепциях:
- LSM-Tree — Cassandra использует LSM-tree для всех операций записи - memtable + SSTables
- CAP теорема — Cassandra - AP система: availability и partition tolerance за счёт eventual consistency
- Time-series базы данных — Cassandra с TWCS - популярный выбор для time-series при нагрузке выше TimescaleDB
Вопросы для размышления
- Система аналитики: миллион событий в секунду, нужен count по user_id за последний час. Как смоделировать в Cassandra?
- Когда стоит выбрать Cassandra вместо PostgreSQL даже при небольшом объёме данных?
- Cassandra гарантирует 'eventual consistency'. Что это означает для пользователя приложения на практике?