Как рассуждать о RPS в System Design

RPS (requests per second) показывает, сколько запросов система должна принять и обработать за секунду.

Но сам по себе RPS почти ничего не решает. 1 000 лёгких GET из Redis и 1 000 запросов, каждый из которых делает пять SQL-запросов, вызывает внешний API и генерирует PDF, — это совершенно разные нагрузки.

От чего зависит допустимый RPS

1. Стоимость одного запроса

Что выполняется внутри запроса:

  • только чтение из памяти;
  • чтение из Redis;
  • простой SELECT по индексу;
  • тяжёлый JOIN;
  • запись в базу;
  • транзакция с блокировками;
  • обращение к нескольким микросервисам;
  • загрузка файла;
  • шифрование, компрессия, генерация отчёта.

Чем дороже один запрос, тем меньше RPS выдержит один экземпляр сервиса.

2. Время обработки запроса

Есть полезная связь:

Количество одновременно выполняющихся запросов ≈ RPS × среднее время запроса

Например:

RPS = 1 000
средняя длительность запроса = 200 мс = 0,2 секунды

concurrency ≈ 1 000 × 0,2 = 200

То есть в каждый момент система обслуживает примерно 200 параллельных запросов.

Если длительность запроса увеличилась до двух секунд:

1 000 × 2 = 2 000 параллельных запросов

RPS остался прежним, но системе уже нужны тысячи соединений, потоков или асинхронных операций.

3. Соотношение чтения и записи

Например:

10 000 RPS:
9 900 чтений
100 записей

Это может быть достаточно простая система с кешем и read replicas.

Но:

10 000 RPS:
5 000 чтений
5 000 записей

Это уже совершенно другая архитектура. Появляются:

  • конкуренция за строки;
  • блокировки;
  • рост журнала транзакций;
  • нагрузка на диски;
  • репликационный лаг;
  • необходимость шардирования или партиционирования;
  • сложность обеспечения консистентности.

4. Размер запроса и ответа

Нужно считать не только RPS, но и трафик.

Например:

10 000 RPS × 1 КБ = примерно 10 МБ/с

Но:

10 000 RPS × 1 МБ = примерно 10 ГБ/с

Одинаковый RPS, но радикально разная нагрузка на сеть, балансировщики и сервисы.

5. Равномерность нагрузки

Средний RPS может быть обманчив.

Средний RPS: 1 000
Пиковый RPS: 15 000

Например, при открытии продаж билетов почти вся суточная нагрузка может прийти за несколько минут.

Поэтому спрашивают:

  • какой средний RPS;
  • какой пиковый RPS;
  • как долго длится пик;
  • насколько быстро он возникает;
  • допустимо ли отклонять запросы;
  • можно ли поставить операции в очередь.

6. Требуемая задержка

Система может выдерживать 20 000 RPS, но отвечать по десять секунд. Формально throughput высокий, пользовательски система мертва.

Поэтому RPS всегда рассматривается вместе с:

  • средней latency;
  • p95;
  • p99;
  • timeout;
  • error rate.

Например:

10 000 RPS
p95 < 200 мс
p99 < 500 мс
ошибки < 0,1%

Это уже настоящее требование.

Какие решения принимаются в зависимости от RPS

Ниже не абсолютные пороги. Это ориентиры, потому что реальная граница зависит от стоимости запроса, базы, языка, железа, индексов и SLA.

До десятков RPS

Например:

1–50 RPS

Обычно достаточно:

  • одного приложения;
  • одной основной базы данных;
  • обычного connection pool;
  • вертикального масштабирования;
  • простых индексов;
  • резервного копирования.

Но один экземпляр приложения всё равно создаёт single point of failure. Поэтому даже при маленьком RPS для production могут поставить минимум два экземпляра.

Здесь архитектура определяется скорее требованиями доступности, чем пропускной способностью.

Сотни RPS

Например:

100–1 000 RPS

Часто появляются:

  • load balancer;
  • несколько stateless-инстансов приложения;
  • connection pool;
  • Redis для горячих данных;
  • CDN для статики;
  • базовые метрики и tracing;
  • rate limiting;
  • индексы и оптимизация запросов;
  • read replica, если много чтения.

Пример расчёта:

Один инстанс устойчиво выдерживает 250 RPS.
Нужно выдерживать 800 RPS.

800 / 250 = 3,2

Минимум четыре инстанса. Но с резервом:

4 × 0,7 = эффективная безопасная ёмкость около 700 RPS

Значит, скорее понадобится пять или шесть инстансов, чтобы:

  • пережить потерю одного;
  • не работать постоянно на 100% CPU;
  • выдерживать небольшие пики.

Тысячи RPS

Например:

1 000–10 000 RPS

Здесь уже тщательно рассматривают каждый слой.

Приложение

  • горизонтальное масштабирование;
  • stateless-сервисы;
  • autoscaling;
  • асинхронный ввод-вывод там, где много ожидания;
  • ограничение concurrency;
  • circuit breaker;
  • timeouts;
  • bulkheads.

База

  • индексы;
  • устранение N+1;
  • read replicas;
  • партиционирование таблиц;
  • ограничение числа соединений;
  • PgBouncer или другой connection proxy;
  • кеширование;
  • разделение чтений и записей.

Особенно важен connection pool. Например:

100 инстансов приложения × 50 соединений
= 5 000 соединений к PostgreSQL

База может умереть не от количества SQL-запросов, а от количества соединений.

Асинхронность

Не всё обязательно выполнять внутри HTTP-запроса.

Например:

POST /booking

Синхронно:

  • проверить запрос;
  • создать бронь;
  • зафиксировать критическое состояние.

Асинхронно:

  • отправить email;
  • записать аналитику;
  • обновить поисковый индекс;
  • отправить push;
  • сформировать документ.

