Кожне з'єднання з базою коштує ресурсів на сервері бази: у PostgreSQL це окремий процес з власною пам'яттю (мегабайти), у MySQL - потік. Тому кількість з'єднань обмежена (max_connections), і її не можна просто підняти до тисяч - база витратить пам'ять і процесор на керування з'єднаннями замість запитів.
Як PHP-застосунок вичерпує з'єднання: кожен процес PHP-FPM (чи воркер черги, чи воркер Octane) тримає власне з'єднання.
4 вебсервери × 50 процесів PHP-FPM = 200 з'єднань
3 сервери воркерів × 20 процесів = 60
планувальник, Horizon, Pulse, cron ~ 20
Додали сервери під час піку - і наступний запит отримує too many connections. Причому з'єднань багато, а активних запитів у кожен момент - одиниці: більшість процесів PHP у цей час чекає на мережу, рендерить шаблон чи стоїть без діла.
Пул з'єднань - проміжний сервіс між застосунком і базою (PgBouncer для PostgreSQL, ProxySQL для MySQL, керовані пули в хмарах):
- застосунок відкриває сотні «дешевих» з'єднань до пулу;
- пул тримає невелику кількість справжніх з'єднань до бази (наприклад, 30) і видає їх на час транзакції;
- база бачить рівно стільки з'єднань, скільки може ефективно обслужити.
Режими PgBouncer:
- session - з'єднання закріплене за клієнтом на весь сеанс (мало виграшу);
- transaction - з'єднання видається лише на час транзакції - найефективніший, але ламає функції, що живуть довше транзакції:
SETна рівні сесії, advisory locks на сесію,LISTEN/NOTIFY, підготовлені запити поза протоколом; - statement - на кожен оператор, найобмеженіший.
Для Laravel з PgBouncer у режимі transaction - вимкнути емульовані/постійні підготовлені запити, якщо вони несумісні, і не покладатися на стан сесії між транзакціями.
Інші важелі:
- обмежити кількість процесів PHP-FPM і воркерів реальною потребою;
- закривати з'єднання в довгоживучих воркерах між задачами, якщо задачі рідкісні;
- скоротити тривалість транзакцій - менше часу з'єднання зайняте.
Помилка, якої варто уникати: «вирішити» проблему, піднявши max_connections до тисяч - база почне деградувати від кількості з'єднань раніше, ніж від запитів.