---
title: Системный дизайн — база знаний (числа, back-of-envelope, хранилища, паттерны, карта DDIA)
source: подготовлено 2026-09-17, основание — TASK-45.1; источники — System Design Primer (Appendix + гайд), статья Яндекса habr 564132, DDIA Клеппмана, interactive latency (colin-scott, TASK-45.25), производственный опыт
---

# База знаний по системному дизайну

Плотный справочник для архитектурной секции. Задача документа — чтобы на секции **числа, названия паттернов и трейдоффы звучали из головы**, без пауз. Формат: таблицы + короткие правила проговаривания. Как пользоваться: §1–2 выучить до автоматизма (это скелет back-of-envelope), §3–4 — критерии выбора, §5–11 — словарь паттернов с формулировками для доски, §12 — карта DDIA, §13 — карта инфографики «System Design Blueprint» с мини-блоками, которых не было в §1–12.

---

## 1. Числа

### 1.1 Степени двойки

| Степень | Точное значение | Приближение | Название |
|---------|----------------|-------------|----------|
| 2^10 | 1 024 | ~1 тысяча | 1 KiB |
| 2^20 | 1 048 576 | ~1 миллион | 1 MiB |
| 2^30 | ~1.07 × 10^9 | ~1 миллиард | 1 GiB |
| 2^40 | ~1.1 × 10^12 | ~1 триллион | 1 TiB |
| 2^50 | ~1.13 × 10^15 | ~1 квадриллион | 1 PiB |
| 2^60 | ~1.15 × 10^18 | ~1 квинтиллион | 1 EiB |

Размеры типовых сущностей (нужно для оценки storage):

| Сущность | Размер |
|----------|--------|
| Символ ASCII / байт UTF-8 (латиница) | 1 байт |
| Int / float | 4 байта |
| Long / double / Unix-timestamp (int64) | 8 байт |
| IPv4-адрес | 4 байта |
| UUID | 16 байт |
| IPv6-адрес | 16 байт |
| SHA-256 (хеш) | 32 байта |
| Короткая строка / URL | ~50–500 байт |
| Запись в БД среднего размера | ~100 байт – 1 КиБ |
| Страница HTML (сжатая) | ~50–100 КиБ |
| Фото (сжатое) | ~0.1–5 МиБ |
| Минута видео 480p / 1080p | ~10 МиБ / ~50–100 МиБ |

### 1.2 Latency numbers every programmer should know

| Действие | Время | В человекообразных единицах (1 нс = 1 с) |
|----------|-------|------------------------------------------|
| L1 cache reference | 0.5 нс | 1 с |
| Branch mispredict | 5 нс | 5 с |
| L2 cache reference | 7 нс | 7 с |
| Захват/освобождение mutex | 25 нс | 25 с |
| Обращение в RAM | 100 нс | 2 мин |
| Сжатие 1 КиБ (snappy/zstd) | ~3–10 мкс | ~час |
| Отправить 2 КиБ по 1 Gbps | 20 мкс | 5.5 ч |
| Чтение 1 МиБ последовательно из RAM | 250 мкс | ~3 суток |
| Round-trip внутри дата-центра | 0.5 мс | ~6 суток |
| Чтение 1 МиБ последовательно с SSD (NVMe) | 50 мкс – 1 мс | до 12 суток |
| Random read 4 КиБ с SSD | ~150 мкс | ~2 суток |
| Disk seek (HDD) | 10 мс | 4 месяца |
| Чтение 1 МиБ последовательно с HDD | 30 мс | 1 год |
| Round-trip через океан (CA ↔ Европа) | ~150 мс | 4.8 года |

**Производные метрики (та же таблица «на поток»):**

| Канал | Скорость последовательного чтения |
|-------|----------------------------------|
| RAM | ~4 ГиБ/с |
| SSD | ~1 ГиБ/с (NVMe — до 3–7 ГиБ/с) |
| HDD | ~30–100 МиБ/с |
| Сеть 1 Gbps | ~100–125 МиБ/с |
| Сеть 10 Gbps | ~1 ГиБ/с |
| Round-trip в ДЦ | ~2 000 RT/с — сетевые хопы «не бесплатные» |
| Свет вокруг Земли | ~5–7 оборотов/с — «скорость света» в распределённых системах это ~150 мс до другого континента |

**Мнемоники:**
- Лестница ×1000: **нс → мкс → мс → с**. RAM — нс, SSD — мкс, HDD и сеть до другого ДЦ — мс, океан — сотни мс.
- Каждый следующий уровень быстрее предыдущего в ~10–1000 раз; **RAM быстрее SSD в ~100–1000 раз, SSD быстрее HDD-seek в ~100 раз**.
- «Память — это бесплатно, диск — это дорого, сеть через океан — это вечность»: отсюда все паттерны (кэш, батчинг, locality).
- Избегать: random reads на HDD (10 мс seek), синхронных вызовов через океан в горячем пути, «одна лишняя цифра в латентности = другой дизайн».
- **Порог человеческого восприятия — ~100 мс:** лаг меньше ~100 мс человек не замечает (источник 4, habr 516604). Отсюда SLO 150 мс у эталона Яндекса — «на грани комфорта», а round-trip через океан (~150 мс) сам съедает весь бюджет ответа.

**Происхождение чисел: тренды железа (материал 21, colin-scott — интерактивная таблица «числа по годам»):**

- CPU-числа — это такты: **L1 = 3, branch mispredict = 10, L2 = 13, mutex = 50, сжатие 1 КиБ = 6 000 тактов**; при 3 ГГц (0.33 нс/такт) → 1 / 3 / 4 / 17 нс / 2 мкс. На секции называть порядок, не десятые доли (CPU-числа плавают в разы от машины к машине, порядок — стабилен).
- **Стена частот — 2005 год:** герцы удваивались каждые 2 года до ~2005, дальше замерли на ~3 ГГц; расти продолжили ядра, не герцы. Однопоточная производительность исчерпана — горизонтальное масштабирование и конкурентность не выбор, а следствие.
- **Полы латентности не двигаются 20+ лет:** RAM 100 нс (шина даже деградирует с 2000), RT в ДЦ 0.5 мс, океан 150 мс — скорость света. Полосы при этом удваиваются: NIC ×2/2 года, DRAM и SSD ×2/3 года, HDD ×2/5 лет, HDD-seek — всего /2 за 10 лет (самый медленный тренд).
- Фраза для доски: **«полоса дешевеет, латентность — нет»** → батчить, пайплайнить, параллелить, меньше round trip'ов. Одним предложением объясняет пайплайны в протоколах, батчи в Kafka, мультиплексирование HTTP/2.
- Цветовая лестница ×100 (визуальная мнемоника источника): такты/нс → RAM/100 нс → сеть и SSD в ДЦ/10 мкс → диски и океан/мс — перепутать классы сложно: мьютекс не бывает «зелёным», RT в ДЦ — «синим».
- Ориентир свежести: обновление таблицы 2018 (Jeff Dean) — сжатие 1 КиБ 10 → 2 мкс, SSD random read 150 → 16 мкс; на секции безопаснее консервативные значения канона. Конспект и пересчёт тренд-модели → `materials/lsd-interactive-latency.md`.

