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

Справочник: числа, формулы, матрицы выбора#

Всё, к чему обращаются во время проектирования, в одном месте. Подробности — в карточках по ссылкам.

Оглавление#

Числа и порядки · Формулы оценки · Доступность · Выбор хранилища · Выбор стиля API · Очередь или лог · Стратегии кэша · Уровни изоляции · Модели согласованности · Гарантии доставки · Стратегии выкатки · Аварийное восстановление · Коды ответа и повторы · Что мерить


Числа и порядки#

Задержки (PERF-01)

Операция Порядок
Кэш процессора наносекунды
Оперативная память ~100 нс
Чтение с SSD ~100 мкс
Обмен внутри дата-центра ~0.5 мс
Чтение с жёсткого диска ~10 мс
Обмен между континентами 100–200 мс

Ёмкость одного узла — грубые ориентиры для проверки правдоподобия, не обещания:

Компонент Порядок
Реляционная БД, простые транзакции тысячи в секунду
Хранилище в памяти (Redis) сотни тысяч операций в секунду
Приложение, лёгкий запрос тысячи запросов в секунду
Kafka, один брокер сотни тысяч сообщений в секунду
Сеть 10 Гбит/с ~1.2 ГБ/с

Полезные величины

Величина Значение
Секунд в сутках 86 400
Секунд в месяце (30 дней) 2.6 млн
1 млн запросов в сутки ≈ 12 в секунду
1 млрд запросов в сутки ≈ 11 600 в секунду
2¹⁰ / 2²⁰ / 2³⁰ / 2⁴⁰ тысяча / миллион / миллиард / триллион (приблизительно)
Символ UTF-8 (латиница / кириллица) 1 / 2 байта
UUID 16 байт (36 символов в текстовой записи)

Карточки: PERF-01 числа задержек · PERF-02 перцентили · NET-01 как работает интернет · PERF-03 Big-O и структуры данных

Формулы оценки#

Шаг W1.

средний RPS      = действий в сутки / 86 400
пиковый RPS      = средний × коэффициент пика        (3–10, событийные — до 100)
объём за период  = записей в сутки × размер записи × дни × коэффициент (2–3 на индексы и репликацию)
исходящий трафик = RPS × размер ответа
бюджет задержки  = Σ участков + запас                (сумма < цели)
число обработчиков = темп × время обработки          (закон Литтла)
время ожидания   ∝ ρ / (1 − ρ)                       (ρ — загрузка; при 0.9 — ×9)

Правила.

  • считать в порядках;
  • умножать на количество: дешёвая операция × 1000 может обойтись дороже одной дорогой;
  • параллельные участки складываются максимумом, последовательные — суммой;
  • целевая загрузка ресурса — 60–70 %, не 100 % (PERF-07).

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

Уровень Простой в месяц Простой в год Чем обычно достигается
99 % 7.2 часа 3.65 суток Одна машина, ручное восстановление
99.9 % 43 минуты 8.8 часа Резервирование в одной зоне
99.95 % 22 минуты 4.4 часа Несколько зон доступности
99.99 % 4.3 минуты 53 минуты Автоматическое переключение, multi-AZ
99.999 % 26 секунд 5.3 минуты Несколько регионов, active-active

Цепочка последовательных зависимостей перемножается: пять сервисов по 99.9 % дают 99.5 %, если нет деградации (ARCH-01).

Карточки: REL-06 обзор отказоустойчивости · REL-08 multi-region · REL-07 ячеистая архитектура · OPS-09 SLO и бюджет ошибок

Выбор хранилища#

Подробно — DATA-01, DATA-02.