Для этого появляются Kafka, RabbitMQ, SQS или другие очереди.

Десятки тысяч RPS

Например:

10 000–100 000 RPS

На этом масштабе один монолит всё ещё теоретически может работать. Сам RPS не доказывает необходимость микросервисов. Но начинают появляться физические ограничения отдельных компонентов.

Типовые решения:

  • агрессивное кеширование;
  • CDN и edge caching;
  • распределение нагрузки по регионам;
  • несколько кластеров приложения;
  • partitioning;
  • database sharding;
  • отдельные хранилища для разных паттернов доступа;
  • Kafka для потока событий;
  • batch processing;
  • materialized views;
  • precomputation;
  • денормализация;
  • изоляция горячих путей;
  • rate limiting по пользователям и клиентам;
  • graceful degradation.

Например, карточка отеля может собираться из десяти источников. При 50 000 RPS нельзя каждый раз синхронно ходить во все десять систем.

Вместо этого делают:

источники данных
    ↓
события изменения
    ↓
предварительно собранное представление
    ↓
Redis / document store / search index
    ↓
быстрый GET

То есть меняется не только количество серверов. Меняется сам путь обработки запроса.

Сотни тысяч и миллионы RPS

На этом уровне обычно возникают:

  • географически распределённая архитектура;
  • global load balancing;
  • региональные кластеры;
  • локальные кеши;
  • eventual consistency между регионами;
  • шардирование;
  • многоуровневый кеш;
  • защита от cache stampede;
  • специализированные хранилища;
  • потоковая обработка;
  • ограничение функциональности при перегрузке;
  • admission control;
  • управление backpressure;
  • capacity planning как постоянный процесс.

Но важно не произносить на интервью:

«Миллион RPS, значит Kafka, Cassandra и микросервисы».

Это превращение числа в ритуал. Сначала надо выяснить, какие именно запросы составляют этот миллион.

Например:

950 000 RPS — получение статического изображения через CDN
49 000 RPS — чтение каталога из кеша
1 000 RPS — реальные обращения к основной базе

Основная система может видеть только небольшую часть общего трафика.

Какие вопросы задавать интервьюеру

Когда дают RPS, стоит сразу разложить число:

  1. Это средний или пиковый RPS?
  2. Каков коэффициент пика?
  3. Какова доля чтений и записей?
  4. Какие типы запросов входят в это число?
  5. Какой размер request и response?
  6. Какая требуемая latency, включая p95 и p99?
  7. Есть ли резкие всплески?
  8. Допустимо ли ставить операции в очередь?
  9. Какие операции требуют строгой консистентности?
  10. Каков ожидаемый рост нагрузки?
  11. Нагрузка глобальная или сосредоточена в одном регионе?
  12. Сколько уникальных ключей участвует в запросах?
  13. Есть ли горячие сущности, на которые приходит непропорционально много запросов?

Последний вопрос особенно важен.

10 000 записей в секунду в 10 000 разных записей

и

10 000 записей в секунду в одну и ту же запись

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

Быстрый алгоритм принятия решений

Шаг 1. Разделить запросы по типам

Например:

Search:          5 000 RPS
Hotel details:   2 000 RPS
Create booking:    200 RPS
Cancel booking:     20 RPS
Payment:            50 RPS

Не надо проектировать все запросы одинаково.

Шаг 2. Посчитать трафик

Traffic = RPS × average payload size

Шаг 3. Оценить concurrency

Concurrency = RPS × latency in seconds

Шаг 4. Оценить ёмкость одного инстанса

Это нельзя достоверно вывести только из теории. Нужны:

  • benchmark;
  • load test;
  • production metrics;
  • запас по CPU и памяти.

Расчёт:

Количество инстансов =
Peak RPS / safe RPS per instance

Безопасная производительность инстанса обычно берётся не на пределе, а при допустимом использовании ресурсов и latency.

Шаг 5. Найти реальный bottleneck

Им может оказаться:

  • CPU;
  • память;
  • garbage collection;
  • network bandwidth;
  • connection pool;
  • база данных;
  • блокировки;
  • диск;
  • внешний API;
  • очередь;
  • один горячий ключ;
  • лимит файловых дескрипторов;
  • TLS handshake.

Шаг 6. Выбирать решение против конкретного ограничения

Ограничение Возможное решение
Не хватает CPU приложения Больше инстансов, оптимизация вычислений
Много одинаковых чтений Redis, local cache, CDN
База не выдерживает чтения Read replicas, cache, denormalized views
База не выдерживает записи Partitioning, sharding, batching
Долгие фоновые операции Очередь и workers
Резкие пики Queue, autoscaling, rate limiting
Горячий ключ Распределение ключа, сериализация операций, отдельный агрегатор
Много соединений к базе Connection proxy, уменьшение pool
Медленный внешний сервис Timeout, circuit breaker, async processing
Перегрузка каскадом Backpressure, bulkhead, load shedding

Главный вывод для System Design

RPS определяет не готовое архитектурное решение, а масштаб давления на каждый участок системы.

Правильное рассуждение:

У нас такой-то peak RPS. Из него столько-то чтений и столько-то записей. При такой latency получаем такую-то параллельность. Основная нагрузка приходится на такой-то компонент. Поэтому сначала применяем такое решение. Если один узел перестаёт выдерживать нагрузку, вводим следующий уровень масштабирования.

Неправильное рассуждение:

Высокий RPS, поэтому нужны микросервисы, Kafka, NoSQL и Kubernetes.

RPS не выбирает технологию напрямую. Он помогает обнаружить, где последовательная или централизованная часть системы перестанет пропускать требуемый поток.

Прокрутить вверх