### 1.3 Календарные константы

| Константа | Значение | Округление для доски |
|-----------|----------|----------------------|
| 1 час | 3 600 с | 3.6 × 10^3 |
| 1 сутки | 86 400 с | ~100 тыс. с (10^5) |
| 1 месяц (30 дней) | 2 592 000 с | ~2.5 млн с |
| 1 год | 31 536 000 с | ~30 млн с (3 × 10^7) |
| 100 лет | ~3.15 млрд с | ~3 × 10^9 |

Availability в минутах простоя: **99 % = 3.65 дня/год**; **99.9 % («три девятки») = 8.7 ч/год**; **99.99 % = 52 мин/год**; **99.999 % = 5 мин/год** (доп. Alex Xu, гл. 2: `простой = (100 − SLA)% × год`).

---

## 2. Back-of-envelope estimation

### 2.1 Метод (порядок вопросов себе)

1. **Масштаб пользователей:** DAU / MAU, пик одновременных.
2. **RPS:** `QPS_avg = DAU × запросов/сутки / 86 400`; `QPS_peak ≈ 2–3 × QPS_avg` (утро/вечер, релизы). Reads обычно ≥ writes в 10–100 раз; запись чаще всего и есть узкое место по консистентности.
3. **Storage:** `записей/с × размер × секунд/год × retention × фактор репликации` + индексы (×2 от сырых данных — хорошая прикидка).
4. **Bandwidth:** `чтение = read QPS × размер объекта`, `запись = write QPS × размер`. Сравнить с 1/10 Gbps NIC и решить: нужен ли CDN / сжатие.
5. **Память кэша:** правило 80/20 — кэшируем горячие 20 %; `память = 0.2 × DAU × запросов/сутки × размер объекта`.
6. **Серверы:** типовое приложение-сервис держит ~1–10 тыс. RPS на ноду (зависит от работы: CPU-bound vs IO-bound); БД — лучше не считать «одна нода потянет», а сразу делить роли.

Правило разговора: **назвать допущение → формулу → число → вывод** («это терабайты, влезает в одну ноду, значит узкое место не storage, а RPS на чтение → кэш/KV-зеркало»).


### 2.2 Пример 1: storage (URL shortener)

Дано: 100 млн новых ссылок/месяц, retention 10 лет, запись ~500 байт.

- Записи: `100M × 12 мес × 10 лет = 12 млрд записей`.
- Сырые данные: `12G × 500 Б = 6 ТБ`; с индексами и оверхедом ×2 → **~12 ТБ**.
- Вывод: 12 ТБ — это одна-две ноды с дисками; storage не узкое место. Значит дизайн крутится вокруг **чтения** (см. classic-designs.md: 500k RPS → KV-зеркало + кэш).

### 2.3 Пример 2: RPS (лента новостей)

Дано: 100 млн DAU, пользователь открывает ленту 10 раз/сутки, публикует 2 поста/сутки, в среднем 300 подписчиков.

- Чтение: `100M × 10 / 86 400 ≈ 11.5k QPS avg`, пик ×3 → **~35k QPS**.
- Запись постов: `100M × 2 / 86 400 ≈ 2.3k QPS`.
- Fan-out: каждый пост → 300 вставок в ленты подписчиков → `2.3k × 300 ≈ 700k вставок/с` в кэш лент. Вот здесь узкое место: **не пост, а доставка**. Отсюда выбор fan-out on write vs read и микс для селебрити (см. classic-designs.md §2).

### 2.4 Пример 3: bandwidth (видео-хостинг)

Дано: 10 тыс. загрузок/сутки × ~1 ГБ исходник; 100 тыс. просмотров/сутки, средний просмотр 5 мин при битрейте 3 Mbps ≈ 110 МиБ.

- Storage-рост: `10k × 1 ГБ = 10 ТБ/сутки` исходников + транскоды ×3–5 версий → **30–50 ТБ/сутки**. Через год — десятки ПБ: только объектное хранилище (S3-класс), никакой NAS.
- Egress: `100k × 110 МиБ ≈ 10 ТБ/сутки` → средний поток `10 ТБ / 86 400 с ≈ 120 МБ/с ≈ 1 Gbps`, пик ×3–5 → **3–5 Gbps**. Вывод: отдавать клиентам напрямую из кластера нельзя (дорого и медленно глобально) → **CDN с offload 90 %+**.
- Транскодинг: 10k видео/сутки, минуты CPU на минуту видео → асинхронный пайплайн через очередь (обработка может отставать от загрузки на минуты — это приемлемо и проговаривается).

### 2.5 Гигиена оценок и пример Twitter (Alex Xu, гл. 2)

Правила из книги — как подавать прикидку на секции:

- **Округлять** до круглых чисел: не 11.64 МБ, а «примерно 10 МБ» — интервью про порядок, а не про точность.
- **Записывать допущения** (письменно/на доске): «предположим 100 млн DAU, 2 твита/день» — интервьюер сможет поправить, а не оспорить результат.
- **Подписывать единицы**: KB — килобайт, Kb — килобит (×8 разницы); латентность в мс, bandwidth в МБ/с.
- Пример книги (Twitter): 100M DAU × 2 твита ≈ 2300–3500 QPS запись; медиа ~30 ТБ/день; 5 лет ≈ 55 ПБ — порядок величин важнее цифр.

---

## 3. Классы хранилищ и критерии выбора

| Класс | Представители | Модель / движок | Сильные стороны | Слабые стороны | Когда выбирать |
|-------|---------------|-----------------|-----------------|----------------|----------------|
| RDBMS | PostgreSQL, MySQL | B-tree, строгая схема, SQL/JOIN | ACID, транзакции, сложные запросы, зрелость, ограничения целостности | Вертикальный масштаб, шардирование вручную, дорогие high-write-нагрузки на большие объёмы | Деньги, заказы, связи сущностей; данные до единиц ТБ; консистентность важнее доступности |
| KV | Redis, DynamoDB, Cassandra | hash / LSM; O(1) по ключу | Гигантский RPS на ноду, горизонтальный масштаб, TTL | Нет JOIN и сложных запросов, ограниченная модель, у Redis — память | Сессии, счётчики, фичи-флаги, кэш, hot path по известному ключу |
| Document | MongoDB, Couchbase | JSON-документы | Гибкая схема, агрегаты «документ = объект домена», атомарность на документ | JOIN слабые, транзакции между документами — боль | Контент с вариативной структурой, каталоги, профили |
| Column / analytics | ClickHouse, HBase, Bigtable | columnar / LSM-семейство | Агрегации по миллиардам строк, сжатие, потоковая вставка | Нет точечных UPDATE, слабые транзакции | Логи, метрики, аналитика, отчёты, event store для чтения |
| Search | Elasticsearch, Solr, OpenSearch | инвертированный индекс | Полнотекстовый поиск, фасеты, морфология, fuzzy | Не источник правды (в конечном счёте eventual), дорогая запись | Поиск по тексту, автодополнение, логи-поиск |
| Time-series | Prometheus, InfluxDB, VictoriaMetrics | time-partitioned columnar | Даунсемплинг, retention, быстрые оконные агрегаты | Специализированная модель | Метрики, мониторинг, телеметрия |
| Graph | Neo4j | граф, index-free adjacency | Траверсы на глубину, связи N-го порядка | Редко нужно; операции на массовом графе дороги | Соцграф, рекомендации, fraud-цепочки |
| Object storage | S3, GCS, MinIO | blob по ключу | Почти бесконечный масштаб, дешевизна, 11 девяток durability | Высокая латентность, нет списков/запросов в реальном времени | Медиа, бэкапы, стейджинг для batch |
| Event log | Kafka | append-only partitioned log | Реплей, ретеншн, десятки МБ/с на партицию, порядок в партиции | Не queryable, порядок только в партиции | Интеграция сервисов, event sourcing, батчи-конвейеры |

