На графике нагрузочного теста CPU приложения низок, но время ожидания соединения с базой данных растёт. Какой узел следует считать вероятным узким местом?
Вероятным узким местом является не CPU приложения, а доступ к базе данных: сама база, сетевой обмен с ней или ограниченный пул соединений. Рост времени ожидания показывает, что запросы не могут своевременно получить соединение, поэтому нужно исследовать насыщение этого ресурса и причины его возникновения.
Низкая загрузка CPU не опровергает наличие узкого места: приложение может проводить значительную часть времени в ожидании внешнего ресурса.
Профилирование производительности первоначально часто сводилось к поиску процесса, который потребляет больше всего CPU. Такой подход был полезен для вычислительно сложных программ, но оказался недостаточным для распределённых систем, где задержка формируется ожиданием базы данных, сети, диска, брокера сообщений или ограниченного пула потоков.
Поэтому анализ нагрузочных тестов стал опираться не только на общую задержку и загрузку процессора, но и на состояние очередей, пулов и внешних зависимостей. Это позволяет находить ресурс, который ограничивает пропускную способность системы, даже если остальные ресурсы простаивают.
При росте нагрузки приложение может быстро занимать все доступные соединения с базой данных. Новые запросы тогда не начинают работу сразу, а ждут освобождения соединения; это увеличивает задержку и может привести к тайм-аутам.
Неверно объявить CPU приложения причиной проблемы только потому, что он является главным ресурсом сервиса. Также опасно без проверки увеличить размер пула соединений: это может временно уменьшить очередь приложения, но перегрузить базу данных, усилить конкуренцию за блокировки и ухудшить результат.
Сначала нужно разделить два похожих случая:
Для различения случаев сопоставляют время ожидания соединения, число занятых и свободных соединений, длительность запросов к базе данных, число активных запросов, ошибки и тайм-ауты. Дополнительно проверяют сетевую задержку, блокировки и соответствие длительности теста прогреву кэшей и установлению соединений.
Признаком узкого места является согласованная картина: очередь на получение соединения растёт, пул близок к полной занятости, а пропускная способность базы данных или приложения перестаёт увеличиваться. Однако один показатель недостаточен: рост ожидания может быть следствием неправильной инструментальной метрики или короткого всплеска нагрузки.
Размер пула выбирают как компромисс. Слишком маленький пул создаёт очередь внутри приложения, а слишком большой увеличивает конкуренцию за ресурсы базы данных и количество одновременно выполняемых операций. После изменения конфигурации тест повторяют при той же модели нагрузки и сравнивают не только задержку, но и ошибки, пропускную способность и состояние базы данных.
Во время теста API при увеличении нагрузки CPU приложения оставался на уровне около 35%, но p95 задержки быстро рос, а метрика ожидания соединения с базой данных достигала нескольких секунд. В пуле постоянно не было свободных соединений.
Рассматривались три варианта. Увеличение пула обещало быстро сократить очередь, но могло усилить нагрузку на базу данных. Масштабирование приложения добавило бы экземпляры, однако каждый из них создал бы собственный пул и мог суммарно ещё сильнее перегрузить базу. Оптимизация запросов требовала больше времени, но устраняла бы первопричину при подтверждении медленных операций.
Сначала проверили длительность запросов, планы выполнения и блокировки. Выяснилось, что один запрос выполнялся дольше ожидаемого из-за неэффективного доступа к данным и удерживал соединение на протяжении всей операции. После оптимизации запроса и умеренной настройки пула ожидание почти исчезло, p95 снизился, а база данных сохранила запас производительности. Простое масштабирование приложения в этом случае дало бы худший результат.
Может ли растущее ожидание соединения означать, что пул слишком большой?
Да, косвенно. Само ожидание обычно означает нехватку свободных соединений, но увеличение пула могло ранее перегрузить базу данных и увеличить длительность каждой операции. В результате соединения удерживаются дольше, очередь растёт, хотя формальная причина находится не в размере пула, а в снижении производительности базы.
Почему нельзя считать низкую загрузку CPU доказательством отсутствия проблем с приложением?
Потоки приложения могут быть заблокированы ожиданием соединения, ответа базы данных или сетевого ввода-вывода. В таком состоянии они почти не используют CPU, но пользовательская задержка продолжает расти. Поэтому загрузку CPU нужно анализировать вместе с состоянием потоков, очередей, пулов и длительностью внешних операций.
Как отличить узкое место базы данных от слишком короткого тайм-аута получения соединения?
Нужно сопоставить несколько временных рядов. Если запросы к базе выполняются быстро, пул полностью занят лишь краткими всплесками, а тайм-ауты возникают при недостаточном размере пула, вероятна проблема настройки или модели нагрузки. Если же соединения удерживаются долго, растут длительность запросов, число активных операций, блокировки или загрузка ресурсов базы, увеличение тайм-аута только позволит запросам дольше ждать и не устранит узкое место.