Job 2026 md

title: Статья 11 — Эталонные архитектуры сервисов source: подготовлено 2026-09-17, TASK-45.51; каркас — brief.md §11; основа — classic-designs.md §1–4 (полные эталоны); сверка — Alex Xu гл. 8, 11–12, 14 (TASK-45.38), DDIA 2-е изд. гл. 2 (TASK-45.39), статья Яндекса (TASK-45.5)


Статья 11: эталонные архитектуры сервисов

Одиннадцатая статья серии — сборочная. Разделы 01–10 дали словарь и строительные блоки: фреймворк ведения секции, арифметику, лестницу масштабирования, хранилища, репликацию и шарды, кэш, очереди, отказоустойчивость, согласованность, прикладные компоненты. Критерий «умею, если» из брифа собирает всё это в одно требование: «собираю полный разбор ленты за 15 минут по фреймворку из 6 этапов». Не «знаю паттерны», а «могу провести весь ответ — от требований до эксплуатации — как связный рассказ с числами и трейдоффами». Это ровно формат нашей секции: «крупноблочная схема сервиса уровня инстаграм/твиттер + отказоустойчивость», а инстаграм/твиттер — это лента новостей (§3 этой статьи) плюс медиапайплайн (§5).

Отношение статьи к ../classic-designs.md — главный вопрос, на который она отвечает. Эталонник — это полные разборы: таблица диалога с интервьюером, SQL-схемы, псевдокод горячего пути, таблицы отказов, сверки с Сюем и DDIA. Здесь — ход решения: у каждого сервиса одна большая идея, из которой вытекает всё остальное, скелет из 6 этапов, узкое место и чем отличают сильный ответ. Порядок работы с двумя документами: эта статья читается до эталонов (задаёт карту), эталонник — после тренировочного раунда (сверка; перед раундом не перечитывать — раунд засчитывается только «из головы», ../methodology.md §6.1). Формулы и числа-константы — ../knowledge-base.md (далее KB); каркас 6 этапов — статья 01.

1. Как читать четыре разбора: каркас и ритм

Все четыре эталона рассказываются одним и тем же ритмом — 6 этапов из статьи 01. Сквозной ответ — это не «сначала requirements, потом design», а кольцо с двумя возвратами: числа этапа 1 становятся ресурсами этапа 5, а лист требований этапа 1 закрывается в финале этапа 6. Универсальный каркас, общий для всех сервисов:

# Этап Что должно появиться Откуда берём
1 Требования Функциональные/нефункциональные, числа-гипотезы вслух (DAU, RPS чтение/запись, SLO, консистентность), минус-объём; лист на доске не стирается статья 01 §4, статья 02 §4
2 Потоки и API Сущности, 3–5 сигнатур, control plane vs data plane статья 01 §3
3 Крупноблочная схема 5–8 блоков, путь горячего запроса проговариваем по стрелке статья 03 §6
4 Детали + БД Устройство 1–2 главных блоков, хранилища, ключевой алгоритм, главный трейдофф статьи 04–07, 09
5 Ресурсы и узкие места Back-of-envelope: ноды, storage, bandwidth; узкое место дизайна — где система реально напрягается статья 02
6 Эксплуатация Прогонка отказов по узлам, деградации, метрики, релизы; возврат к листу требований статья 08, статья 12

Формат каждого разбора ниже: одна большая идея (решающий ход, из которого вытекает остальное) → скелет 6 этапов таблицей → ключевые ходы и трейдоффы → узкое место и финал → куда углубляться. Большая идея — это то, что должно всплыть на этапе 1–2, сразу после чисел: она определяет схему, а не украшает её. Интервьюер ждёт её услышать как «точку, вокруг которой собран ответ» — и каждый эталон ниже выбран так, чтобы эта точка была своя.

2. URL shortener — эталон Яндекса

Одна большая идея: чтение доминирует с отношением 50 000:1 — поэтому система делится на два почти несвязанных контура. Data plane (500 тыс. RPS GET /{id} → 302) — это чистое чтение из реплицированного KV-зеркала; control plane (создание ссылок, аккаунты, статистика — единицы RPS записи) — обычное приложение над реляционной СУБД. Всё элегантное в этом эталоне — следствия этого деления.

