Развернули Temporal (оркестратор workflow) в Docker и подключили две PostgreSQL-базы (основная и visibility).
Всё шло гладко. Через какое-то время от разработчиков прилетел запрос: «UI Temporal отдаёт 200 ОК, но ничего не грузит. Страница открывается, но данные не появляются.»
📍Проверили:
— Нагрузка на ноды в норме
— CPU/память без пиков, диски не забиты
— Алерты молчат.
Пробовали масштабировать Temporal и облегчить «тяжёлые» воркфлоу — без эффекта.
Подключили детальный мониторинг БД — и словили сюрприз: задержка отдельных запросов доходила до ~8 минут.
Копнули глубже: очередь соединений росла, а PgBouncer упирался в лимиты пула.
Это и оказался корень проблемы.
📍Что такое PgBouncer
— это лёгкий прокси для PostgreSQL, который управляет пулом соединений. Он ограничивает число одновременных коннектов от приложений, чтобы не положить базу. Когда пул переполнен, новые запросы встают в очередь и ждут свободного «слота». В этот момент UI кажется «зависшим»: страница уже вернула 200 ОК, но данных нет — запросы стоят в очереди на соединение.
Простая метафора
Запросы — пассажиры на остановке.
Пул соединений — парк автобусов с фиксированным числом машин(например 50).
База — конечная точка пути.
Пока все автобусы заняты, новые пассажиры стоят в очереди. Чем длиннее очередь, тем дольше UI «ничего не показывает».
Как это выглядит в архитектуре:
[Приложение / Temporal UI] → запросы → [PgBouncer] → очередь → [PostgreSQL]
📍Как мы подтвердили узкое место
— На дашбордах выросло время ответа БД и число «висящих» запросов
— В PgBouncer
cl_active упёрся в лимит пула, а cl_waiting начал растиВо второй части разберем:
— Подробный разбор:
max_client_conn, default_pool_size, reserve_pool_size— Что это такое и как работает — на аналогии с «автопарком» и очередью
— Как подобрать значения под вашу нагрузку и ограничения Postgres.
#заметкиИнженера
