Пулы соединений и Redis
Два столпа производительного доступа к данным: пул соединений к СУБД (открывать соединение дорого) и Redis для того, чему не место в реляционной базе. Собес проверяет, понимаешь ли ты, почему «пул исчерпан» под нагрузкой и где Redis - не замена БД.
Типовые формулировки: «зачем пул соединений?», «почему под нагрузкой пул исчерпывается?», «для чего Redis и что в нём нельзя хранить».
Пул: зачем и почему исчерпывается
Открыть соединение с БД дорого - TCP-хендшейк, аутентификация. Пул держит набор уже готовых соединений и выдаёт их запросам, а после - принимает обратно. Размер ограничивают под лимит СУБД (система управления базами данных): в SQLAlchemy это pool_size (постоянные) плюс max_overflow (временные).
При исчерпании пула новый запрос ЖДЁТ свободное соединение до pool_timeout, а не дождавшись - падает с TimeoutError. Отсюда главная причина «пул исчерпан» под нагрузкой - незакрытые сессии: соединение не вернулось в пул. Поэтому сессию обязательно закрывают (в FastAPI - teardown в yield-зависимости).
// И потолок: ставить размер пула больше max_connections СУБД бессмысленно - упрёшься в лимит самой базы, а не пула.
- пул соединений
- переиспользуемые готовые соединения с БД
- pool_timeout
- сколько ждать свободное соединение до ошибки
Redis: где уместен и где нет
Redis - быстрый in-memory key-value стор. Его берут под кэш с TTL (time to live), сессии, счётчики и рейт-лимиты (атомарный INCR), брокер очередей, pub/sub для рассылки между воркерами. Всё это - про скорость и простые структуры.
Но Redis НЕ замена реляционной БД: данные в памяти летучи (без настроенной persistence переживут не всякий перезапуск), а модель - простые структуры, а не таблицы с джойнами и внешними ключами. Хранить в нём то, что обязано пережить перезапуск, без persistence - потерять данные.
// Практика: истина живёт в PostgreSQL, Redis ускоряет и разгружает - кэш, счётчики, эфемерное состояние.
- pool_size/overflow
- постоянные + временные соединения пула
- Redis
- in-memory стор: кэш, сессии, счётчики, брокер
Как отвечать: «Почему под нагрузкой пул соединений исчерпывается?»
Чаще всего - из-за незакрытых сессий. Пул держит ограниченное число соединений, потому что каждое стоит ресурсов и упирается в лимит max_connections базы. Если код взял соединение и не вернул - например, сессия не закрылась из-за забытого teardown или исключения на полпути - оно навсегда занято. Под нагрузкой такие утечки быстро выбирают весь пул, и новые запросы ждут до pool_timeout, а потом падают с TimeoutError. Лечение - гарантированно закрывать сессию, в FastAPI это yield-зависимость с закрытием в finally. И размер пула не задираю выше max_connections СУБД - там всё равно потолок базы.
Названа корневая причина (утечка соединений), связана с лимитом СУБД и pool_timeout, дано конкретное лечение (гарантированное закрытие) - диагностика, а не пересказ определения.
На чём валят
- −Не закрывать сессии: соединения не возвращаются в пул - «пул исчерпан» под нагрузкой.
- −Ставить размер пула больше max_connections СУБД - упрёшься в лимит самой базы.
- −Хранить в Redis то, что должно пережить перезапуск, без настроенной persistence - данные летучи.
- −Считать Redis заменой реляционной БД: там простые структуры, а не таблицы с джойнами.
Проверьте себя
Пять вопросов из банка по этой подтеме. Всего их 11, остальные разбираются в тренажёре.
- Пул исчерпан (все соединения заняты), приходит новый запрос. Поведение по умолчанию (SQLAlchemy)?A)Ждёт освобождения до таймаута, потом бросает ошибкуB)Молча открывает соединений сколько нужно, игнорируя размер пулаC)Переключает запрос на резервную базу данных автоматическиD)Сразу отбрасывает запрос с ошибкой, не дожидаясь освобождения
показать ответ и разбор
+A)Ждёт освобождения до таймаута, потом бросает ошибку// разбор: У SQLAlchemy пул имеет pool_size и max_overflow (временные сверх-соединения). Когда всё занято, новый запрос ждёт до pool_timeout; не дождавшись — TimeoutError. Отсюда важность правильного размера пула и возврата соединений (закрывать сессии), иначе — «пул исчерпан» под нагрузкой.
- Для чего в бэкенде обычно ставят Redis?A)Как файловое хранилище для загруженных пользователями медиаB)Для полнотекстового поиска по документам вместо ElasticsearchC)Как основную реляционную базу с транзакциями и джойнамиD)Кэш, сессии, брокер очередей — быстрый in-memory стор
показать ответ и разбор
+D)Кэш, сессии, брокер очередей — быстрый in-memory стор// разбор: Redis — быстрый in-memory key-value стор: типичные роли в бэкенде — кэш (с TTL), хранилище сессий, счётчики/рейт-лимиты (атомарные INCR), брокер очередей (для Celery/RQ), pub/sub. Он не замена реляционной БД: данные живут в памяти, а модель — простые структуры, а не таблицы с джойнами.
- Зачем приложению пул соединений с БД вместо открытия коннекта на каждый запрос?A)Установка соединения дорога — пул переиспользует готовые, экономя времяB)Пул увеличивает максимальный размер результата, который можно получить из базыC)Пул шифрует соединения с базой, тогда как одиночный коннект идёт незащищённымD)Пул позволяет обойтись вообще без аутентификации при каждом обращении к базе
показать ответ и разбор
+A)Установка соединения дорога — пул переиспользует готовые, экономя время// разбор: Открытие соединения — дорого: TCP-рукопожатие, TLS, аутентификация, инициализация сессии на сервере. Делать это на каждый запрос — большие накладные расходы и лишняя нагрузка на БД. Пул держит набор уже открытых соединений и выдаёт их запросам, возвращая назад после использования. Это снижает задержку и ограничивает число одновременных коннектов к базе.
- Приложение в 8 инстансов, у каждого пул на 20 коннектов, у Postgres лимит 100. Чем это грозит?A)8×20=160 > 100 — база отвергнет часть соединений; размеры пулов надо согласовать с лимитомB)Ничем: Postgres автоматически поднимет свой лимит соединений под нагрузку от приложенияC)Проблема только в памяти приложения; на стороне базы данных ограничений нетD)База просто станет медленнее, но все 160 соединений всё равно будут обслужены разом
показать ответ и разбор
+A)8×20=160 > 100 — база отвергнет часть соединений; размеры пулов надо согласовать с лимитом// разбор: Лимит соединений БД — общий на всех клиентов. 8 инстансов по 20 в пуле — потенциально 160 коннектов при max_connections=100: часть запросов на соединение получит отказ (too many connections). Размеры пулов согласуют с лимитом сервера и числом инстансов, оставляя запас на служебные подключения. При многих инстансах ставят внешний пулер (PgBouncer), мультиплексирующий соединения.
- Redis чаще всего применяют в веб-бэкенде как что?A)Файловое хранилище для больших медиа-объектов вроде видео и изображений пользователейB)Основное надёжное хранилище всех данных приложения вместо реляционной базы данныхC)Быстрый кеш в памяти для частых чтений (и брокер/сессии)D)Инструмент для построения сложных отчётов с многотабличными JOIN по историческим данным
показать ответ и разбор
+C)Быстрый кеш в памяти для частых чтений (и брокер/сессии)// разбор: Redis — быстрое in-memory key-value хранилище со структурами данных (строки, хеши, списки, множества, sorted sets). Типичные роли в бэкенде: кеш горячих чтений, брокер очередей задач (Celery/RQ), хранилище сессий, счётчики и rate-limit, pub/sub. Как единственный источник правды его берут редко (данные в памяти, ограниченная надёжность), обычно — слой поверх основной БД.
дальше
Теорию прочитали. Навык ставится повторением
В Сеньорчике эта подтема идёт в ежедневных сессиях: движок возвращает её, пока ответы не станут уверенными, и ведёт прогресс отдельно по каждой подтеме. Теория внутри тоже бесплатна, лимит только на количество вопросов в день.