control:  клиенты → REST API → RDBMS (источник правды) ──репликация──▶ KV-зеркало
data:     клиенты → IPVS → воркер (веб-сервер + L1 LRU + ко-локальный KV) → 302
фон:      очередь → LAT actuator / RPS limiter / TTL-GC (асинхронно)
Этап Ход решения
1. Требования Вытягиваем диалогом: 500k RPS чтения в пике, 10–20 RPS записи, 1 млрд ссылок, 150 мс p95, четыре девятки на чтение, новые ссылки — строго, модификации — лаг в секунды, free-лимит 1000 req/min. Вывод: «дизайн целиком про чтение; строгая согласованность — только для новых ссылок»
2. Потоки и API Data plane — один GET /{id}302, никаких синхронных вызовов в горячем пути; control plane — REST (аккаунты, статистика, правка). ID: random base36, 6+1=7 символов (36⁶≈2.2 млрд; +1 разряд против перебора), не инкремент
3. Схема Два контура физически раздельны: IPVS → воркеры → KV; REST → RDBMS; синхронизация СУБД → KV асинхронная
4. Детали RDBMS — источник правды (сотни ГБ, без шардирования — репликация); KV-зеркало ~100 ГБ — реплицировать, не шардировать (100k RPS на сервер, CPU не тратит) → ко-локация инстанса KV на каждом воркере; лимиты — снимок таблицы RPS в разделяемой памяти воркера (обновление раз в ~100 мс), счётчики — в памяти воркера, батчами; вместо 2PC — коммит после большинства реплик KV + фоновая GC; read-your-writes новых ссылок — L1 LRU на воркере
5. Ресурсы Дефицит — TLS-handshake: ~20k RPS на сервер → 500k/20k = 25 воркеров; KV тянет 100k, но кушает память — ко-локация решает оба; бюджет латентности: ~130 мс из 150 (120 мс сеть клиент↔сервер + ≤10 мс воркер)
6. Эксплуатация Топология от отказа ДЦ, не от пика: 9 воркеров × 4 ДЦ + 4 IPVS + 3 СУБД = 43 сервера; таблица отказов (воркер → размазалось по ДЦ; primary СУБД → страдает только control, GET жив; IPVS → запас); перегрузка чтения: очередь на воркерах, антифрод/blacklist, понижение криптостойкости SSL; финал — каждое требование закрыто и меряется

Ключевые ходы, которые отличают сильный ответ: 302 против 301 — у нас платные правки ссылок (у Сюя вторая грань: 301 кэшируется браузером → клики не считываются — проговорить обе); случайные ID против инкремента — перебор чужих ссылок; «не нужно для ответа пользователю → в память воркера, батчами во внешний мир» (accessed, счётчики, лимиты) — формула, которая переносится в любой сервис; лимитер — leaky bucket со burst budget и состоянием в основной СУБД (не строим ещё один распределённый сервис ради умеренного потока обновлений). Узкое место — не БД и не KV, а TLS на воркерах: система CPU-bound в data plane и I/O-light везде. Финал: «150 мс p95 — бюджет 130 мс; четыре девятки — N+1 и 4 ДЦ; строгие новые ссылки — L1 + majority; каждое требование — с метрикой».

Глубина: ../classic-designs.md §1 (полный конспект статьи Яндекса: диалог, SQL-схемы, алгоритм GET по шагам, таблица отказов, «чему учит эталон»); Сюй гл. 8 — два способа генерации кода (hash + фильтр Блума против base62(ID)) и оценка 1160 QPS записи; конспект — ../materials/alex-xu-vol1/ch-08-url-shortener.md.

3. Лента новостей (Instagram/Twitter) — главный билет нашей секции

Одна большая идея: узкое место не «написать пост», а «доставить его 300 подписчикам за 5 секунд» — и весь дизайн держится на выборе fan-out on write против fan-out on read. Постинг 2.3k QPS при 300 подписчиках = 700 тыс. вставок/с в ленты — на два порядка больше, чем сам постинг. Числа этапа 1 (DAU 100 млн, 10 открытий ленты → ~35k QPS чтения в пике) сами выпрямляют ответ: чтение ×15 к записи, лента обязана быть готовой в кэше.