**Как отвечать на секции** (по одному предложению на выбор): «Данные реляционные и за деньги → PostgreSQL; hot path по ключу с RPS, которые не тянет SQL → KV-зеркало/Redis; поиск → инвертированный индекс; аналитика → колоночная БД; медиа → S3 + CDN; событийная интеграция → Kafka. Источник правды один (RDBMS), остальные — производные проекции с известным лагом».

### 3.1 Движки хранения: LSM vs B-tree (DDIA 2-е изд., гл. 4)

Два семейства OLTP-движков — классический вопрос этапа 4 «а как внутри вашей БД»:

- **LSM-tree (RocksDB, Cassandra, HBase, LevelDB):** запись → memtable (отсортированная структура в памяти) → flush в **SSTable** (иммутабельные отсортированные файлы на диске, компрессия, sparse index); фоновая **компактация** сливает сегменты как mergesort; удаление — **tombstone**; **Bloom filter** отсекает чтение отсутствующих ключей; компактация size-tiered (сначала мелкие равного размера) vs leveled (уровни по размеру) — компромисс write/пространство.
- **B-tree (PostgreSQL, MySQL, почти все RDBMS):** страницы фиксированного размера, обновление на месте, глубина O(log n) — на практике 3–4 уровня (≈250 TB при branching factor ~500); page split при заполнении; надёжность через **WAL** (журнал до модификации страниц); copy-on-write варианты (LMDB) дают снапшоты.
- **LSM vs B-tree:** LSM — выше write throughput (только последовательные записи, ниже write amplification, лучше компрессия), плата — чтение старых ключей дороже (несколько SSTable), range слабее, компактация конкурирует за IO → **латентность-спайки**; B-tree — предсказуемое точечное чтение и range, плата — write amplification (WAL + запись страницы целиком). SSD: sequential > random даже на flash (erase block ~512 KiB).

---

## 4. Кэш

**Стратегии:**
- **Cache-aside** (базовая): приложение читает кэш, при промахе — БД и запись в кэш; при записи — БД, кэш инвалидируется. Просто, консистентность через TTL.
- **Read-through / write-through**: кэш-слой сам ходит в БД; запись идёт сквозь кэш. Строже, но дороже на запись.
- **Write-behind (write-back)**: запись в кэш, в БД — асинхронно батчами. Быстро, но риск потери при падении — проговаривать явно.
- **Refresh-ahead**: предиктивное обновление горячего до истечения TTL (профилактика stampede).

**Инвалидация:** TTL (универсальная страховка), инвалидация по записи (delete, не update), версионированные ключи (`key:v2`), событийная инвалидация через шину (Kafka → удалить/прогреть). Классическая гонка «читатель успел положить старое после записи» → лечится коротким TTL; радикально — delayed double delete.

**Cache stampede (thundering herd):** истечение тысячи горячих ключей разом роняет БД. Защиты: (1) single-flight / distributed lock — один запрос пересчитывает, остальные ждут; (2) probabilistic early expiration (XFetch) — обновлять заранее с вероятностью, растущей от близости TTL; (3) разогрев и разнесённые TTL (jitter).

**Прочее, что надо проговаривать:** hit ratio цель 90 %+ для hot path; LRU как дефолт, LFU для неравномерных; hot key (селебрити) → локальный L1 + реплики ключа; метрики кэша обязательны (hit ratio, evictions, latency).

---

## 5. Репликация

- **Leader–follower** (базовая): запись на лидера, реплики тянут WAL/binlog. **Sync** — не теряем данные, платим латентностью; **async** — быстро, лаг и потери при failover; **semi-sync** — компромисс (ждём ACK одной реплики).
- **Replication lag:** read-your-writes ломается. Средства: читать свои записи с лидера (sticky), монотонное чтение с одной реплики, версионные токены (LSN), наблюдение за lag как SLO.
- **Multi-leader:** несколько пишущих узлов (мульти-ДЦ, оффлайн-клиенты). Плата — конфликты writes; решение: LWW (теряет данные), CRDT, ручное разрешение. На секции: «избегаю без необходимости».
- **Leaderless (Dynamo-стиль):** пишем в W реплик, читаем из R, при `W + R > N` читаем свежее; hinted handoff, read repair, anti-entropy (Merkle-деревья). Tunable consistency. Членство/детект отказов — **gossip-протокол** (без центрального детектора = без SPOF); при недоступности «своих» узлов — **sloppy quorum**: пишем на ближайшие доступные с hint, отдаём владельцу позже (Alex Xu, гл. 6).
- **Failover:** детект (heartbeat + кворум), выбор нового лидера, fencing старого (split brain = два лидера пишут — катастрофа), автоматический vs ручной (проговаривать: автоматика быстрее, но ложные failover дороже простоя).
- **Что реплицируем (DDIA 2-е изд., гл. 6):** statement-based (нестабильно: now()/rand()), WAL (привязан к версии движка), **logical/row-based лог** — переносимый компромисс, фундамент CDC; сессионные гарантии формулируются по позиции в логе (read-your-writes = «читай с реплики, дотянувшей позицию моей записи»; monotonic reads = приклеивание к реплике; consistent prefix reads = порядок причинных записей). Кворумы `W+R>N` дают свежесть, **но не linearizability** — см. §7.

---

## 6. Шардирование

**Сначала — а надо ли?** Лестница «до шардирования»: индексы → вертикаль (железо) → реплики на чтение → кэш → денормализация/проекции → и только потом шарды. Шардирование — последняя ступень, потому что оно ломает транзакции, JOIN и операции.

