АрхитектураПроектирование системИнженер по проектированию распределённых систем

Команда оценивает систему только по числу запросов в секунду. Как перевести эту оценку в нагрузку на хранил...

Команда оценивает систему только по числу запросов в секунду. Как перевести эту оценку в нагрузку на хранилище?

Проходите собеседования с ИИ помощником Hintsage

Краткий ответ

Нужно разложить пользовательский RPS по типам операций и построить цепочку обработки каждого запроса: какие обращения к хранилищу он порождает, сколько раз они выполняются и какая доля запросов попадает в кэш. Нагрузка на хранилище — это не просто входной RPS, а сумма операций чтения и записи с учётом fan-out, повторов, пакетирования и коэффициента попадания в кэш.

Например, если 1 000 запросов в секунду вызывают в среднем по 4 чтения, а кэш обслуживает 75% этих чтений, хранилище получает примерно 1 000 операций чтения в секунду, а не 4 000.

Исторический контекст

По мере перехода от монолитных приложений к распределённым системам одного показателя входного трафика стало недостаточно. Один внешний запрос может обращаться к нескольким сервисам, выполнять несколько запросов к базе или порождать асинхронные записи.

Поэтому оценку нагрузки стали связывать не только с пользовательскими запросами, но и с конкретными ресурсами: базой данных, кэшем, очередью, диском и сетью. Такой подход помогает планировать ёмкость по реальному узкому месту.

Постановка проблемы

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

Если считать только входной RPS, можно недооценить нагрузку на хранилище, неправильно выбрать размер пула соединений или обнаружить перегрузку только после запуска. Особенно опасны скрытые множители: fan-out, повторные запросы после тайм-аутов, промахи кэша и операции, выполняемые для каждого элемента списка.

Подробное решение

Сначала трафик делят на классы: например, чтение карточки, поиск, создание заказа и фоновая обработка. Для каждого класса фиксируют долю общего трафика и отдельно оценивают чтения, записи и дополнительные обращения к хранилищу.

Для класса запросов можно использовать расчёт:

нагрузка на хранилище = входной RPS × доля класса × среднее число операций на запрос × доля операций, не обслуженных кэшем.

Для записей коэффициент попадания в кэш обычно не применяется, поэтому их считают отдельно. Если один запрос читает список из 20 элементов и для каждого элемента выполняет отдельное обращение, возникает fan-out: среднее число операций может быть значительно больше единицы. При пакетной загрузке тот же объём данных может обслуживаться меньшим числом операций, хотя каждая операция станет тяжелее.

Расчёт нужно выполнять не только для среднего значения, но и для целевого пика. В модель включают долю повторов, ретраи, фоновые задачи, периодические джобы и запас по ёмкости. Ретраи особенно опасны: при перегрузке они увеличивают нагрузку и могут усилить исходную проблему.

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

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

Ситуация из практики

Сервис каталога получает 2 000 запросов в секунду. Команда сначала оценила нагрузку на базу как 2 000 чтений в секунду и выбрала конфигурацию с небольшим запасом.

При разборе пути запроса выяснилось, что 60% трафика приходится на выдачу списка. Каждый такой запрос читал страницу товаров, затем отдельными обращениями загружал характеристики и остатки. Среднее число обращений к хранилищу составляло 8, а кэш обслуживал только половину запросов на характеристики.

Рассматривались варианты: увеличить базу, добавить больше реплик или уменьшить число обращений. Увеличение базы быстро повышало стоимость и не устраняло fan-out. Реплики снижали давление на основную базу для чтений, но не решали проблему лишних запросов и могли увеличить задержку из-за синхронизации.

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

Что кандидаты часто упускают

  1. Нужно ли считать только среднее число операций на один запрос?

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

  1. Как учитывать кэш в расчёте нагрузки?

Нужно учитывать не только средний hit rate, но и его изменение во времени и по ключам. Например, истечение большой группы записей, прогрев после перезапуска или горячие ключи могут временно увеличить промахи и создать всплеск нагрузки. Поэтому для планирования берут консервативный hit rate и отдельно проверяют сценарии холодного кэша.

  1. Почему увеличение числа реплик не всегда пропорционально увеличивает доступную нагрузку?

Реплики могут разгрузить чтения, но не устраняют записи, репликацию, сетевой обмен и ограничения балансировки. Кроме того, не каждый запрос можно безопасно направить на реплику: для некоторых операций требуется актуальное состояние, а задержка репликации может сделать результат устаревшим. Поэтому перед добавлением реплик нужно определить, какая часть нагрузки действительно состоит из допускающих eventual consistency чтений и не упирается ли система в другой ресурс.