Соединения (Connections) — это скрытый механизм, о котором мы часто забываем, пока система не ляжет под нагрузкой. Главная проблема соединений — их асимметричная стоимость.
- Для клиента (сервера приложения) установить TCP-соединение стоит копейки: нужен лишь один порт и пара килобайт под буфер.
- Для базы данных (особенно PostgreSQL) каждое новое соединение — это колоссальная нагрузка.
Физика под капотом
В PostgreSQL используется архитектура на основе процессов. На каждое входящее соединение сервер форкает (создает) новый тяжеловесный процесс ОС. Каждый такой процесс потребляет минимум 10 МБ оперативной памяти. Если к БД придет 2000 клиентов, она сожрет 20 ГБ памяти просто на поддержание пустых коннектов, даже если они ничего не делают.
В MySQL используется архитектура на основе потоков (threads). На каждое соединение создается поток внутри одного процесса БД. Памяти уходит меньше, но при тысячах коннектов процессор начинает задыхаться от постоянного переключения контекста (Context Switch) между тысячами потоков.
Что такое Пул соединений?
Чтобы БД не тратила ресурсы на бесконечное создание и уничтожение процессов, был придуман паттерн Pooling.
Пул — это объект, который держит заранее открытый набор соединений с БД. Когда коду нужно сходить в базу, он не открывает TCP-соединение с нуля, а делает следующее:
- Берет готовое открытое соединение из пула.
- Выполняет полезный SQL-запрос.
- Мгновенно возвращает соединение обратно в пул, чтобы им мог воспользоваться кто-то другой.
В следующем уроке мы разберем, где именно должен физически находиться этот пул, и почему инженеры часто настраивают сразу два пула одновременно.