Модуль 1. Введение: три мира данных

Цель модуля: получить карту территории до погружений — понимать, зачем в одной системе живут две СУБД, куда какая задача ложится, и какие паттерны связывают их в единое целое. Дальше каждый модуль открывает свой участок этой карты.

Перед началом: SQL (SELECT, JOIN, GROUP BY), Docker, Go на уровне go-basic/go-intermediate трека. Инструменты: docker-compose (приложится к каждому модулю), Go 1.22+. Трудоёмкость: ~4 ч (теория 2 ч · практика 2 ч · квиз 0.5 ч).

🔥 Инцидент: отчёт, который положил прод

Понедельник, час пик в OrderFlow: операторы разгребают заказы, платежи идут потоком, маркетинг готовит квартальную сводку по выручке. Аналитик запускает тяжёлый SELECT по таблице заказов — прямо на мастер-PostgreSQL, в ту же базу, где живут заказы и платежи. Так делали и раньше, но теперь данных стало в разы больше.

Через пару минут диск упирается в потолок: в Grafana iowait под 100%, p99 оформления заказа вырастает со 120 мс до нескольких секунд, свободные коннекты кончаются, а операторы видят растущую очередь заказов. Отчёт при этом падает по таймауту: квартальная выручка не посчитана, заказы пострадали.

Первым делом запрос убили через pg_terminate_backend — сервис ожил за минуты. Дальше решили «просто оптимизировать отчёт»: добавили индексы и перенесли запуск на ночь. Помогло ровно на месяц: отчётов становится больше, данные растут, и аналитика снова конкурирует с заказами за один и тот же диск и буферный пул.

Настоящая причина — не в плохом запросе, а в том, что три мира данных свалены в одну СУБД. В модуле соберём карту территории: где кончается OLTP и начинается OLAP, зачем нужен третий, векторный мир, и как CQRS и проекции связывают миры в единую систему.

📖 1.1. OLTP vs OLAP vs Vector: зачем две СУБД вместо одной

Сначала расшифруем аббревиатуры

  • OLTP — Online Transaction Processing, обработка транзакций в реальном времени: короткие операции «создать заказ», «списать деньги», «какой статус у заказа 42?» — миллисекунды, десятки строк, ACID.
  • OLAP — Online Analytical Processing, аналитическая обработка: «выручка по дням за квартал», «p99 времени оплаты» — секунды и минуты, миллионы и миллиарды строк, агрегаты.
  • Vector (векторный поиск) — третий профиль: «найди k ближайших соседей эмбеддинга» — для RAG и рекомендаций (Модуль 10).

Это не маркетинговые ярлыки, а профили нагрузки: разные формы запросов, разные требования к записи, разная физическая организация данных. Дальше по курсу OLTP = PostgreSQL, OLAP = ClickHouse — но важно помнить, что это классы задач, а не названия продуктов (OLTP-баз много, OLAP-движков тоже).

Два профиля нагрузки

Одна и та же «таблица заказов» живёт в двух совершенно разных мирах:

OLTP (PostgreSQL)OLAP (ClickHouse)
Что делаетмного мелких транзакциймало тяжёлых аналитических запросов
Размер запросамиллисекунды, десятки строксекунды, миллиарды строк
Записьпострочно, точечно, с индексамибольшими батчами, append-heavy
ИзмененияUPDATE/DELETE — нормапочти нет: insert-only + ретроспектива
Хранениеrow-oriented: строка целикомcolumn-oriented: колонки отдельно
ИнвариантACID, консистентность здесь и сейчасthroughput и скорость агрегатов
Типовой вопрос«какой статус у заказа 42?»«выручка по дням за квартал, p99 оплаты»

Почему row-oriented не тянет аналитику: чтобы посчитать сумму одной колонки по миллиарду строк, PostgreSQL прочитает все колонки всех строк (каждая страница диска — целиком), а ClickHouse прочитает только нужную колонку, сжатую специально под её тип данных, и распараллелит по ядрам. Разница — не в 2 раза, а в 100x. Обратное тоже верно: точечный UPDATE по индексу — работа PostgreSQL, ClickHouse на ней беспомощен.

