День 2696. #ЗаметкиНаПолях
Планирование Мощностей для API. Окончание
Начало
Продолжение
Следим за результатами
- Задержка p95 - Остается ли скорость в выбранных рамках?
- Частота ошибок 429 - Срабатывает шлюз нагрузки, как и было задумано.
- pendingOutbox (длина очереди обработки – в примере выше в http://localhost:5080/api/metrics) - Если это число продолжает расти и никогда не уменьшается, ваши фоновые процессы не справляются со скоростью записи, а это тоже ограничение пропускной способности — только в фоновых сервисах.
Цель здесь никогда не состоит в нулевом количестве ошибок. Цель — предсказуемое снижение производительности — точное знание того, что делает API, когда вы выходите за его предел, чтобы отказ был плавным, а не катастрофическим.
Рекомендуемые пороговые значения
Это отправные точки, а не законы. Ваши показатели зависят от оборудования, запросов и SLO. Но при отсутствии другой информации, вот примерные цифры:
- Менее ~100 запросов в секунду
Пока не стоит обращаться к инфраструктуре. Сначала избавьтесь от N+1 запросов и лишних аллокаций. Большинство API на этом уровне работают медленно из-за кода, а не из-за нагрузок на оборудование.
- ~100-1000 запросов в секунду
Здесь оправдывает себя кэширование, и имеет смысл настройка пула соединений. Правильно определите размер пула и разместите кэш перед наиболее часто выполняемыми операциями чтения.
- 1000+ запросов в секунду на операции записи
Прекратите синхронную запись в БД на пути запроса. Перейдите к выравниванию нагрузки на основе очередей: быстро отвечайте на запросы, обрабатывайте их в фоновом режиме (см. паттерн Outbox в демо-проекте).
- Высокие пиковые нагрузки + строгий уровень SLO
Добавьте явное ограничение скорости. Встроенный ограничитель скорости в ASP.NET Core или шлюз, подобный описанному выше. Определите точку отказа целенаправленно, а не после обнаружения её в проде.
Общий принцип для всех вариантов: по мере роста нагрузки работа перемещается за пределы пути запроса. Операции чтения кэшируются, операции записи ставятся в очередь, а синхронная критическая секция становится минимально возможной.
Контрольный список по планированию мощностей
1. Для каждого класса конечной точки существует записанный SLO (целевой показатель p95 + бюджет ошибок).
2. Скрипты нагрузочного тестирования находятся в системе контроля версий рядом с кодом и запускаются при каждом значимом изменении.
3. Для каждого класса конечной точки существует известный, задокументированный максимальный безопасный RPS.
4. Существует руководство по масштабированию вверх и вниз — именно при масштабировании вниз скрываются неожиданности.
5. Оповещения срабатывают при p95, частоте тайм-аутов и задержке очереди — а не только по CPU и памяти.
Если хотя бы один из этих параметров отсутствует, вам снова придется гадать при следующем релизе.
Часто задаваемые вопросы
Какой показатель важнее всего?
Задержка p95, почти всегда. Она отражает то, что чувствует реальный пользователь. Сочетайте её с частотой таймаутов и частотой ошибок, чтобы отличать «медленную» работу от «сбоев».
Как часто следует повторно запускать тесты производительности?
При каждом значимом изменении архитектуры или БД, и как минимум один раз за цикл выпуска. Самый быстрый способ потерять показатель производительности — это выпустить изменения, копившиеся три месяца, и предположить, что он всё ещё актуален.
Является ли возврат кода 429 под нагрузкой ошибкой?
Нет — если это сделано намеренно, система защищает запросы, которые она может обработать. Ошибка - принимать неограниченную нагрузку и снижать производительности для всех пользователей вместо того, чтобы избавиться от чрезмерных запросов.
Источник: https://thecodeman.net/posts/capacity-planning-for-dotnet-apis-from-guessing-to-measured-scaling
Post #3226
1.42K
- 👍 2