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

E-02 · Лента новостей — вход#

Этап прогона: прогон завершён · правки исполнены 2026-09-17 · вход зафиксирован 2026-09-16 Кейс: CASE-02 лента новостей Шаги: W0 · Рамки и требования и W1 · Оценки на салфетке

Зачем второй прогон. Четырнадцать правок по итогам E-01 сделаны по одному кейсу. Пока они не проверены на непохожем, набор растёт на непроверенном основании.

Кейс выбран противоположным по всем осям, которые документы используют — и это касается не только предметной области.

Система вымышлена, но внутренне непротиворечива. Числа не взяты у реальной компании; они выбраны так, чтобы арифметика сходилась и решения принимались на них по-настоящему. Пометки: [замер] — измерено на работающей системе, [расчёт] — выведено арифметически, [продукт] — задано продуктом, [орг] — из состава команд и инфраструктуры.

Чем E-02 противоположен E-01#

E-01 · Бронирование E-02 · Лента
Стадия проекта Гринфилд — фактов нет, предсказываем Работающая система два года — факты измеряются
Дефицитный ресурс Место: продать дважды нельзя Нет вовсе
Согласованность Атомарность обязательна, местами недостижима Итоговая по построению, отставание 10 с допустимо
Объём 130 ГБ за пять лет — ничтожен Сотни гигабайт в памяти, терабайты на диске
Нагрузка Пик ×1000 полчаса в неделю Ровная, пик ×10, круглосуточно
Команда Четыре разработчика, платформенной нет Три команды, платформенная есть
Наблюдаемость Нет — система не запущена Есть: метрики, трассировка, автовыкат
Что решает исход Конкуренция за строку Соотношение чтений к записям и неравномерность подписок

Стадия — главное отличие. E-01 породил D-05 · Границы на старте — решение там принималось по D-02 v2.1, а отдельный документ выделился уже по итогам прогона, так что применением D-05 E-01 не был. E-02 проверит D-02 · Границы в работающей системе — вторую половину разделения, сделанного на этапе 6. Заодно проверится сама позиция: действительно ли это разные решения, а не один документ с ветками.

Почти все дисквалификаторы, сработавшие в E-01, здесь не сработают. Это и нужно: документ, который на одном кейсе всё отсекает, а на другом ничего, — проверен вдвое лучше, чем документ, испытанный дважды в одинаковых условиях.


План прогона#

Этап Что делаем Документ Статус
1 Вход: рамки, числа, инварианты W0, W1 ✅ этот файл
2 Выбор хранилища под ленты D-01 v1.1 → ADR-0001 ✅
3 Границы работающей системы D-02 v3.0 → ADR-0002 ✅
4 Связь в процессе раздачи поста D-04 v2.0 → ADR-0003 ✅
5 Кэш и стратегия чтения ленты D-03 v2.0 → ADR-0004 ✅
6 Ревизия: подтвердились ли правки 98-revision-plan.md ✅ 20 находок в правки, пять документов в MAJOR

Нумерация ADR начинается заново: это другой проект, а не продолжение первого.

1. Что имеем#

Социальная сеть работает два года. Лента обратно хронологическая, собирается при чтении: открыл — сходили за постами всех подписок, слили, отдали. Схема работала до полумиллиона активных пользователей и с тех пор деградирует.

Симптом, из-за которого всё началось: p99 открытия ленты вырос со 180 мс до 900 мс за полгода [замер]. Цель по продукту — 200 мс.

Вне рамок: ранжирование ленты (только хронология), рекомендации, медиафайлы (лежат в объектном хранилище, ссылками), личные сообщения, реклама.

2. Инварианты#

Их меньше, чем в E-01, и все мягче — атомарности не требуется нигде.

№ Инвариант Чем грозит нарушение
И1 Пользователь видит собственный пост немедленно, не дожидаясь раздачи Выглядит как потеря поста; пользователь публикует второй раз
И2 Удалённый пост не показывается ни в одной ленте Юридический риск и жалобы
И3 Пост не появляется в ленте дважды Видно сразу, выглядит как поломка

Отставание до 10 секунд допустимо [продукт] — это не недоработка, а сознательная уступка, и именно она открывает целый класс архитектур. В E-01 сопоставимой уступки не было: там место либо ваше, либо нет.

3. Профиль нагрузки#