**Стратегии:**
- **Range:** по диапазону ключа (даты, ID-отрезки). Плюс — range-запросы, минус — hot spot на «свежем» диапазоне.
- **Hash:** равномерно, но нет range-запросов; перешардирование болезненное.
- **Consistent hashing:** кольцо + **виртуальные ноды** (100–200 на ноду) → при добавлении/уходе узла переезжает ~1/N ключей, а не почти всё. Стандартный ответ на «как перекладывать шарды без даунтайма».
- **Directory:** lookup-сервис хранит карту; гибко (неровные данные), но сама карта — точка отказа/кэширования.

**Hot partition:** селебрити/перегретый ключ перекашивает шард. Средства: salting (ключ + суффикс с последующей агрегацией), выделение горячего в отдельный шард/сервис, локальный кэш на ноде.

**Шард-ключ — главное решение:** выбирается по access pattern, менять после — переливка всех данных. Кросс-шардные транзакции и JOIN → избегать (денормализация, 2PC — осторожно, см. §7). Ребалансировка: удвоение числа шардов заранее, миграция в фоне с dual-read.

**Поверх шардов (DDIA 2-е изд., гл. 7):**
- **Вторичные индексы:** local (каждый шард ищет сам → scatter-gather по всем шардам) vs **global** (сам распределён по ключу индекса — быстрее поиск, но отстаёт от записи и hot-spot-уязвим).
- **Сколько шардов:** фиксированное число маленьких шардов заранее — миграции дешевле, но больше метаданных; динамическое расщепление — автоматика, но движущиеся границы. Не mod N (двигается почти всё).
- **Request routing:** «где мои данные?» — слой маршрутизации + метаданные в координационном сервисе + кэш на клиенте; изменение членства — gossip/notifications.
- **Мультиарендность:** tenant_id в ключе шарда; шумные соседи (noisy neighbors) изолируются выделенными шардами.

---

## 7. Консистентность и распределённые транзакции

- **CAP:** при сетевом разделении (P — не опция, оно случается) выбираем C или A. Формулировка для доски: «в одном ДЦ почти всегда C; между ДЦ — вынужденно AP с eventual».
- **PACELC:** даже без разделения (Else) платим Latency за Consistency или наоборот. Честнее CAP в обычной жизни: строгая консистентность = дополнительный round-trip.
- **Модели:** linearizability (выглядит как одна копия; дорого) → sequential → causal → eventual (дёшево, но аномалии: read-your-writes, monotonic reads нужно обеспечивать отдельно).
- **Quorum:** `W + R > N` гарантирует пересечение; настройка W=N/R=1 (строгая запись), W=1/R=N (строгое чтение), промежуточные — по чтению/записи. Конфликты параллельных версий отслеживаем **векторными часами** (счётчики по узлам в каждой записи): определяют причинность; параллельные ветки → отдаём клиенту обе версии, слияние вручную (Alex Xu, гл. 6, Dynamo).
- **2PC (prepare/commit):** строгая атомарность, но координатор — точка блокировки и отказа; на секции говорить: «в высоконагруженных системах избегаю, применяю саги».
- **Saga:** последовательность локальных транзакций + компенсирующие действия при откате (order → reserve → charge → ship; откат = cancel/refund). Оркестрация (координатор) vs хореография (события через шину).
- **Transactional outbox:** запись в БД и публикация события атомарно: событие пишется в outbox-таблицу в той же транзакции, отдельный воркер/CDC (Debezium) публикует в Kafka. Решает «БД записала, событие потерялось».
- **Идемпотентность:** точно-once между системами не существует — есть at-least-once + дедупликация (idempotency key, уникальные constraint, таблица обработанных).

**Уровни изоляции и гонки (DDIA 2-е изд., гл. 8):** read committed (нет dirty read/write: MVCC — читатели видят закоммиченные версии, row-lock на запись) → **snapshot isolation** (транзакция читает согласованный снапшот на старте) → serializable (2PL или **SSI**: MVCC + отслеживание опасных rw-антизависимостей → abort вместо блокировок). Гонки: **lost update** (read-modify-write; лечится SELECT FOR UPDATE / CAS / автоматическим детектом в MVCC), **write skew** (две транзакции читают пересечение, пишут разные строки — инвариант сломан; лечится serializable/constraint/материализацией конфликта), phantom (предикатные чтения → predicate locks).

**Linearizability vs serializability (DDIA 2-е изд., гл. 10, вопрос-ловушка):** linearizability — гарантия свежести одной операции («после завершения записи все читают новое», система выглядит как одна копия); serializability — гарантия изоляции транзакций (порядок любой, если эквивалентен последовательному). Вместе = **strict serializability** (Spanner, FoundationDB). Нужна для: lock/leader election, uniqueness-ограничений, cross-channel timing. Дают: single-leader (пока лидер настоящий) и консенсус; **кворумы W+R>N НЕ дают** (гонки concurrent read repair; LWW по wall-clock — тем более теряет данные).

**Часы и порядок (DDIA 2-е изд., гл. 9–10):** time-of-day (NTP, прыжки, drift до 200 ppm) против monotonic (только интервалы). **Lamport clock** (counter+nodeID) и **hybrid logical clock (HLC)** дают total order, согласованный с причинностью — но не linearizability; параллельность детектируют только **vector clocks** (дороже по размеру). ID: автоинкремент = linearizable fetch-and-add; Snowflake/UUIDv4/ULID теряют порядок.

**Консенсус (DDIA 2-е изд., гл. 10):** эквивалентные формулировки — single-value consensus, linearizable CAS, shared log (**total order broadcast**), atomic commit, fetch-and-add; свойства agreement/integrity/validity (safety — держится всегда) + termination (liveness — требует большинства живых). Механика: epoch/term, уникальный лидер эпохи, два голосования (выборы + коммит) с пересекающимися кворумами. Практика — **координационные сервисы** (ZooKeeper/etcd/Consul): locks/leases + **fencing tokens** (zxid/cversion в ZooKeeper, revision в etcd, epoch в Kafka; term/ballot в Raft/Paxos) + failure detection (сессии, ephemeral nodes) + change notifications; service discovery — кэшировать (observers).

**Распределённые транзакции на практике (DDIA 2-е изд., гл. 8):** 2PC/XA — in-doubt транзакции держат локи при падении координатора, «heuristic decisions» ломают атомарность; **NewSQL** (CockroachDB, Spanner, TiDB, FoundationDB, транзакции Kafka) — реплицированный координатор на консенсусе, без XA-болей. **Exactly-once без распределённых транзакций:** таблица обработанных message-ID в локальной транзакции = идемпотентный консьюмер (так делает Kafka Streams).

---

## 8. Очереди и потоковая обработка

**Зачем:** развязка сервисов, буферизация пиков (load leveling), ретраи, broadcast, порядок и реплей. Плата: лаг, дубли, сложность отладки.

**Kafka — словарь:** topic → **партиции** (порядок и параллелизм внутри партиции; ключ маршрутизирует), **consumer group** (каждая партиция — одному консьюмеру группы), **offsets** (позиция, коммитится; реплей с любого offset), retention по времени/размеру (лог можно перечитать), ISR для надёжности, `acks=all` для данных, которые нельзя терять.