Профиль Класс Примеры
Связи, транзакции, гибкие запросы Реляционная PostgreSQL, MySQL
Агрегат читается и пишется целиком Документная MongoDB
Огромный поток записи, запрос по известному ключу Wide-column Cassandra, ScyllaDB
Минимальная задержка, простые операции Key-value (KV) Redis, DynamoDB
Полнотекстовый и фасетный поиск Поисковая Elasticsearch, OpenSearch
Агрегации по миллиардам строк Колоночная ClickHouse, BigQuery
Метрики по времени Time-series Prometheus, VictoriaMetrics
Обход графа глубже 3 уровней Графовая Neo4j
Поиск по близости эмбеддингов Векторная pgvector, Qdrant
Файлы и медиа Объектная S3, GCS, MinIO

Правило. Реляционная БД — умолчание; отклонение требует довода в виде числа или формы данных. Второе хранилище стоит дороже, чем кажется при выборе: бэкапы, мониторинг, обновления, экспертиза, дежурство.

Выбор стиля API#

Подробно — NET-08.

Стиль Когда Слабое место
REST Публичный API, ресурсная модель, кэшируемые чтения Избыточные и недостаточные выборки
gRPC Внутренние вызовы, строгий контракт, стриминг Не из браузера напрямую, бинарная отладка
GraphQL Много разных клиентов Кэширование, N+1, ограничение сложности
SSE Односторонний поток к клиенту Только текст, только от сервера
WebSocket Двусторонний обмен в реальном времени Состояние на сервере, масштабирование
Webhook Уведомление внешней системы Зависимость от чужой доступности
Обмен сообщениями Развязка сервисов во времени Отложенная согласованность

Карточки: NET-08 стили API · NET-12 realtime-транспорт · NET-10 gRPC · NET-11 GraphQL · MSG-10 webhooks

Очередь или лог#

Подробно — MSG-02, MSG-05.

Признак задачи Очередь (RabbitMQ, SQS) Лог (Kafka, Pulsar)
Задача одному исполнителю ✅ —
Событие нескольким подписчикам — ✅
Перечитать историю — ✅
Сложная маршрутизация, приоритеты ✅ —
Порядок по ключу — ✅ (в партиции)
Отложенная доставка, точечный повтор ✅ сложнее
Поток в сотни тысяч сообщений в секунду — ✅

До сотен сообщений в секунду с одним потребителем таблица-очередь в имеющейся БД (SELECT … FOR UPDATE SKIP LOCKED) обычно лучше любого брокера. Постановка задачи происходит в одной транзакции с изменением данных.

Стратегии кэша#

Подробно — CACHE-02, CACHE-03.

Стратегия Чтение Запись При падении кэша
Cache-aside Приложение читает БД при промахе Приложение удаляет ключ Нагрузка на БД, данные целы
Read-through Кэш сам грузит — Как выше
Write-through — Синхронно в кэш и БД Данные целы, запись медленнее
Write-behind — В кэш, в БД асинхронно Потеря данных
Write-around — Мимо кэша в БД Данные целы, первое чтение промах

Инвалидация.

  • по времени: просто, надёжно;
  • по событию из журнала БД: свежо, нужен TTL как страховка;
  • версионированием ключа (user:42:v17): гонок нет вовсе.

Уровни изоляции и аномалии#

Подробно — DATA-08.

Аномалия Что происходит Предотвращается с
Грязное чтение Видны незафиксированные изменения Read Committed
Неповторяемое чтение Повторное чтение строки даёт другое Repeatable Read / Snapshot
Фантомы Повторный запрос по условию даёт новые строки Repeatable Read (в ряде СУБД) / Serializable
Потерянное обновление Два «прочитал–изменил–записал» затирают друг друга Repeatable Read с обнаружением, SELECT FOR UPDATE, атомарный UPDATE
Write skew Каждая транзакция корректна, вместе нарушают инвариант Только Serializable

Одинаковые названия уровней в разных СУБД означают разные гарантии. В PostgreSQL repeatable read — это snapshot isolation и не защищает от write skew.

Как защищаться.

  • инкремент → атомарный UPDATE;
  • обновление по прочитанному → версия строки и WHERE version = ?;
  • инвариант между строками → SERIALIZABLE;
  • уникальность → уникальный индекс, самое дешёвое и надёжное.