Третий мир: vector

Отдельный профиль — векторный поиск (эмбеддинги для AI/RAG): тысячамерные плавающие векторы, поиск ближайших соседей. PostgreSQL закрывает его расширением pgvector (опциональный Модуль 10), а на больших масштабах — специализированные Vector DB. Три мира — три инструмента; курс строит первые два и трогает третий.

Цена «одной СУБД на всё»

Соблазн взять одну систему «и OLTP, и аналитику» обходится дорого в обе стороны:

  • Аналитика на OLTP: тяжёлые запросы вымывают shared_buffers, создают bloat через долгие транзакции (Модуль 2), реплики отстают; точечные операции деградируют.
  • OLTP на OLAP: нет честных транзакций и точечных обновлений; «изменить статус заказа» превращается в перезапись и мутации, latency — не та.
  • Векторный поиск без индекса: точное сравнение со всеми строками — O(N).

Правило курса: данные живут там, где их профиль нагрузки. Границы между хранилищами — не костыль, а архитектура.

📖 1.2. Архитектурные паттерны: CQRS, Event-Driven, проекции

CQRS: разделение модели записи и чтения

Command Query Responsibility Segregation — запись идёт в одну модель (нормализованную, под транзакции), чтение — в другую (денормализованную, под запросы):

text
[Команды: создать заказ] ──► [PostgreSQL: write model] ──► (синхронизация) ──► [ClickHouse: read model]
[Запросы: дашборд, отчёты] ◄────────────────────────────────────────────────────────────────┘

Полный CQRS — это разные БД, разные схемы и событийная синхронизация. Прагматичный (наш случай) — две СУБД, связанные CDC-потоком: PostgreSQL остаётся единственным источником правды, ClickHouse — производная проекция для аналитики.

Event-Driven: изменения как события

Связующее звено между мирами — не «ночной ETL», а поток событий об изменениях. Каждый INSERT/UPDATE/DELETE в PostgreSQL превращается в сообщение (CDC — Change Data Capture, Модуль 6), едет через брокер (Kafka — Модуль 6 брокерского курса) и материализуется в ClickHouse. Отсюда свойства, которые будут проверяться в MVP:

  • Казуальность: порядок событий на сущность сохранён (ключ = id сущности).
  • Идемпотентность: повтор события не меняет результат (ReplacingMergeTree).
  • Eventual consistency: аналитика отстаёт от OLTP на секунды — и это осознанный trade-off, а не баг.

Проекции: производные данные как первосортная сущность

Агрегаты в ClickHouse (материализованные представления) — не «кэш», а честные производные таблицы: посчитаны инкрементально при вставке, живут своей жизнью, восстанавливаются перезаливкой из raw-слоя. Этот стиль — «raw facts + проекции» — пройдет через весь курс (Модуль 7).

📖 1.3. Обзор стека курса

Каждый компонент появляется не «потому что мода», а под конкретную роль:

КомпонентРоль в курсеМодули
PostgreSQLOLTP: заказы, платежи, состояние2–3, 8–9, 11
Расширения PGраспределённость: Citus (шардирование), Patroni (HA), pg_partman, pg_failover_slots3, 11
Kafka + DebeziumCDC-транспорт: изменения PG как события6, 11
ClickHouseOLAP: события, агрегаты, дашборды4–7, 9, 11
Grafanaвизуализация: метрики обеих СУБД и аналитика из CH8, 11
Goприкладной слой: pgx, clickhouse-go, тесты через testcontainersвезде
pgvector(опционально) векторный поиск / RAG10

Инфраструктура курса — единый docker-compose с профилями: pg (Patroni-кластер), kafka (+Debezium), ch (2×2 + Keeper), obs (Prometheus + Grafana). Профили включаются по мере прохождения модулей — как в брокерском курсе.