**Delivery semantics:**
- **At-most-once** — может потерять, не дублирует (fire-and-forget).
- **At-least-once** — дефолт надёжных систем; дубли неизбежны → потребитель обязан быть **идемпотентным**.
- **Effectively-once** — at-least-once + дедуп (Kafka transactions / idempotent producer / ключи дедупа на стороне потребителя).

**Паттерны:** DLQ для ядовитых сообщений, backpressure (не тащим быстрее, чем можем обработать), competing consumers для масштаба, приоритетные очереди (отдельные топики), dead man's switch на затишье.

**Группы потребителей (DDIA 2-е изд., гл. 12):** одна consumer group — **load balancing** (партиция — одному консьюмеру группы), разные группы — **fan-out** (каждая получает всё); acknowledgments + redelivery. Обычные брокеры (AMQP/RabbitMQ) — delete-after-delivery; **log-based (Kafka)** — append-only партиции, consumer offsets, retention и реплей.

**CDC и компоновка (DDIA 2-е изд., гл. 12):** **CDC** — репликационный лог БД → стрим (Debezium/Kafka Connect): БД не знает об этом, исторические данные — через initial snapshot + offset; **log compaction** — по ключу хранится только последнее значение (навсегда), а не окно по времени. CDC (факты изменений) ≠ event sourcing (намерения домена). Окна: tumbling/sliding/session; **event time vs processing time** (часы клиентов плывут — watermarks для закрытия окна).

---

## 9. Отказоустойчивость

**Изоляция и деградация:**
- **Timeout на каждый внешний вызов** — без него один зависший dependency съедает потоки.
- **Retries**: экспоненциальный backoff + **jitter**; только идемпотентные операции; ограничение числа попыток.
- **Circuit breaker:** closed → (ошибки > порога) → open (фейлим сразу, дёшево) → half-open (пробный запрос). Защищает от каскадного падения и даёт зависимости время восстановиться.
- **Bulkhead:** отдельные пулы соединений/потоков на dependency; падение одного не топит остальные.
- **Rate limiting:** token bucket / leaky bucket / sliding window; на клиенте (борьба с абузой) и на сервере (self-protection); `429 + Retry-After`; в распределёнке — Redis + Lua или лимитер на шлюзе.
- **Load shedding:** при перегрузке отказываем «дешёвым» запросам, спасаем критичные; graceful degradation — отдаём кэш/неполные данные вместо ошибки.

**Резервирование:** N+1 на каждом ярусе; active–active (мульти-ДЦ, дороже, выше утилизация) vs active–passive (проще, тёплый простой). Health checks (liveness/readiness), автоматический failover с кворумом.

**Арифметика надёжности:** доступность цепочки = произведение; параллель = `1 − ∏(1−ai)`. «Три девятки» = 8.7 ч/год — уже требует резервирования всего пути.

**Слабые места распределённой среды (DDIA 2-е изд., гл. 9):**
- **Partial failure — норма:** «работает или нет» больше нет; сеть асинхронна — потерянный запрос, очередь, упавшая нода, GC-пауза, потерянный ответ **не отличить**; таймаут — догадка; «нет ответа» ≠ «не выполнилось» → ретраи только для идемпотентного.
- **Часы:** time-of-day (NTP: прыжки, drift) для wall-clock опасен (LWW теряет данные), интервалы — только monotonic; между машинами время несравнимо.
- **Process pauses / зомби-лидер:** GC, VM suspend, swap — нода «засыпает» на секунды, не замечая истёкшего lease; защита — **fencing token** на каждом grant, хранилище отвергает старые (см. §7).
- **Кворум объявляет мёртвым — нода обязана подчиниться:** узел знает только полученные сообщения; majority-кворум — единственный с гарантированным пересечением.
- **System models:** реалистичная — partially synchronous + crash-recovery; **safety** (не нарушается никогда) vs **liveness** («eventually», при живом большинстве); Byzantine (враньё узлов) — вне охвата датацентров, от слабого вранья — checksums/валидация входа; gray failure (limping node) — хуже чистого отказа.

---

## 10. Эксплуатация (говорим на секции всегда)

- **Golden signals (Google SRE):** latency (отдельно ошибки и успехи!), traffic, errors, saturation. Метрики каждого яруса: QPS, p50/p95/p99, error rate, очередь/лаг, утилизация (CPU, память, соединения).
- **SLI/SLO/SLA + error budget:** SLO 99.9 % даёт бюджет 43 мин/мес; бюджет кончился — фризим фичи, чиним надёжность. На секции это маркер production-зрелости.
- **Релизы:** rolling, **canary** (1 % → 10 % → 50 % → 100 % с авто-откатом по метрикам), **blue-green** (мгновенный откат переключением), feature flags (расходим деплой и релиз фичи).
- **Миграции без даунтайма — expand/contract:** 1) расширяем схему (новая колонка/таблица, nullable, backfill в фоне), 2) двойная запись/чтение-сравнение, 3) переключаем чтение, 4) контракт: убираем старое. Каждый шаг — рабочий релиз. Antipattern: большие миграции ALTER на живых больших таблицах и dual writes без сверки.
- **Наблюдаемость:** metrics (Prometheus) + logs (структурированные) + traces (OpenTelemetry, сквозной trace id). Алерты на симптомы (SLO burn), а не на причины.
- **Ёмкость:** план на пики (реклама, праздники), headroom ≥ 2×, регулярный load-тест.
- **Хвостовая латентность и metastable failure (DDIA 2-е изд., гл. 2):** считать **p50/p95/p99**, среднее врёт; **tail amplification** — один медленный вызов в fan-out-цепочке тянется в общую p99 (N бэкендов → почти каждая страница ловит хвост). **Metastable failure:** перегруз → таймауты → retry storm → система «застревает» в перегрузе даже после спада нагрузки; лечится exponential backoff + jitter, circuit breaker, load shedding, backpressure. Словарь: response time ≠ service time ≠ latency (очередь — главный источник задержки).

---

## 11. Мини-шпаргалка «что назвать на секции»

| Тема | Обязательная лексика |
|------|----------------------|
| Оценка | DAU → QPS avg/peak, storage с retention, bandwidth, 80/20 для кэша |
| Хранилище | источник правды RDBMS, проекции под access pattern, критерии выбора класса |
| Масштаб | кэш → реплики → шардирование; consistent hashing, virtual nodes, hot partition |
| Консистентность | CAP/PACELC, quorum, лаг репликации, saga/outbox вместо 2PC, идемпотентность |
| Очереди | Kafka, партиции, at-least-once + дедуп, DLQ, load leveling |
| Отказы | timeout/backoff/jitter, circuit breaker, bulkhead, rate limit, graceful degradation |
| Эксплуатация | golden signals, SLO/error budget, canary, expand-contract миграции |

---

## 12. Карта DDIA (Клеппман, «Высоконагруженные приложения»)

