Налаштування Apache Cassandra для високонавантажених веб-додатків
Конфігурація Apache Cassandra для веб-додатку потребує не просто встановлення пакета. Без грамотного проектування схеми та налаштувань кластера ви отримаєте повільні запити, гарячі партиції та нестабільну роботу під навантаженням. За 5 років роботи ми налаштували Cassandra для 30+ проектів: стрічки подій, метрики, логи. Найпоширеніша помилка — неправильний первинний ключ. Ігнорування компрессії та недостатня пам'ять для memtable призводять до падіння продуктивності в 2–3 рази. Правильне налаштування Cassandra з першого разу економить тижні переробок. Ділимося перевіреними прийомами.
Де Apache Cassandra незамінна
Часові ряди з мільйонами подій на секунду, стрічки активності, системи логування, IoT-телеметрія — там, де потрібно писати швидко та багато. Netflix, Discord, Apple використовують Cassandra саме для цього. Discord зберігає трильйони повідомлень. Для OLTP зі складними транзакціями — не підходить. Ми застосовуємо Cassandra для зберігання метрик та логів: вона дає лінійне масштабування запису та відмовостійкість без єдиної точки відмови.
Налаштування Cassandra 4.1: встановлення та конфігурація
Як встановити Cassandra 4.1?
- Додайте репозиторій:
echo "deb https://debian.cassandra.apache.org 41x main" > /etc/apt/sources.list.d/cassandra.sources.list - Імпортуйте ключ:
curl https://downloads.apache.org/cassandra/KEYS | apt-key add - - Встановіть пакет:
apt update && apt install -y cassandra
Після встановлення відредагуйте cassandra.yaml:
cluster_name: 'MyAppCluster'
# Мережа
listen_address: 10.0.0.1
rpc_address: 10.0.0.1
seeds: "10.0.0.1,10.0.0.2,10.0.0.3"
# Директорії
data_file_directories:
- /var/lib/cassandra/data
commitlog_directory: /var/lib/cassandra/commitlog # окремий диск для швидкості
hints_directory: /var/lib/cassandra/hints
saved_caches_directory: /var/lib/cassandra/saved_caches
# Продуктивність
concurrent_reads: 32
concurrent_writes: 32
concurrent_counter_writes: 16
memtable_heap_space: 2048
compaction_throughput_mb_per_sec: 64
# Реплікація та консистентність
endpoint_snitch: GossipingPropertyFileSnitch
# JVM (в jvm11-server.options)
num_tokens: 256
Додатково налаштуйте JVM, щоб уникнути довгих GC-пауз:
# /etc/cassandra/jvm11-server.options
-Xms8G
-Xmx8G
-XX:+UseG1GC
-XX:G1RSetUpdatingPauseTimePercent=5
-XX:MaxGCPauseMillis=300
-XX:InitiatingHeapOccupancyPercent=70
Як вибрати стратегію компресії?
Порівняння стратегій ущільнення:
| Стратегія | Призначення | Коли використовувати |
|---|---|---|
| SizeTieredCompactionStrategy | За замовчуванням | Універсальний варіант, підходить для більшості випадків |
| TimeWindowCompactionStrategy | Часові ряди | Дані з TTL, стрічки подій — зменшує кількість файлів |
| LeveledCompactionStrategy | Часті оновлення | Системи з великою кількістю записів, потребує більше дискового простору |
Вибір компрессії безпосередньо впливає на продуктивність читання та запису. Наприклад, TimeWindowCompactionStrategy зменшує кількість SSTable в 2–3 рази порівняно з SizeTieredCompactionStrategy при роботі з часовими рядами. Ми рекомендуємо TimeWindowCompactionStrategy для даних з TTL, а LeveledCompactionStrategy — для сценаріїв з інтенсивними оновленнями. Остання працює на 50% швидше за умови частих оновлень.
Орієнтуйтеся на характер даних. Якщо дані мають TTL і записуються з постійною швидкістю — TimeWindowCompactionStrategy. Для частих оновлень та видалень — LeveledCompactionStrategy. SizeTieredCompactionStrategy — безпечний вибір, якщо не впевнені.
Важливість правильного ключа партиціонування
Ключ партиціонування визначає розподіл даних по вузлах. Якщо він вибраний неправильно, одні вузли будуть перевантажені, інші простоюють. Наприклад, для таблиці user_events ми використовуємо user_id — це гарантує рівномірний розподіл. Для часових рядів (таблиця metrics) складений ключ (service, bucket, metric_name) дозволяє згрупувати метрики по сервісу та часовому вікну. Ніколи не використовуйте стовпці з малою кількістю унікальних значень (boolean або enum) — це призведе до гарячих партицій.
Схема даних — Query-driven design
-- Keyspace з реплікацією
CREATE KEYSPACE myapp
WITH replication = {
'class': 'NetworkTopologyStrategy',
'dc1': 3
} AND durable_writes = true;
USE myapp;
-- Стрічка подій користувача
CREATE TABLE user_events (
user_id uuid,
occurred_at timestamp,
event_id uuid,
event_type text,
payload text,
PRIMARY KEY ((user_id), occurred_at, event_id)
) WITH CLUSTERING ORDER BY (occurred_at DESC)
AND compaction = {'class': 'TimeWindowCompactionStrategy',
'compaction_window_unit': 'DAYS',
'compaction_window_size': 7}
AND default_time_to_live = 7776000;
-- Статистика по користувачах
CREATE TABLE user_stats (
user_id uuid PRIMARY KEY,
total_orders counter,
total_spent counter,
last_active timestamp
);
-- Часові ряди метрик
CREATE TABLE metrics (
service text,
bucket timestamp,
metric_name text,
ts timestamp,
value double,
PRIMARY KEY ((service, bucket, metric_name), ts)
) WITH CLUSTERING ORDER BY (ts DESC)
AND compaction = {'class': 'TimeWindowCompactionStrategy',
'compaction_window_unit': 'HOURS',
'compaction_window_size': 1};
Як інтегрувати Cassandra з Node.js?
import cassandra from 'cassandra-driver'
const client = new cassandra.Client({
contactPoints: ['10.0.0.1', '10.0.0.2', '10.0.0.3'],
localDataCenter: 'dc1',
keyspace: 'myapp',
credentials: { username: 'cassandra', password: process.env.CASSANDRA_PASSWORD! },
pooling: {
coreConnectionsPerHost: {
[cassandra.types.distance.local]: 3,
[cassandra.types.distance.remote]: 1
}
},
socketOptions: { readTimeout: 12000 }
})
await client.connect()
const insertEvent = await client.prepare(`
INSERT INTO user_events (user_id, occurred_at, event_id, event_type, payload)
VALUES (?, ?, ?, ?, ?)
`)
const selectEvents = await client.prepare(`
SELECT * FROM user_events
WHERE user_id = ? AND occurred_at >= ? AND occurred_at <= ?
ORDER BY occurred_at DESC
LIMIT ?
`)
async function writeEvents(events: UserEvent[]) {
const batch = events.map(e => ({
query: insertEvent,
params: [
cassandra.types.Uuid.fromString(e.userId),
new Date(e.occurredAt),
cassandra.types.TimeUuid.now(),
e.eventType,
JSON.stringify(e.payload)
]
}))
await client.batch(batch, { prepare: true, logged: false })
}
async function* fetchEvents(userId: string, from: Date, to: Date) {
const options = { prepare: true, fetchSize: 1000 }
let pageState: Buffer | undefined
do {
const result = await client.execute(selectEvents,
[cassandra.types.Uuid.fromString(userId), from, to, 1000],
{ ...options, pageState })
yield result.rows
pageState = result.pageState as Buffer | undefined
} while (pageState)
}
Рівні консистентності
| Рівень | Швидкість | Надійність | Приклад використання |
|---|---|---|---|
| ONE | Швидко | Низька | Аналітика, кеш |
| LOCAL_QUORUM | Середньо | Висока | Операції запису |
| QUORUM | Повільно | Максимальна | Критичні дані |
const { types: { consistencies } } = cassandra
await client.execute(insertEvent, params, { consistency: consistencies.localQuorum })
await client.execute(selectEvents, params, { consistency: consistencies.one })
await client.execute(criticalQuery, params, { consistency: consistencies.quorum })
Моніторинг та діагностика
nodetool status
nodetool tpstats
nodetool cfstats myapp.user_events
nodetool compactionstats
nodetool cleanup myapp
Увімкніть повільні запити в cassandra.yaml: slow_query_log_timeout_in_ms: 500.
Типові помилки та їх вирішення
- Гарячі партиції через неправильний ключ: використовуйте складені ключі з високою кардинальністю. Уникайте стовпців з малою кількістю значень.
-
Високе споживання пам'яті: зменшіть
memtable_heap_spaceабо перемкніть G1GC на ParallelGC. Економія пам'яті до 30%. -
Повільний запис: перевірте диск для commitlog — використовуйте окремий SSD. Збільшіть
concurrent_writes.
Практичні аспекти та варіанти співпраці
Типовий проект з трьома вузлами та інтеграцією займає 2–3 тижні. Включає аудит вимог, проектування схеми, розгортання кластера, оптимізацію конфігурації та написання адаптера для бекенда. Складні кластери з кількома дата-центрами можуть потребувати до 5 тижнів. Отримайте точну оцінку під вашу задачу — напишіть нам.
Ми виконали понад 30 проектів з Cassandra, включаючи системи метрик для рекламної платформи (100 млн подій на добу) та стрічки активності для SaaS-сервісу. У кожному проекті ми гарантуємо стабільну роботу кластера протягом місяця після здачі. Наші інженери мають 5+ років досвіду з Cassandra та суміжними технологіями. Зв'яжіться з нами для консультації — обговоримо вашу архітектуру безкоштовно.
Що входить в роботу
- Аудит поточної архітектури та вимог до навантаження
- Проектування схеми даних (query-driven design)
- Розгортання кластера (bare-metal / хмара / Docker)
- Оптимізація
cassandra.yaml, JVM та мережевих налаштувань - Інтеграція з бекендом (Node.js, Python, Go)
- Документація схеми та інструкції з експлуатації
- Навчання команди та рекомендації з експлуатації
- Гарантія стабільної роботи кластера протягом місяця після здачі
Замовте налаштування Cassandra під вашу задачу — отримайте консультацію інженера з 5-річним досвідом. Вартість типового проекту — від €2000.







