ТестированиеНагрузочное тестированиеИнженер по производительности

Сервис начинает нарушать SLA после увеличения пула соединений к базе данных. Как проверить, не перенесло ли...

Сервис начинает нарушать SLA после увеличения пула соединений к базе данных. Как проверить, не перенесло ли это изменение узкое место вместо его устранения?

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

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

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

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

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

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

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

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

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

Нельзя делать вывод только по тому, что после изменения вырос достигнутый RPS. Рост пропускной способности может сопровождаться ухудшением p95, p99, временем ожидания соединения или долей тайм-аутов.

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

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

Для каждого прогона сопоставляют:

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

Если пул мал, его увеличение обычно уменьшает ожидание соединения и улучшает задержку без резкого роста внутренних ожиданий базы данных. Если пул уже достаточно велик, дальнейшее увеличение даёт насыщение: RPS выходит на плато, а задержка и очереди растут. Это признак того, что ограничение находится ниже по цепочке — например, в CPU, дисковой подсистеме, блокировках или конкретном типе запросов.

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

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

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

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

Интернет-магазин увеличил пул с 10 до 40 соединений на экземпляр, потому что при нагрузочном тесте запросы долго ждали свободное соединение. В первом прогоне время ожидания действительно снизилось, но p99 вырос, а база данных стала чаще показывать ожидания блокировок и диска. Пропускная способность почти не изменилась.

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

Команда провела серию тестов с разными размерами пула, отдельно измеряя ожидание соединения, время выполнения SQL-операций и показатели базы данных. Выяснилось, что после определённого значения ожидание в приложении почти исчезало, а дальнейшее увеличение пула только повышало задержку запросов к базе.

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

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

  1. Можно ли считать рост времени ожидания соединения доказательством того, что пул слишком мал?

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

  1. Почему увеличение пула иногда повышает задержку даже при низкой загрузке CPU базы данных?

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

  1. Почему нельзя выбрать размер пула равным числу виртуальных пользователей нагрузочного теста?

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