⚠️ Карта ниже — по **1-му изданию** (= русский перевод). Вышло **2-е издание** (Kleppmann & Riccomini, 2025, 673 стр.): гл. 1 переписана, гл. 2 новая (НФТ + кейс лент), старые гл. 5–9 → 6–10, + логические часы и ID-генераторы, + durable execution/workflow engines в гл. 5. Соответствие глав и приоритеты 2-го изд. (6–10 ядро, 1–5 вторично, 11–13 опционально, 14 — этика) — `materials/ddia-map.md` §0; полный текст 2-го издания с выжимками — `materials/ddia-2ed/ch-*.md` (TASK-45.39).

Приоритеты: **ЯДРО** — читать обязательно, именно отсюда вопросы секции; **вторично** — к интервью после ядра; **опционально** — после секций / для общего развития.

### Часть I. Основы данных (главы 1–4)

| Глава | Тема | Приоритет | Что брать на секцию |
|-------|------|-----------|---------------------|
| 1 | Надёжность, масштабируемость, поддерживаемость | ЯДРО (быстро) | Словарь: нагрузка → латентность p99 → эластичность; «сначала описать нагрузку, потом решать» |
| 2 | Модели данных и языки запросов | Вторично | Реляционная vs документная: локальность данных vs связи; когда NoSQL оправдан |
| 3 | Хранение и извлечение | ЯДРО | **LSM vs B-tree** — любимый вопрос: LSM — быстрый write, компактация, read amplification; B-tree — быстрый read, предсказуемость; плюс хеш-индексы, SSTable |
| 4 | Кодирование и эволюция | Вторично | Обратно-совместимые схемы (protobuf/Avro), зачем schema registry; старые и новые читатели |

### Часть II. Распределённые данные (главы 5–9) — **сердце книги и секции**

| Глава | Тема | Приоритет | Что брать на секцию |
|-------|------|-----------|---------------------|
| 5 | Репликация | ЯДРО | Sync/async, лаг, read-your-writes, failover, split brain, multi-leader конфликты |
| 6 | Партиционирование | ЯДРО | Range vs hash, **hot skew/celebrity**, ребалансировка, запросы по нескольким шардам |
| 7 | Транзакции | ЯДРО | Уровни изоляции, race conditions (dirty/phantom/lost update), serializable snapshot isolation |
| 8 | Проблемы распределённых систем | ЯДРО | Partial failure, неопределённость ответа (timeout — «не знаю»), часы и порядок событий, GC-паузы как «зомби»-процессы |
| 9 | Консистентность и консенсус | ЯДРО (самая плотная) | Linearizability, CAP/PACELC, кворумы, fencing-токены, RAFT/Paxos на уровне идей, зачем ZooKeeper/etcd |

### Часть III. Производные данные (главы 10–12)

| Глава | Тема | Приоритет | Что брать на секцию |
|-------|------|-----------|---------------------|
| 10 | Пакетная обработка | Опционально | MapReduce-идея, partition-parallel batch, когда batch вместо stream |
| 11 | Потоковая обработка | Вторично | **Delivery semantics**, exactly-once иллюзия, окна, переработка (replay) — прямо ложится на вопросы про Kafka |
| 12 | Будущее | Опционально | Общая картина: deriving state from event log |

### Порядок чтения к слотам (18.09 / 21.09 / 22.09)

- **До слота 18.09:** гл. 1, 3, 5, 6 (+ детальный конспект URL shortener из статьи Яндекса). Это скелет: числа, хранение, репликация, партиции.
- **Между 18.09 и 21.09:** гл. 7, 8, 9 — транзакции, отказы, консистентность/консенсус. Самое плотное ядро.
- **Перед 22.09:** гл. 11 + повтор конспектов по ч. II; гл. 2, 4 — по остатку времени.
- Гл. 10 и 12 — после секций, для собеседований уровнем выше.
- После каждой главы — 5-минутный пересказ схемы вслух у доски (протокол тренировки — methodology.md).

Детальная проработка карты чтения и привязка к слотам — `materials/ddia-map.md` (TASK-45.10).

---

## 13. Инфографика System Design Blueprint (learn-system-design) — карта и дополнения