Показатель Значение Откуда
Активных пользователей в сутки 10 млн [замер]
Открытий ленты на пользователя в сутки 10 [замер]
Чтений ленты ≈ 1 200/с средн., 12 000/с в пике [расчёт]: 100 млн ÷ 86 400, пик ×10
Публикаций ≈ 12/с [замер]
Соотношение чтений к записям 100 : 1 [расчёт]
Подписок на пользователя медиана 120, среднее 300 [замер] — распределение с тяжёлым хвостом
Аккаунтов с аудиторией свыше миллиона ~500 [замер]
Максимальная аудитория 10 млн подписчиков [замер]

Почему нынешняя схема не тянет. Сборка при чтении означает обращение к постам всех подписок на каждое открытие: 1 200 × 300 = 347 тысяч обращений в секунду в среднем и 3,5 миллиона в пике [расчёт]. Кэш по авторам гасит часть, но растёт вместе с аудиторией, и запас кончился.

Неравномерность — вторая, независимая проблема. Одна публикация аккаунта с 10 млн подписчиков при раздаче на запись даёт 10 млн вставок. При устойчивом темпе 18 тысяч вставок в секунду это девять минут работы [расчёт], в течение которых обычные посты стоят в очереди. Любая симметричная схема ломается об этот хвост.

4. Объём данных#

Что Размер Откуда
Пост (текст и метаданные, без медиа) ~1 КБ [замер]
Посты 1 ГБ/сут, 374 ГБ/год, 0,7 ТБ накоплено [расчёт]
Медиа В объектном хранилище, вне рамок [продукт]
Лента в памяти при раздаче на запись 10 млн × 1 000 идентификаторов × 16 Б = 160 ГБ, с накладными ≈ 320 ГБ [расчёт]
Граф подписок ~3 млрд рёбер, 48 ГБ [расчёт]: 10 млн × 300

Здесь объём решает. В E-01 он был ничтожен и ни на что не влиял; здесь 320 ГБ в оперативной памяти — это статья расходов, сопоставимая со всем остальным, и ось «стоимость владения на единицу нагрузки» впервые заполняется не пометкой [нет данных].

5. Бюджет задержки#

Цель p99 открытия ленты — 200 мс [продукт]. Сейчас 900 мс [замер].

Участок Сейчас [замер] Целевой
Сеть до площадки и обратно 40 мс 40 мс
Периметр 10 мс 10 мс
Сборка ленты 780 мс 90 мс
Досбор постов и сериализация 70 мс 60 мс
Итого 900 мс 200 мс

Весь перерасход — в одном участке, и он измерен трассировкой, а не угадан. Публикация поста: p99 500 мс [продукт], сейчас 220 мс — запас есть.

6. Доступность#

Что Цель Обоснование
Чтение ленты 99,95 % Основной сценарий; недоступность видна всем
Публикация 99,9 % Пользователь повторит через минуту
Свежесть ленты Отставание до 10 с Уступка, открывающая асинхронный путь

Доступность равномерна во времени — прямая противоположность E-01, где полчаса в неделю стоили дороже остальных 167 часов. Здесь нет момента, который нельзя пропустить, и это меняет то, как читаются все последующие решения.

7. Ограничения, не относящиеся к технике#

Почти все — противоположны E-01, и это главная ценность второго кейса.

  • Команды: три — лента, посты, платформа. По 5–7 человек. Платформенная команда есть, дежурство выделенное [орг].
  • Наблюдаемость: метрики за год, сквозная трассировка за три месяца, автоматический выкат [орг].
  • В эксплуатации уже есть: PostgreSQL, Redis, Kafka, Kubernetes. Опыт эксплуатации у платформенной команды [орг].
  • Размещение: один провайдер, три зоны доступности, во втором регионе реплика только на чтение [орг].
  • История доступна: репозиторий два года, трекер — 1 400 задач за последние полгода, схема данных, метрики [орг].

8. Что осталось неизвестным#

Неизвестно Чем закроется
Распределение подписок по перцентилям, не только медиана и среднее Запрос к графу подписок — час работы
Доля открытий ленты, где пользователь уходит дальше первой страницы Есть в метриках, не выгружали
Стоимость гигабайта памяти против гигабайта диска у нашего провайдера Тариф; нужен для оси стоимости владения
Фактическое время раздачи поста по подписчикам Трассировка есть, замер не делали

Дальше: этап 2 — D-01 v1.1 · Выбор хранилища, результат в ADR-0001.