📖 1.4. Карта расширений PostgreSQL одним взглядом

Детальный разбор — весь Модуль 3 ⭐ (сердце курса), здесь — ориентир:

ГруппаПлагиныОдной фразой
ШардированиеCitus, pg_partman«делим данные, когда один узел исчерпан»
Репликация/HAPatroni, pglogical, pg_failover_slots, Odyssey«мастер умрёт — система не заметит»
CDCpgoutput, wal2json, Debezium«каждое изменение — событие»
Наблюдаемостьpg_stat_statements, auto_explain, pgAudit«видеть, что БД делает на самом деле»
Эксплуатацияpg_repack, pgBackRest/WAL-G, pg_cron«жить под нагрузкой годами»
Специализированныеpgvector, PostGIS, TimescaleDB, pgcrypto«особые типы данных»

Каждая строка этой таблицы — урок Модуля 3 с кодом и лабораторной. ClickHouse расширениями не обрастает — у него другая философия: движки таблиц и встроенная репликация (Модули 4–5).

💻 Практика

  1. Стек на месте: поднимите docker-compose курса (pg + ch + kafka/debezium + grafana), убедитесь, что psql, clickhouse-client и Kafka UI отвечают.
  2. Почувствуйте разницу: создайте в PostgreSQL таблицу событий на 10 млн строк (generate_series) и выполните SELECT date_trunc('day', ts), count(*) ... GROUP BY; затем то же в ClickHouse через generateRandom и вставку батчем. Сравните время — цифры станут личным опытом, а не лозунгом.
  3. Профиль запроса: в PostgreSQL добавьте pg_stat_statements (Модуль 3 расскажет подробно) и найдите самый дорогой запрос из пункта 2.

🧩 Quiz "Проверь себя"

1. Какая группа расширений PostgreSQL отвечает за «мастер умрёт — система не заметит»?
2. Что такое CQRS в прагматичном виде этого курса?
3. Какой профиль нагрузки — работа PostgreSQL?
4. Материализованные представления в ClickHouse — это…
5. Что означает «ClickHouse — производная проекция, PostgreSQL — источник правды»?
6. Зачем нужен CDC-поток между PostgreSQL и ClickHouse?
7. Почему аналитический запрос по одной колонке в ClickHouse на порядки быстрее, чем в PostgreSQL?
8. Eventual consistency аналитики — это…

✅ Итоги модуля

  • Объяснить, почему OLTP и OLAP — разные инструменты, и что даёт колоночное хранение.
  • Нарисовать CQRS-схему курса: PG (write) → CDC → CH (read).
  • Назвать три инварианта пайплайна: казуальность, идемпотентность, eventual consistency.
  • Назвать компоненты стека и роль каждого.
  • Показать на своих цифрах разницу агрегата в PG против ClickHouse.

Шпаргалка модуля

ВопросОтвет
Что такое OLTP?Online Transaction Processing: транзакции в реальном времени, мс, десятки строк, ACID → PostgreSQL
Что такое OLAP?Online Analytical Processing: аналитические агрегаты, секунды, миллиарды строк → ClickHouse
Где живут данные?Там, где их профиль нагрузки: OLTP→PG, агрегаты→CH, эмбеддинги→pgvector/Vector DB
Как связаны?События изменений (CDC) через брокер, не dual-write
Кто источник правды?PostgreSQL; ClickHouse — производная проекция
Что если аналитика отстаёт?Норма (секунды); следим за лагом, а не за «мгновенностью»
Что с изменениями в CH?Нет UPDATE/DELETE — есть версии и ретроспектива (Модуль 6)

🔗 Мостик к Модулю 2

Карта на руках. Дальше — фундамент, без которого всё остальное рушится: внутренности PostgreSQL — MVCC и vacuum, индексы, планы, блокировки и пулы соединений. Приложим SQL-арсенал (окна, CTE, JSONB) и научимся читать EXPLAIN как открытую книгу.