Источник: `system-design-guide.jpeg` из подборки [learn-system-design](https://github.com/beagreatengineer/learn-system-design) («System Design Blueprint: The Ultimate Guide», TASK-45.12): весь путь запроса на одном листе — DNS → балансировщик → API-шлюз → бэкенды → кэш/очереди → БД → хранение медиа, плюс сквозные темы. Большая часть уже покрыта §3–§11; ниже — карта «блок → где в KB» и мини-блоки, которых не хватало. Полная послойная расшифровка — ✅ TASK-45.24 (`materials/lsd-ultimate-guide-image.md`), индекс всей подборки — `materials/learn-system-design-index.md`.

| Блок инфографики | Что на листе | Где в KB |
|---|---|---|
| DNS | resolver → root → TLD → authoritative, GeoDNS, кэш/TTL | §13.1 (новое) |
| API-шлюз | валидация, auth, rate limit, TLS, idempotency key, логи | §9 + §13.7 |
| Load Balancing | алгоритмы + метрики выбора ноды | §13.2 (новое) |
| Real-time транспорт | WebSocket/SSE/polling/webhook/WebRTC/RTMP | §13.3 (новое) |
| Бэкенды | fan-out, конкурентность, распределённые локи, генерация ID | §13.4–13.5 (новое), §7 (идемпотентность) |
| Cache | стратегии записи, eviction, инвалидация | §4 (уже есть) |
| Database | классы хранилищ, шардирование, кворумы, Merkle | §3, §5–§7 + §13.6 (гео) |
| Upload медиа | чанки, signed URL, metadata-таблица, транскодинг | classic-designs §4 |
| Очереди/метрики | лаг, in-transit, golden signals | §8, §10 |
| Платежи | charge-сервис, внешний banking, идемпотентность | §13.7 (новое), §7 |
| Security | OAuth/RBAC, шифрование, audit trail | §13.7 (новое) |

Послойная расшифровка листа и маппинг «блок → где в KB» — `materials/lsd-ultimate-guide-image.md` (TASK-45.24); ниже §13.1–13.7 — мини-блоки с формулировками, §13.8 — дополнения по итогам полной расшифровки.

### 13.1 DNS — одной фразой на секции

Цепочка: клиент → рекурсивный resolver (ISP) → root NS → TLD NS (.com) → authoritative NS → IP; каждый уровень кэшируется с TTL. **GeoDNS** отдаёт IP ближайшего региона — с этого начинается «мульти-ДЦ». Формулировка: «клиент резолвит домен, GeoDNS ведёт в ближайший регион, дальше весь трафик — в LB». Не углубляться.

### 13.2 Алгоритмы балансировщика

Round Robin (stateless-дефолт) • Weighted RR (ноды разной мощности) • **Least Connections** (долгие соединения: websocket/streaming) • Hash/IP-sticky (сессии, кэш-локальность; вместе с consistent hashing — ответ про масштабирование пула LB) • Random (говорим, что не выбираем). Обязательная фраза: «перед LB — health checks, нездоровую ноду выбрасываем из ротации».

### 13.3 Real-time транспорт — выбор по направленности и совместимости

| Механизм | Направление | Когда выбирать |
|---|---|---|
| WebSocket | дуплекс | мессенджер, коллаб-редактор, live-обновления (см. classic-designs §3); LB — least connections/sticky, ping/pong keepalive |
| SSE | сервер → клиент | нотификации, лента: проще WS, поверх HTTP, авто-reconnect |
| Long polling | сервер → клиент | старые клиенты/прокси, где WS не проходит |
| Short polling | клиент опрашивает | простые статусы; называем цену: холостые запросы |
| Webhook | сервер → сервер | push событий наружу (интеграции) |
| WebRTC / RTMP | P2P медиа / ingest | звонки; приём видеопотока → дальше HLS/DASH + CDN |

### 13.4 Распределённая генерация ID (URL shortener, лента, заказы)

- **UUID v4**: без координации, но 128 бит и нет порядка → плохие индексы и шардирование по времени.
- **Auto-increment × N нод** (чёт/нечет или шаг N): просто, но плохо масштабируется и предсказуемо.
- **Snowflake** (64 бита: 41 время + 10 нод + 12 секвенция): хронология «бесплатно», дружелюбно индексам и шардированию; семейство — Baidu UID, Sonyflake. Дефолтный ответ для ID сущностей в масштабе.
- Централизованный генератор (ticket service): просто, но точка отказа; лечится кэшированием диапазонов.

### 13.5 Распределённые локи и координация

Redis (Redlock) — быстро, компромисс по надёжности; ZooKeeper/etcd/Chubby — кворумные, надёжнее и дороже. Применение: leader election, single-flight пересчёт кэша (stampede, §4), дедуп критичных операций. Оптимистичная блокировка (версия/CAS) — дефолт; пессимистичная — короткие критические секции. При локах проговаривать fencing token и «лок ≠ транзакция» (§5, §7).

### 13.6 Гео-шардирование и пространственные данные

Гео-шарды (по регионам): локальность данных, latency, GDPR-границы; цена — кросс-региональная консистентность (§7). Запросы «ближайшие N объектов» — geohash/QuadTree + R-деревья (S2 от Google — тот же жанр ячеек, на сфере); на задачах Uber/карт-класса это ключевой блок выбора БД. Реверс-геокодинг «точка → страна/регион» — point-in-polygon, ray casting (чётность пересечений луча с границами полигона).

### 13.7 Платежи и security — сквозные темы секции

Платежи: charge-сервис с **idempotency key** (повтор запроса ≠ двойное списание), статус-машина платежа, внешний banking-провайдер = медленная зависимость → таймаут/ретрай/очередь + сверка (reconciliation). Ошибки домена (карта просрочена, недостаточно средств, провайдер недоступен) — обрабатываемые ветки, не 500.

Security-чеклист (назвать всегда): OAuth 2.0/JWT, RBAC, TLS in-transit + шифрование at-rest, audit trail, input validation, signed URLs на приватные объекты (медиа), rate limiting (§9).

### 13.8 Дополнения по полной расшифровке листа (TASK-45.24)

Мини-факты, которых не было в §1–13.7; формулировки — как на листе, добавлена расшифровка «зачем»:

- **API-шлюз, ответная сторона** (просим не забыть): gzip/deflate, Request ID (трассировка), pagination, expiry-заголовки (кэш-контроль), mime, cookie, коды/тексты ошибок. Запросная сторона: валидация, auth (OAuth 2.0), rate limit, whitelist/blacklist, flow control, TLS termination, дедуп по idempotency key, metering/диспетчеризация.
- **CDN — push hot / pull rare / hybrid**: горячее проталкиваем на край заранее, редкое тянем по промаху, обычно гибрид; метрики края — cache miss outs, active/total resources.
- **Генерация ID — offline generations**: генератор выдаёт нодам диапазоны заранее — сервис не стоит на критическом пути записи (дополняет snowflake, §13.4).
- **Конкурентность — serially batch**: между «строго последовательно» и пессимистичными локами есть промежуточная ступень — последовательные батчи (дополняет §13.5).
- **Upload медиа — metadata-таблица чанков**: `key | checksum | timestamp` в in-memory key storage, целостность чанка проверяем по checksum при каждом чтении, таблицу синхронизируем централизованно; событие «новый чанк» фан-аутится в MQ → воркеры (транскодинг: compute time, failed count, encoded/compression ratio, storage consumed).
- **Рекомендации — фильтры**: content-based (по признакам контента) и collaborative (по поведению похожих пользователей) — назвать обе, если в системе есть лента/каталог.
- **Метки наблюдаемости листа развешаны по компонентам** (шлюз: 4XX/5XX/2XX, response time; очередь: count, consumption rate, in-transit waiting-for-ack, queue limit; БД: query time, throughput, active connections) — так и подавать на этапе 6: метрики привязаны к узлу, а не списком в конце.

---

## 14. Строительные блоки из Alex Xu Vol. 1 (TASK-45.38)

Источник: «System Design. Подготовка к сложному интервью» (рус. Vol. 1), полный текст глав — `materials/alex-xu-vol1/ch-*.md`, карта переноса — `materials/alex-xu-vol1/_map.md`. Здесь — паттерны, которых не было в §1–13: алгоритмы rate limiting (гл. 4), краулер (гл. 9), уведомления (гл. 10), автозаполнение (гл. 13), блочное хранилище (гл. 15). Snowflake — §13.4; транспорт (polling/WS) — §13.3; consistent hashing — §6; Dynamo-механики — §5/§7.

### 14.1 Алгоритмы rate limiting (гл. 4)

| Алгоритм | Память | Плюсы | Минусы |
|---|---|---|---|
| Token bucket | O(размер корзины) | допускает burst, гибкая настройка скорости | два параметра |
| Leaking bucket | O(размер очереди) | ровный выходной поток | burst режется; два параметра |
| Fixed window counter | O(счетчиков) | просто | burst ×2 на границе окон |
| Sliding window log | O(запросов) | точно | дорого по памяти |
| Sliding window counter | O(счетчиков) | компромисс (гибрид двух) | оценка, не точный лимит |

Распределённый лимитер: **Redis + Lua** (атомарный check-and-set, иначе race между воркерами); multi-DC → лимитер на **edge** (GeoDNS → ближайший узел), консистентность между узлами — eventual, учесть в бенчмарках. Эксплуатация: заголовки `X-RateLimit-*`, код 429, **мониторинг доли заблокированных** (высокая = абьюз или неверный лимит). Клиентские лимитеры (в приложении) — для экономии вызовов, серверные — источник правды.

### 14.2 Поисковый краулер (гл. 9)

Характеристики: масштабируемость, устойчивость, **вежливость** (не DDoS чужие серверы), расширяемость (плагины). Компоненты: seed URL → **frontier** (очередь на загрузку) → загрузчик HTML (+DNS-кэш — узкое место, 10–200 мс) → дедуп контента по хешам (**29 % страниц — дубликаты**; фильтр Блума для «видели URL?») → извлекатель ссылок → фильтр URL → хранилище URL.

Frontier — сердце: **лицевые очереди** (приоритет: PageRank, популярность, частота обновления) + **тыльные очереди** (вежливость: домен → таблица связывания → своя FIFO → выделенный рабочий поток с задержкой). BFS «в лоб» бьёт по одному домену и не учитывает ценность страниц. Ещё: **robots.txt** (кэшировать, уважать Disallow), гео-распределение, timeout на медленные серверы, состояние в хранилище (рестарт после сбоя), спайдертрапы (лимит длины URL, чёрные списки), server-side рендеринг JS-страниц.

### 14.3 Система уведомлений (гл. 10)

Каналы: APNs (iOS) / FCM (Android) / Twilio-Nexmo (SMS) / SendGrid-Mailchimp (email) — провайдеры сторонние, расширяемость обязательна (FCM недоступен в Китае → JPush). Паттерн: сервисы → серверы уведомлений (API, валидация, **шаблоны**) → **очередь на каждый канал** (отказ одного провайдера не роняет остальные) → воркеры → провайдеры. Надёжность: уведомление **не теряется** — журнал уведомлений в БД + **retry** из очереди; доставок может быть больше одной (at-least-once) → **дедуп по ID события**; rate limiting на получателя (иначе отписки); мониторинг **длины очередей** (растёт → добавляем воркеров); аналитика (открытия/клики/отписки), настройки opt-in. Это же — типовой ответ «как связать сервис с внешним миром».

### 14.4 Автозаполнение поиска / typeahead (гл. 13)

Требования: <100 мс, топ-5 по частоте, совпадение с начала строки. Прикидка: 10M DAU × 10 запросов × 20 символов ≈ 24k QPS (пик 48k) — запрос на каждый введённый символ. Ядро — **trie (префиксное дерево)** с частотами; наивный алгоритм O(p) + O(c) + O(c log c). Две оптимизации до **O(1)**: (1) ограничить максимальную длину префикса; (2) **топ-k популярных запросов прямо в каждом узле** — память платим, латентность забираем. Данные строятся offline: логи → **агрегаторы** (частоты за период; для Google хватает недели, для Twitter — реальное время) → воркеры пересобирают trie → БД (документная/снимок или KV «префикс → список») → **кэш trie в памяти** → API. Шардирование — по диапазонам префиксов. Вариант вопроса «top-k самых частых запросов» — это он.

### 14.5 Блочное хранилище и синхронизация файлов (гл. 15, Google Drive/Dropbox)

Файл → блоки (~4 МБ) → сжатие по типу → шифрование → S3; метаданные (блоки + хеши, версии) — в **реляционной БД (ACID)**: нужна **строгая согласованность** между кэшем и БД, инвалидация кэша при записи. Экономия трафика: **дельта-синхронизация** (передаём только изменённые блоки; механика — **rsync**: rolling checksum + сравнение хешей блоков; content-defined chunking делает границы блоков устойчивыми к вставкам — иначе вставка в начало файла инвалидирует все блоки), **дедупликация** (одинаковый хеш = один блок), лимит версий, холодное хранилище (Glacier) для неактивного. Конфликты одновременного редактирования: побеждает первая обработанная версия, второму клиенту — **обе версии** на слияние/выбор. Уведомления об изменениях — **long polling** (одностороннее, редкие события — WebSocket избыточен); оффлайн-клиент — очередь автономной архивации. Таблицы: user, device (push_id), namespace, file, **file_version (immutable)**, block.

### 14.6 Приближённые счётчики: sketch-структуры (system-design-algorithms, 45.35)

Когда точность не нужна, а память/скорость нужны: **HyperLogLog** — счёт уникальных (count-distinct) с ошибкой ~0,8 % при 12 КБ на ключ (Redis: PFADD/PFCOUNT/PFMERGE) — уникальные посетители, поисковые запросы, DAU; **Count-Min Sketch** — частоты элементов потока (топ-k с heap; см. статью 10) и пороговые фильтры; **lossy counting** — «тяжёлые» элементы потока с частотой выше порога за O(1/ε) памяти (кейс Cloudflare: подсчёт для rate limiting миллионов доменов). Правило секции: «деньги/аудит — точный счёт в БД; метрики/лимиты/агрегации — sketch с известной и приемлемой ошибкой». Стыкуется: лимиты §14.1, топ-k агрегаторы §14.4.

---

## 15. Кодирование, эволюция схем и durable execution (DDIA 2-е изд., гл. 5)

Мини-блок под вопросы «как менять формат данных без даунтайма» и «какие alternatives сагам есть":

- **Совместимость:** backward (новый код читает старые данные) и forward (старый код — новые): обязательны при поэтапных релизах; потоки данных — через БД («сообщение будущему себе»), через сервисы (REST/RPC), через сообщения (брокер).
- **Форматы:** JSON/CSV — читаемые, объёмные, двусмысленность чисел; **Protobuf/Avro** — компактные, эволюция через схему (protobuf — теги полей, новые поля с новыми номерами; Avro — writer/reader schema, идеален для CDC), проверка совместимости до деплоя (schema registry).
- **RPC не может спрятать сеть:** частичные отказы, таймауты, семантика ретраев — те же проблемы, что у распределённых систем (§9).
- **Durable execution / workflow engines (Temporal, Restate) — новое во 2-м изд.:** оркестратор персистит состояние workflow в журнал, задачи идемпотентны и ретраятся движком; практическая альтернатива сагам и распределённым транзакциям для долгих бизнес-процессов (заказы, платежи, онбординг). На секции: «сага — дефолт; для долгих многошаговых процессов смотрю в сторону workflow-движков с durable execution».

---

## Связанные документы

- `../interview-materials.md` — общая карта материалов по вакансии
- `materials/` — конспекты источников (статья Яндекса, System Design Primer, habr 516604, видео Gabbard, DDIA) + `learn-system-design-index.md` (индекс подборки, TASK-45.12) + `lsd-ultimate-guide-image.md` (расшифровка инфографики, TASK-45.24) + `alex-xu-vol1/` (книга Алекса Сюя, полный текст глав + выжимки + карта переноса `_map.md`, TASK-45.38) + `ddia-2ed/` (DDIA 2-е издание, полный текст глав + выжимки + карта переноса `_map.md`, TASK-45.39)
- `methodology.md` — фреймворк ответа, тайминг, план тренировки (TASK-45.2)
- `classic-designs.md` — эталонные разборы сервисов (TASK-45.3)
- `../algo-exam/complexity-cheat-sheet.md` — методичка по алгоритмам (этап 1, закрыт)
