Для основной задачи — приём и хранение 500 000 событий в секунду — мы выбрали Apache Cassandra. Именно она проектировалась для write-heavy нагрузок с линейным горизонтальным масштабированием.
# cassandra.yaml — ключевые параметры кластера из 6 нод
cluster_name: 'adtech-events'
num_tokens: 256
seed_provider:
- class_name: org.apache.cassandra.locator.SimpleSeedProvider
parameters:
- seeds: "10.0.1.1,10.0.1.2"
listen_address: 10.0.1.1
rpc_address: 10.0.1.1
endpoint_snitch: GossipingPropertyFileSnitch
commitlog_sync: periodic
commitlog_sync_period_in_ms: 10000
commitlog_segment_size_in_mb: 64
memtable_heap_space_in_mb: 4096
memtable_offheap_space_in_mb: 4096
compaction_throughput_mb_per_sec: 256
concurrent_reads: 64
concurrent_writes: 128
concurrent_counter_writes: 64
Схема таблицы событий с правильным партиционированием:
-- Таблица событий: партиция по campaign_id + дате
CREATE TABLE events.impressions (
campaign_id text,
event_date date,
event_time timestamp,
event_id timeuuid,
user_id text,
creative_id text,
placement_id text,
geo_country text,
geo_city text,
device_type text,
cost decimal,
custom_data map<text, text>,
PRIMARY KEY ((campaign_id, event_date), event_time, event_id)
) WITH CLUSTERING ORDER BY (event_time DESC)
AND compaction = {'class': 'TimeWindowCompactionStrategy',
'compaction_window_size': 1,
'compaction_window_unit': 'DAYS'}
AND default_time_to_live = 7776000 -- 90 дней
AND gc_grace_seconds = 864000;
-- Материализованное представление для аналитики по гео
CREATE MATERIALIZED VIEW events.impressions_by_geo AS
SELECT * FROM events.impressions
WHERE geo_country IS NOT NULL
AND campaign_id IS NOT NULL
AND event_date IS NOT NULL
AND event_time IS NOT NULL
AND event_id IS NOT NULL
PRIMARY KEY ((geo_country, event_date), event_time, event_id, campaign_id);
Результат: кластер из 6 нод (32 ядра, 128 GB RAM, NVMe каждая) стабильно обрабатывает 520 000 записей в секунду при задержке записи P99 = 4 мс.
Оставить комментарий