Модели согласованности#

Подробно — DIST-03.

Модель Что гарантирует Цена Типичное применение
Линеаризуемость Как одна копия данных Кворум или лидер на каждое чтение Деньги, уникальность, блокировки
Причинная Причинно связанное видно по порядку Средняя Комментарии, сообщения
Read-your-writes Своя запись видна сразу Низкая Профиль, настройки
Monotonic reads Не «уезжает» в прошлое Низкая Любой список
Eventual Когда-нибудь сойдётся Минимальная Счётчики, рекомендации

CAP. При разрыве сети — выбор между согласованностью и ответом. PACELC. Без разрыва — между задержкой и свежестью. Выбор делается для операции, а не для системы.

Гарантии доставки#

Подробно — MSG-06.

Гарантия Как достигается Потери Дубликаты
At-most-once Подтверждать до обработки Есть Нет
At-least-once Подтверждать после обработки Нет Есть
Effectively-once At-least-once + идемпотентный потребитель Нет Нет по эффекту

«Exactly-once» между независимыми системами недостижим. Практический рецепт: устойчивый идентификатор события + запись отметки об обработке в той же транзакции, что и бизнес-эффект.

Стратегии выкатки#

Подробно — OPS-02.

Стратегия Ресурсы Скорость отката Раннее обнаружение
Rolling ×1 Медленно Нет
Blue-green ×2 Мгновенно (код, но не данные) Нет
Canary ×1 + запас Быстро Да
Фича-флаг ×1 Мгновенно Да

Схема должна быть совместима в обе стороны: во время выкатки работают обе версии (DATA-17).

Аварийное восстановление#

Подробно — REL-09, REL-08.

Стратегия RPO RTO Стоимость
Бэкап и восстановление Часы Часы Минимальная
Pilot light (минимальная копия) Минуты Десятки минут Низкая
Warm standby (тёплый резерв) Минуты Минуты Средняя
Active-active Секунды Секунды Высокая

Репликация защищает от отказа узла, не от логической ошибки: удаление таблицы реплицируется мгновенно. Бэкап, из которого ни разу не восстанавливались, — ещё не бэкап.

Коды ответа и повторы#

Подробно — NET-05, REL-01.

Код Смысл Повторять
400, 422 Неверный запрос Нет
401 / 403 Не аутентифицирован / нет прав Нет (после обновления токена — да)
404 Нет ресурса Нет
409 Конфликт состояния Нет, разрешить конфликт
429 Слишком часто Да, по Retry-After
500 Ошибка сервера Да, если операция идемпотентна
502 / 504 Проблема на пути Да
503 Временно недоступен Да, по Retry-After

Формула задержки. delay = random(0, min(cap, base × 2^attempt)) — экспонента с full jitter. Плюс бюджет повторов (не более ~10 % трафика) и повторы только на одном уровне цепочки.

Карточки: REL-01 таймауты и повторы · NET-05 коды состояния · EDGE-06 rate limiting · REL-03 load shedding

Что мерить: минимальный набор#

Уровень Показатели
Сервис Частота запросов, доля ошибок, распределение времени ответа (RED)
Ресурс Утилизация, насыщение, ошибки (USE)
Очередь Глубина, лаг во времени, возраст самого старого сообщения
БД Длительность транзакций, дедлоки, лаг репликации, доля Seq Scan
Кэш Hit ratio, вытеснения, возраст отдаваемых данных
Доставка Частота выкаток, время до прода, доля откатов, время восстановления
Деньги Стоимость на 1000 запросов, на пользователя, на ГБ хранения

Перцентили, а не средние. Гистограммы, а не готовые перцентили — их нельзя усреднять между узлами (PERF-02).


Чек-лист design review — в 00-workflow.md, шаг W11. Типовые ошибки — в 91-antipatterns.md.