Перейти к содержанию

D. High-volume Event Storage

Walkthrough · Раздел 02

Тип материала: учебный архитектурный сценарий. Не описывает систему конкретной компании.

Границы и предпосылки

Cassandra5.0 либо ScyllaDB2025.1; immutable event history с lookup по tenant/time. Common CQL subset не обещает идентичные defaults/операции. HYPOTHETICAL; retention, bucket width и shard count определяются workload, без универсальных чисел.

Архитектура

Все узлы и связи — HYPOTHETICAL.

flowchart TB
  Kafka --> Router[Stable hash and layout version]
  Router --> Bucket[Bounded tenant time shard partitions]
  Bucket --> Replicas[Configured replica set and CL]
  Replicas --> LSM[Commit log memtable SSTables]
  LSM --> Compaction[TWCS and safe tombstone GC]
  Query[Time range query] --> Fanout[Known buckets and shards]
  Fanout --> Bucket

Последовательность операций

  1. Контракт immutable event задаёт tenant, event_id, occurred_at, original expiry deadline и payload. Для одного ID время/payload не меняются; corrections — отдельные версии или иной model.

  2. Router вычисляет event_day, layout_version и shard по явно заданному stable hash, например фиксированной реализации SHA-256 bytes modulo N. Встроенный process-randomized hash языка не использовать. N/algorithm версионируются.

  3. Partition key=(tenant,day,layout_version,shard), clustering=(occurred_at,event_id). Отдельная таблица lookup by event_id нужна, если требуется запрос без time; её dual-write consistency надо проектировать отдельно.

  4. Writer вычисляет remaining TTL по original deadline, пропуская уже истёкшее. Повтор не должен продлевать retention. Политика timestamp при retry должна быть согласована: обычный upsert/timestamp resolution не является проверкой payload equality.

  5. Driver задаёт write/read CL в нужном DC и обрабатывает timeout как ambiguous outcome. Для RF3/local quorum пример кворума — 2, но это объяснение алгоритма, не sizing recommendation. В Scylla2025.1 LWT неприменим к tablets keyspace; event path LWT не требует.

  6. Reader перечисляет известные buckets/layout versions/shards, делает bounded clustering-range queries с paging и merge sorted results. Не выполнять бесконтрольный global fan-out или ALLOW FILTERING по payload.

  7. TWCS обслуживает временные runs; одинаковая expiration policy, редкие late writes, repair schedule и достаточный disk headroom позволяют безопасный lifecycle. Expired данные физически уйдут позже, после compaction/safety checks.

Failure modes и recovery

Сбой Поведение и восстановление
Write timeout Повтор stable primary key и immutable payload; помнить timestamp/TTL semantics и неопределённый исход.
Hot tenant/partition Увеличить будущий layout shards, хранить routing version; старые partitions не перераспределятся магически.
Node отсутствовал долго Оценить repair/tombstone safety, выполнить documented replace/rebuild; не возвращать stale disk без анализа.
Repair/compaction backlog Снизить ingest/дать ресурсы и место; не сокращать GC horizon без доказательства безопасности.
Replay старой истории Original expiry deadline исключает продление retention; restore полноты требует сохранённого source archive.

Trade-offs и эксплуатация

Больше shards даёт распределение writes ценой fan-out; меньший bucket ограничивает partition size ценой metadata/query overhead. Денормализованные query tables увеличивают write cost и recovery сложность. TTL и TWCS требуют аккуратности с mixed TTL/late updates; counters не используются для финансовых сумм.

Код и границы проверки

events.cql — schema/TWCS/query. Cassandra/ScyllaDB runtime отсутствует; CQL не прошёл server validation, replication DC name и options требуют проверки в реальном кластере. Нет обещаний native arbitrary point-in-time restore для обеих систем.

Типичные ошибки проектирования

Обещать exactly-once по одному компоненту; не хранить stable identity/version; путать ACK, visible state и восстановимость; не учитывать replay/retention horizon. Таблица отказов задаёт обязательные сценарии дальнейшего тестирования.

Вопросы на собеседовании

Где заканчивается транзакционная гарантия? На явно указанной local/engine boundary. Все последующие projections требуют собственного delivery/retry/version contract и контроля полноты.

Практические упражнения

Постройте worst-tenant partition size по своим rows/day/bytes. Затем сделайте drill потери node, late replay после TTL и migration N→новое N. Проверяйте не только count, но и event IDs, deadline и query fan-out.

Дополнительные источники

Общий отчёт проверок (архив рабочего проекта). Ни статическая проверка, ни model test не подтверждают production reliability.