чтение:  клиент → LB → Feed API → кэш лент (Redis, post_id-списки) ─miss→ merge из таймлайнов
постинг: клиент → Post API → БД постов (источник правды) → событие в Kafka → fan-out воркеры → кэш лент
медиа:   → S3 → транскодинг → CDN (отдельный контур, §5)
Этап Ход решения
1. Требования Гипотезы вслух (KB §2.3): DAU 100M, 10 открытий/сутки → 35k QPS чтения в пике; 2 поста/сутки → 2.3k QPS записи; 300 подписчиков → fan-out 700k вставок/с; p95 ≤ 200 мс; 99.9 %; eventual ≤ 5 с, свой пост автору — сразу; медиа обязательны (но отдельным контуром)
2. Потоки и API POST /posts (idempotency-key), GET /feed?cursor= (курсорная пагинация), follow/like — eventual. ID постов — snowflake (время внутри ID → сортировка ленты = сортировка ID). Постинг/чтение — data plane; профили, подписки, модерация — control
3. Схема Чтение: LB → Feed API → кэш лент → ответ (единицы мс). Постинг: Post API → БД → очередь → fan-out воркеры → кэш. Два пути разной частоты: длинный путь постинга в 15 раз реже — его сложность никому не мешает
4. Детали Центральный трейдофф таблицей: push (быстрое чтение, дорогая запись, катастрофа на селебрити, пушим мёртвым) против pull (дешёвая запись, merge на каждый запрос, катастрофа для читателя с 1000+ подписок) → микс: push обычным (99.9 %), pull для селебрити (>1M); чтение = кэшированный push-список + merge свежих постов селебрити. Кэш лент: Redis по user_id (consistent hashing), только post_id, глубина ~800, 80/20 → единицы ТБ; stampede — per-user блокировка + rebuild merge'ем; read-your-writes — свой пост синхронно в свою ленту. Посты — шард по post_id, соцграф — отдельно по user_id; счётчики — INCR в Redis + батч-флаш
5. Ресурсы Чтение 35k QPS → единицы-десятки нод Feed API; fan-out 700k вставок/с — это и есть дизайн: очередь + шардированные воркеры, метрика — lag; storage постов ~70 ТБ/год → шарды; медиа — сотни ТБ/год в S3-класс + CDN. Формулировка: «две системы разной природы — лента (миллионы мелких операций) и медиа (гигантские блобы); смешивать нельзя»
6. Эксплуатация Приоритеты деградации: чтение > постинг > счётчики; перегрузка ×10 → shedding на постинге + адаптивный fan-out (пушим только активным за 30 дней, остальные pull'ом); отказ Redis-ноды → rebuild из таймлайнов (медленнее, но работает); отказ fan-out-воркеров → «лента стареет» (graceful degradation), алерт на lag; canary на fan-out-воркерах — регрессия доставки видна в lag до полного выката; финал — возврат к листу

Ключевые ходы: celebrity-проблема двусторонняя — (а) пост миллионщика не пушим (merge на чтении, его посты — идеальный кэш-кандидат), (б) горячий ключ кэша реплицируем; фильтры (mute, приватность) применяются до fan-out, иначе «размутинг» невозможен; медиапайплайн не блокирует постинг — плейсхолдер сейчас, рендиции доедут фоном (трейдофф «свежесть > комплектность»). Узкое место — доставка, не запись: формулировка для этапа 5 из DDIA гл. 2: «1M лёгких записей в Redis против 2M тяжёлых чтений — обмен выгодный». Финал: «лента отдаётся из кэша за единицы мс; пост доезжает ≤ 5 с по очереди с метрикой lag; свой пост — сразу; при перегрузке жертвуем счётчиками и свежестью, не чтением».

Глубина: ../classic-designs.md §2 (полный разбор: таблица fan-out, псевдокод publish/fanout, память кэша, таблица отказов, сверки с Сюем гл. 11 и DDIA гл. 2); критерий раздела брифа — именно этот разбор собирается за 15 минут.

4. Мессенджер

Одна большая идея: у сообщения два независимых обязательства — пережить (источник правды) и долететь (доставка) — и они строго в этом порядке: сначала хранилище, потом шина. Пока сообщение в БД диалога, потеря шины, воркера или коннекта — это задержка, а не потеря. Вторая половина идеи: онлайн-доставка живёт на постоянных соединениях — gateway-кластер, который ничего не считает, только держит коннекты и знает, где кто сидит.

клиент ⇄ gateway (WS, ~500k коннектов/нода) ⇄ Kafka (key=dialog_id) ⇄ delivery-воркеры
             │ registry: user_id → gateway (Redis, TTL+heartbeat)      │
             └ offline: APNs/FCM                          messages store (источник правды, seq per dialog)
Этап Ход решения
1. Требования DAU 50 млн, ~10M одновременно онлайн; 20 сообщений/сутки → 11.5k msg/s avg, ~35k msg/s пик (доставок в 2–3 раза больше — группы); p95 доставки ≤ 500 мс; at-least-once + дедуп на клиенте; строгий порядок внутри диалога, eventual между устройствами; история навсегда; группы до 1000 (каналы-миллионники — минус-объём)
2. Потоки и API Протокол WebSocket + protobuf-фреймы: send(msg, idem_key), серверные deliver/ack, sync(cursor) для офлайн-догонялки; история — REST GET /dialogs/{id}/messages?before_seq=. Коннекты и доставка — data plane; профили, настройки групп — control
3. Схема Gateway → Kafka → delivery-воркеры → registry lookup → push в gateway получателя или push-нотификация офлайн. Проговариваем вслух: «сначала пишу в источник правды — потеря шины не теряет сообщение»
4. Детали Gateway — stateful, но без бизнес-логики: терминирует TLS/WS, heartbeat; registry user_id → gateway_id с TTL (мёртвые коннекты зачищаются сами). Порядок: монотонный seq на диалог назначает хранилище при вставке; ключ партиции Kafka = dialog_id → порядок на всём пути; «строгость нужна только внутри диалога» (глобальный порядок не строим — трейдофф). Гарантии: at-least-once → дедуп по (dialog_id, seq) на клиенте; офлайн — история догонит по sync(cursor). Presence — события в шину → Redis TTL, с троттлингом; группы — fan-out по участникам из соцграфа (тысячи, не миллионы); хранилище write-heavy → LSM, партиции по dialog_id
5. Ресурсы Gateway: 10M коннектов / 500k = 20 нод → с запасом по сценариям ~9×4 ДЦ; шина — тысячи партиций, воркеры горизонтально; storage ~400 ТБ/год текста; латентность считаем хопами: gateway→шина→воркер→gateway ≈ 4 × 0.5 мс внутри ДЦ — в бюджете 500 мс с запасом
6. Эксплуатация Отказ gateway-ноды → 500k reconnect'ов с jitter (иначе шторм), недоставленное ждёт в шине/истории — доставка после переподключения; отказ партиции → реплики, лидер-фейловер, метрика lag per-партиция; перегрузка ×10 → приоритет сообщения > статусы > typing, shedding на presence, rate limit на отправку; мониторинг: end-to-end delivery p95 (от send до deliver), lag, reconnect rate; релизы gateway — drain + canary на одну ноду

Ключевые ходы: «писать в хранилище до шины (надёжность) против после (латентность) — выбираю надёжность, сообщение важнее миллисекунды»; seq в хранилище против внешнего координатора (меньше распределённых сущностей); канал-миллионник — pull по указателю (как селебрити в ленте — общий паттерн «миллионы получателей = pull»); reconnect с jitter — тот же урок, что ретраи в статье 08 §5. Узкое место — не throughput (35k msg/s для шины копейки), а lag и штормы переподключений: система ломается событиями, не потоком. Финал: «сообщение не теряется: источник правды + at-least-once + дедуп; порядок внутри диалога — seq и партиция по dialog_id; офлайн догоняет по курсору; presence деградирует первым».

Глубина: ../classic-designs.md §3 (псевдокод send/delivery по шагам, presence, группы, таблица отказов); Сюй гл. 12 — mailbox-модель WeChat, синхронизация устройств через cur_max_message_id, presence-heartbeat; конспект — ../materials/alex-xu-vol1/ch-12-chat-system.md.

5. Медиа-хостинг (видео)

Одна большая идея: это не сервис «запрос–ответ», а асинхронный конвейер — байты не должны проходить через наш API вообще. Загрузка идёт presigned multipart прямо в объектное хранилище (чанки 5–20 МБ с retry по чанку), а всё дорогое (антивирус, транскодинг, миниатюры) — фоновые воркеры за очередью. Пользователь видит статус uploaded → processing → ready — и это честная eventual-консистентность: минуты обработки — приемлемо, проговариваем.

upload:   клиент → presigned multipart → S3 (исходник) → событие → очередь
transcode: транскодинг-фарм (GOP-сегменты параллельно, ladder рендиций) → S3 (HLS/DASH) → CDN
metadata: RDBMS (статусы, счётчики eventual) ◀— события пайплайна
watch:    клиент → CDN → origin shield → S3; счётчики: heartbeats → очередь → батч-писатель
Этап Ход решения
1. Требования 10k загрузок/сутки × ~1 ГБ → 30–50 ТБ/сутки с рендициями → десятки ПБ/год (только объектное хранилище); 100k просмотров × 5 мин × 3 Mbps → egress ~10 ТБ/сутки, пик ×3–5 → CDN обязателен; старт воспроизведения p95 ≤ 2 с, rebuffer < 1 %; метаданные — строго, готовность рендиций — eventual, минуты
2. Потоки и API POST /videos → запись + presigned multipart URL; POST /videos/{id}/complete (идемпотентен по upload_id); GET /videos/{id} → статус + манифест; отдача — CDN. Загрузка метаданных и загрузка файла — два независимых вызова (развязка путей)
3. Схема Upload → S3 → очередь → ферма транскодинга → S3 (рендиции) → CDN; RDBMS держит статусы; счётчики — отдельный events-путь с батч-писателем
4. Детали Транскодинг: исходник режется на GOP-сегменты → параллельная обработка (часовое видео на десятке нод — минуты); на выходе ladder битрейтов (1080/720/480/360) в HLS/DASH: сегменты 4–10 с + манифест; те же сегменты дают ABR — интеллект на клиенте, сервер только предлагает лестницу; оригинал сразу в cold-класс; идемпотентность воркеров + DLQ; CDN: origin shield (один промах в origin на сегмент), signed URLs против хотлинка, иммутабельные сегменты → большой max-age; счётчики просмотров — heartbeats → очередь → батч (просмотр никогда не трогает RDBMS синхронно)
5. Ресурсы Storage — от retention (считать вслух: «десятки ПБ/год — разговор про холодные ярусы»); egress: offload 90 % → origin видит ~1 ТБ вместо 10; ферма: минуты CPU на минуту видео × 10k/сутки → десятки нод, SLA «ready ≤ 30 мин» определяет размер фермы — очередь сглаживает суточный пик (задержка вместо роста фермы — трейдофф проговорить)
6. Эксплуатация Отказ транскодера → retry на другом + DLQ, деградация = «обрабатывается дольше», потери нет — асинхронность сама по себе механизм отказоустойчивости; перегрузка просмотров ×10 → CDN масштабируется сам, лимитируем origin; перегрузка загрузок → rate limit + приоритеты, очередь — буфер; метрики: старт-тайм p95 и rebuffer ratio (QoE-метрики пользователя), offload %, lag очереди, доля ready < 30 мин; релизы транскодеров — canary с автосравнением качества (VMAF)

Ключевые ходы: «API не проксирует гигабайты» — presigned upload; пайплайн — не одна очередь, а DAG специализированных воркеров (Сюй гл. 14, модель Facebook: нарезка → параллельные ветки видео/звук/миниатюра → сборка); пост «в обработке» сразу против ожидания готовности — свежесть важнее комплектности; стоимость CDN ($0.02/ГБ × 150 ТБ/день ≈ $150k/день) — главный OPEX, популярное в CDN, long tail из origin. Узкое место — не throughput, а консистентность статусов: пользователь смотрит на «обрабатывается», API отдаёт статус из метаданных, CDN — только готовые сегменты. Финал: «отдача — CDN с offload 90 %+; обработка — фоновая, с SLA и метрикой готовности; отказ любого воркера — задержка, не потеря; счётчики не в горячем пути».

Глубина: ../classic-designs.md §4 (полный пайплайн, ABR, таблица отказов, трейдоффы сегмента 4 с против 10 с); Сюй гл. 14 — DAG-модель, развязка путей, арифметика OPEX; конспект — ../materials/alex-xu-vol1/ch-14-youtube.md.

6. Сквозные паттерны: что переносится на любой билет

Четыре эталона пересекаются не случайно — они собраны из одного набора решений. Именно эти девять паттернов и есть «системный дизайн» на секции: незнакомый билет раскладывается на них за пару минут. Сводка — где какой встретили и как он звучит вслух:

Паттерн Где встретили Как звучит
Источник правды один + производные проекции shortener: RDBMS → KV-зеркало; лента: посты → кэш лент; чат: store → шина; медиа: RDBMS-статусы + S3 «Правда — в одном месте; горячее чтение — из read-only копии с известным лагом»
«Не нужно для ответа — из request-path» accessed, счётчики, лимиты (shortener); лайки (лента); доставка событий (чат); view-события (медиа) «Всё, что пользователь не ждёт в ответе, — асинхронно, батчами»
Очередь — изолятор и буфер LAT-actuator (shortener); fan-out (лента); delivery (чат); транскодинг (медиа) «Очередь развязывает этапы, сглаживает пик, метрика — lag; узкое место видно до отказа»
Счёт от дефицитного ресурса TLS → 20k RPS/воркер (shortener); вставки/с fan-out (лента); коннекты/нода (чат); CPU-часы фермы (медиа) «Считаю не серверы, а дефицитный ресурс — от него ноды»
Топология от отказов, не от пика 9×4 ДЦ = 43 сервера (shortener); ~9×4 gateway (чат); canary на самом опасном узле (лента: fan-out) «Запас закладываю сценариями отказов, а не пиковой нагрузкой»
Control plane ≠ data plane короткие ссылки (shortener); профили против лент; коннекты против настроек; загрузка против просмотра «Управление — единицы RPS, горячий путь — сотни тысяч; не смешиваю их»
Ко-локация по доминантному ресурсу KV (память) на воркере (CPU) — localhost вместо сетевого хопа «Данные не шардировать, а реплицировать, и положить рядом с CPU»
Eventual по умолчанию, strict — по требованию новые ссылки строго / модификации лаг (shortener); свой пост сразу / лента ≤ 5 с; порядок в диалоге строго / между устройствами eventual; рендиции — минуты «Строгость покупается там, где она в требованиях; остальное — eventual с числом»
Деградации спроектированы заранее чтение > постинг > счётчики (лента); сообщения > статусы > typing (чат); «обрабатывается дольше» (медиа); «лента стареет» «Чем жертвуем под перегрузкой — решено до инцидента, это фиче-флаги»

Две проверочные связки на память: (1) «миллионы получателей → pull, тысячи → push» — селебрити в ленте, каналы-миллионники в чате, long tail видео из origin — один и тот же трейдофф в трёх декорациях; (2) «байты мимо API» — presigned upload в медиа, CDN для статики в ленте, KV на localhost в shortener: гигабайты не должны протекать через вычислительный слой.

7. Незнакомый билет: карта «задание → эталон»

На реальной секции билет не будет совпадать с эталоном дословно — он будет гибридом. Работает это так: определяем, какая большая идея главная (обычно она одна), берём её скелет, остальные блоки — из других эталонов и раздела 10. Разбор вслух: «ядро — как в ленте; доставку уведомлений возьму из мессенджера; медиа — из видеохостинга» — это звучит как система знаний, а не заученные ответы:

Задание Ядро Дозагрузить из эталонов
Instagram лента (§3) медиапайплайн §5; presence не нужен
Twitter/X лента (§3) акцент на селебрити и запись (лимиты); поиск/тренды — минус-объём или компоненты раздела 10
Мессенджер (WhatsApp/Telegram) мессенджер (§4) медиа-обмен — ссылками на S3/CDN (как в §4)
YouTube/TikTok медиа-хостинг (§5) лента/подписки §3 (pull-часть); рекомендательный скоринг — минус-объём
Файлохранилка (Dropbox) медиа-хостинг без транскодинга (§5) чанки + дедуп + метаданные; синхронизация — события + очередь (§6)
Push-уведомления delivery-контур мессенджера (§4) очередь + rate limit + retry-политика (статья 07, статья 08)
Аукцион/билеты строгие записи: linearizability (раздел 09) burst-очередь, резерв с компенсацией; тренировка — ката Concert Comparison (методичка §6.5)
Google Docs/коллаборация мессенджер (§4) операции/OT против CRDT — назвать трейдофф, не углубляться без запроса

Правило границы: если блок из правой колонки тянет на отдельный трейдофф — называем его одной фразой и помечаем как минус-объём («звонки отмечаю, не детализирую»). Это тот же приём, что на этапе 1: лучше честно сузить, чем утонуть в чужой детали.

8. Как репетировать: эталоны → раунды → мок

Раздел закрывается не чтением, а прогонами. Протокол — ../methodology.md §6 (формат раунда, рубрика 0–3 за этап, порог готовности 13/18); здесь — его свёртка под четыре эталона:

  1. Порядок: shortener → лента → мессенджер → медиа. Shortener — самый механический (тренируем ритм 6 этапов на знакомой идее); лента — главный билет (наш формат секции — «инстаграм/твиттер»), на неё нужно максимум раундов; чат и медиа — по одному-два.
  2. Раунд = 60 минут по протоколу §6.1: доска, голосовая запись, билет «из головы» — эталон до раунда не перечитывать. Спринт 40 минут — те же этапы, детали свёрнуты — если времени мало.
  3. Self-review сразу по рубрике §6.2, затем сверка с ../classic-designs.md и три улучшения в training/.
  4. Контрольное упражнение раздела — из критерия брифа: полный разбор ленты за 15 минут (это спринт-формат ×2 скорости: по 2–3 минуты на этап, числа — только головные: 35k QPS чтения, 700k вставок/с fan-out, микс push/pull, lag как метрика). Если 15-минутный прогон идёт без пауз и заканчивается возвратом к требованиям — раздел готов.
  5. Незнакомый бриф — после эталонов: одна-две каты из методички §6.5 (Concert Comparison — burst и строгие записи; Cheezborger — read-heavy UGC) накануне слота.

9. Ошибки этого раздела

Подмножество топ-10 (../methodology.md §4) + провалы именно сквозных разборов:

Ошибка Как выглядит Противоядие
Блоки без сборки Знает fan-out, кэш, очередь — но не может провести ленту от требований до эксплуатации за 15 минут Тренировать сквозные раунды, не темы; критерий раздела — именно сборка
Большая идея названа поздно Требования собрали, схему нарисовали — и только на деталях всплыло «чтение доминирует» Идея определяется числами этапа 1: посчитал R/W ratio, fan-out, размер — идею называешь сразу
Лента и медиа в одном пути «Посты с видео — в шардированную БД» — гигабайты в транзакционном хранилище «Две системы разной природы»: лента — мелкие операции, медиа — блобы + CDN (§3 этап 5)
Fan-out синхронно Пост вставляется в 300 лент внутри запроса — 700k вставок/с в request-path Очередь + воркеры; узкое место — доставка, метрика lag (§3 этап 4–5)
Селебрити забыли (или наполовину) Решили «не пушим миллионщикам», но не решили горячий ключ его кэша Двусторонняя celebrity-проблема: merge на чтении + реплики горячего ключа (§3)
Чат: шина до хранилища Сообщение ушло в Kafka, потом пишем в БД — сбой между = потеря «Сначала источник правды, потом шина»; сбой = задержка, не потеря (§4)
Транскодинг в запросе / байты через API Загрузка видео через POST-обработчик, рендиции — на лету Presigned upload, конвейер за очередью, статусы eventual (§5)
Эталон заучен, гибкости нет Отвечает коротенером на вопрос про чат; вне сценария — ступор Эталоны = скелет + паттерны §6–7, не сценарий; на секции собираем под требования
Числа посчитаны и брошены Back-of-envelope на этапе 5 не связан с решением Каждое число → вывод → решение: «TLS дефицит → ко-локация», «700k вставок → очередь»
Эксплуатация по остаточному Отказ по каждой ноде «обсудим потом» Таблица отказов — обязательный финал каждого разбора; «эксплуатацию не режем никогда»

10. Что назвать на секции (чек-лист раздела)

По одному «якорю» на эталон — фраза, с которой начинается сильный ответ, плюс обязательные числа. Полный чек-лист серии — методичка §7; канон чисел — KB §2.

Shortener: «Чтение доминирует 50 000:1 → делю на data plane (GET → 302 из KV-зеркала, ко-локация на воркере) и control plane (REST + RDBMS)». Числа: 500k RPS, 20k/воркер (TLS!), 25 воркеров, 43 сервера от отказа ДЦ. Паттерны: majority-коммит вместо 2PC; снимки в разделяемой памяти; «не нужно для ответа — батчами».

Лента: «Узкое место — доставка: 700k вставок/с fan-out → очередь; микс push/pull по порогу селебрити; чтение — кэш post_id-списков». Числа: 35k QPS чтения, 2.3k записи, 300 подписчиков, глубина ~800, eventual ≤ 5 с. Паттерны: snowflake, read-your-writes свой пост, адаптивный fan-out, приоритет «чтение > постинг > счётчики».

Мессенджер: «Сначала источник правды, потом шина: потеря доставки — задержка, не потеря; онлайн — gateway-кластер с registry; порядок — seq per dialog, партиция по dialog_id». Числа: 10M коннектов, 500k/нода → 20 нод, 35k msg/s пик, ≤ 500 мс end-to-end. Паттерны: at-least-once + дедуп, sync(cursor), reconnect с jitter, shedding на presence.

Медиа: «Это конвейер, не запрос: presigned upload в S3, транскодинг за очередью (GOP-параллельно, ladder рендиций, HLS/DASH), отдача — CDN с origin shield; готовность — eventual минуты со статусом». Числа: 30–50 ТБ/сутки storage, egress пик 3–5 Gbps, offload 90 %+, SLA ready ≤ 30 мин. Паттерны: DAG-воркеры, ABR на клиенте, счётчики heartbeat-батчами, деградация «обрабатывается дольше».

На любой билет: большая идея одной фразой до схемы; карта §7 — «ядро такое-то, блоки оттуда-то»; паттерны §6 — как минимум «источник правды + проекция», «не нужно для ответа — асинхронно», «деградации заранее»; финал — возврат к листу требований с метрикой напротив каждого пункта.

11. Самопроверка «умею, если»

Критерий раздела из брифа: собираю полный разбор ленты за 15 минут по фреймворку из 6 этапов. Проверка с закрытыми материалами: (1) лента за 15 минут по таймеру — все 6 этапов, головные числа с формулами, микс push/pull с селебрити, таблица отказов в финале — без возвратов к материалам; (2) каждый из четырёх сервисов — большая идея одной фразой и узкое место одним словом (shortener: чтение 50k:1 / TLS; лента: доставка / fan-out; чат: гарантии и порядок / lag и штормы; медиа: конвейер / статусы и egress); (3) незнакомый билет («спроектируйте X») раскладывается на эталоны по карте §7 за 2 минуты — с явным «ядро + дозагрузка»; (4) паттерны §6 воспроизводятся списком без подсказки — это и есть переносимый капитал раздела. Если 15-минутная лента идёт потоком и заканчивается закрытым листом требований — раздел готов: именно этот навык сдаётся на секции.

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

  • 00-overview.md — обзорная статья по 12 разделам брифа (TASK-45.40); §11 — карта раздела
  • 01-interview-framework.md — каркас 6 этапов с таймингом, кольцо «числа → ресурсы → возврат к требованиям»
  • 02-estimations.md — §5–7: сквозные примеры расчётов shortener и ленты, bandwidth видео
  • 03-scaling.md — §6 типовая схема этапа 3, на которую ложатся все четыре эталона
  • 05-replication-sharding.md — шардирование соцграфа/постов, hot partition селебрити
  • 06-caching.md — кэш лент, stampede, CDN как уровень кэша
  • ../brief.md — бриф: раздел 11 с критерием «умею, если»
  • ../classic-designs.mdполные эталоны (эта статья — ход решения, там — детали): §1 shortener (эталон Яндекса), §2 лента, §3 мессенджер, §4 медиа-хостинг; сверки с Alex Xu и DDIA
  • ../knowledge-base.md — §2 back-of-envelope с примерами всех четырёх сервисов, §11 шпаргалка «что назвать»
  • ../methodology.md — §6 протокол тренировок (рубрика 0–3, порог 13/18, каты §6.5), §7 карточка на секцию
  • ../materials/yandex-564132.md — источник эталона shortener (статья Яндекса)
  • ../materials/alex-xu-vol1/ch-08-url-shortener.md · ch-11-news-feed.md · ch-12-chat-system.md · ch-14-youtube.md — сверки эталонов с книгой
  • Соседние статьи: 04-data-models-storage.md (выбор хранилищ для каждого эталона) · 07-queues-streams.md (очереди fan-out и delivery) · 08-fault-tolerance.md (таблица отказов — финал каждого разбора) · 09-consistency.md (eventual против strict в каждом эталоне) · 10-components-patterns.md (snowflake, rate limiter, WebSocket) · 12-operations-observability.md (QoE-метрики, canary)