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

Когда веб-сервис на Kubernetes получает больше запросов, добавление реплик часто помогает только до первого скрытого ограничения. Приложение может выдерживать рост с двух до двадцати Pod, а PostgreSQL, пул соединений или внешний API уже начнут отвечать медленнее. Ниже — разбор для stateless HTTP-сервиса на Kubernetes 1.30+ с PostgreSQL 16: где возникает узкое место, как измерить предел и почему горизонтальное масштабирование не заменяет работу с состоянием.
Что именно масштабируется
Запрос проходит несколько независимых слоёв: балансировщик, Ingress, Pod приложения, пул соединений, базу данных, кэш и внешние сервисы. У каждого слоя собственная ёмкость. Система масштабируется только до предела самого слабого звена.
Условно пропускную способность можно представить как минимум из нескольких величин: запросы, которые обрабатывают Pod, соединения, которые принимает база, операции чтения и записи, доступная память и лимит внешнего API. Если один из этих ресурсов заканчивается, новые реплики лишь быстрее добираются до общей стены.
Реплика увеличивает число работников. Она не увеличивает размер общей базы, лимит платёжного API и количество соединений, которое способен принять PostgreSQL.
Сноска. Stateless-сервис — приложение без локального состояния, необходимого для следующего запроса. Сессии, загруженные файлы и другие данные хранятся снаружи: в базе, Redis или объектном хранилище. Это позволяет направлять следующий запрос пользователя на любой Pod.
Путь запроса и первая точка отказа
Балансировщик и Ingress
Внешний балансировщик распределяет трафик между узлами, а Ingress — между Pod через Service. Если часть Pod не проходит readiness-проверку, трафик на них не должен поступать. Ошибка в проверке опасна в обе стороны: слишком простая проверка отправит запросы в неготовое приложение, а слишком тяжёлая создаст дополнительную нагрузку на базу.
Под нагрузкой смотрите не только на среднее время ответа, но и на p95 и p99. Если среднее значение остаётся стабильным, а p99 растёт, отдельные запросы уже попадают в очередь или ждут соединение.
Pod приложения
Каждый Pod имеет CPU и память, заданные requests и limits. При нехватке CPU растёт время выполнения, при нехватке памяти процесс может завершиться с OOMKilled. Увеличение числа Pod помогает только тогда, когда в кластере есть свободные ресурсы и приложение действительно использует параллелизм.
Проверьте четыре показателя:
- число запросов в секунду на один Pod;
- p95 и p99 задержки отдельно для чтения и записи;
- долю ответов 5xx и таймаутов;
- перезапуски, OOMKilled и время ожидания CPU.
Пул соединений
Каждая реплика обычно держит пул соединений к PostgreSQL. Если один Pod открывает 20 соединений, а реплик становится 30, база потенциально получает 600 соединений. Это не означает, что запросы обработаются в 30 раз быстрее: соединения потребляют память, конкурируют за блокировки и могут превратить базу в очередь ожидания.
Опасный сценарий выглядит так: HPA добавляет Pod из-за роста CPU, каждый новый Pod открывает пул, PostgreSQL достигает лимита, а задержка увеличивается ещё сильнее. Поэтому размер пула считают от лимита базы и числа реплик, а не задают одинаковым большим значением «на всякий случай».
PostgreSQL 16
У PostgreSQL есть разные пределы для чтения и записи. Чтение можно частично распределять между репликами, но запись должна проходить через первичный сервер или согласованный слой маршрутизации. Репликация не делает запись параллельной и не устраняет блокировки.
На пределе обычно заметны:
- рост времени ожидания блокировок;
- длинные транзакции, удерживающие старые версии строк;
- увеличение I/O и очереди диска;
- рост количества активных соединений без роста завершённых запросов;
- расхождение между репликой чтения и первичной базой.
Последний пункт важен для пользовательских сценариев. Если после записи следующий запрос уходит на отстающую реплику, пользователь может временно не увидеть собственные изменения. Это уже не проблема балансировщика, а следствие выбранной модели согласованности.
Три стратегии и их цена
| Стратегия | Что меняется | Когда помогает | Цена и риск |
|---|---|---|---|
| Вертикальное масштабирование | Больше CPU, памяти или быстрее диск у существующего узла | Нужно быстро убрать дефицит ресурса без изменения приложения | Есть физический предел и единая точка отказа; простой может потребоваться при смене узла |
| Горизонтальное масштабирование | Больше экземпляров stateless-приложения | Запросы независимы, а узкое место находится в коде или CPU Pod | Растёт давление на базу, кэш, сеть и внешние API |
| Асинхронная обработка | Тяжёлая работа уходит в очередь и выполняется воркерами | Пользователю не нужен результат в том же HTTP-запросе | Появляются повторы, задержка результата, дедупликация и контроль очереди |
| Разделение чтения и записи | Чтения направляются на реплики, записи — на primary | Профиль нагрузки преимущественно читательский | Отставание реплик, сложная маршрутизация и проблема read-after-write |
Главная ошибка — выбирать стратегию по графику CPU приложения. Если CPU Pod загружен на 40%, но запросы ждут соединение с базой, горизонтальное масштабирование только увеличит число ожидающих клиентов.
Как измерять предел, а не гадать
Замеры нужно проводить на копии продакшен-конфигурации: с теми же лимитами Pod, размером пула соединений, схемой индексов, типом диска и объёмом данных. Результаты теста на пустой базе нельзя переносить на рабочую систему.
- Зафиксируйте базовую линию. Запишите RPS, p50, p95, p99, процент ошибок, CPU и память Pod, активные соединения и задержку запросов к PostgreSQL. Проверка: для каждого показателя есть значение за один и тот же интервал.
- Увеличивайте нагрузку ступенями. Добавляйте виртуальных клиентов, например по заранее выбранному шагу, и выдерживайте каждую ступень достаточно долго, чтобы закончились прогрев кэша и фоновые операции. Проверка: метрики перестали расти рывками после выхода на устойчивый режим.
- Меняйте только один параметр. Сначала число Pod, затем размер пула, затем конфигурацию базы. Проверка: понятно, какое изменение повлияло на p95 и пропускную способность.
- Ищите насыщение ресурса. Сопоставьте задержку с CPU, памятью, диском, блокировками, очередью соединений и сетевыми ошибками. Проверка: найден ресурс, после насыщения которого задержка растёт, а завершённых запросов больше не становится.
- Проверьте отказ. Удалите Pod, отключите одну реплику чтения или искусственно задержите внешний сервис в тестовом окружении. Проверка: система либо сохраняет заявленный уровень сервиса, либо выдаёт контролируемую ошибку без лавины повторных запросов.
Если стенда для полноценного теста нет, не подменяйте замеры догадками. Настройте сбор метрик и начните с трассировки нескольких самых дорогих маршрутов. Для каждого маршрута разделите время на ожидание приложения, базы, внешнего API и очереди.
Где масштабирование ломается первым
Общее состояние внутри Pod
Локальные сессии, временные файлы и загрузки на диске Pod делают запрос зависимым от конкретного экземпляра. После увеличения реплик часть пользователей начнёт терять состояние, а после пересоздания Pod данные исчезнут. Сессии вынесите в общее хранилище, а файлы — в объектное хранилище или постоянный том с подходящей моделью доступа.
Непредсказуемые повторы
Таймаут не означает, что операция не выполнилась. Клиент может повторить запрос, пока первый всё ещё обрабатывается. Для платежей, заказов и любых операций записи нужны идемпотентность, уникальный идентификатор операции и понятная политика повторов. Иначе масштабирование увеличит не только пропускную способность, но и число дублей.
Каскадный отказ
Когда база замедляется, Pod дольше держат соединения. Пул заполняется, запросы ждут, таймауты запускают повторы, а HPA добавляет новые Pod. Так возникает положительная обратная связь. Ограничивайте время ожидания, число повторов и размер очередей, иначе защита от краткого сбоя превратится в усилитель аварии.
Автомасштабирование по неправильному сигналу
HPA, настроенный только на CPU, не видит очередь в брокере, задержку базы или число ожидающих соединений. Для HTTP-сервиса полезнее сопоставлять загрузку с latency и RPS на Pod. Для воркеров — с длиной очереди и возрастом самого старого сообщения. Конкретные метрики и адаптер зависят от вашей версии Kubernetes и системы мониторинга, поэтому их нужно сверять с документацией установленного стека.
Что делать дальше
Сначала составьте карту пути одного запроса и отметьте для каждого слоя лимит: CPU, память, соединения, I/O, очередь или внешний rate limit. Затем поставьте алерты на p95, p99, 5xx, время ожидания соединения и отставание реплик. После этого проведите ступенчатый тест на конфигурации, близкой к продакшену.
Не начинайте с увеличения числа Pod. Сначала выясните, какой ресурс насыщается и сколько стоит его расширение. Для PostgreSQL отдельно проверьте планы самых тяжёлых запросов, блокировки и рост дисковой очереди. Инвалидация кэша и шардирование — отдельные темы: они меняют модель данных и требуют самостоятельного проектирования.
Субтитры и таймкоды: Расшифровка речи и субтитры по правилам читаемости: 42 знака в строке, две строки, минимум секунда на реплику.
Спросить за 40 ₽Источники: Kubernetes Documentation: Horizontal Pod Autoscaling, PostgreSQL 16 Documentation: High Availability, Load Balancing, and Replication
Частые вопросы
Почему после увеличения числа Pod сервис не стал быстрее?
Как понять, что пора масштабировать базу, а не приложение?
Что будет, если пул соединений настроен слишком большим?
А если у меня другая версия Kubernetes или PostgreSQL?
Что делать, если после роста нагрузки появились дубли операций?
Какие метрики смотреть в продакшене в первую очередь?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.