Каждый бэкенд-разработчик рано или поздно сталкивается с ситуацией, когда база данных MySQL внезапно ложится при резком пиковом наплыве пользователей. Классическая ошибка на старте - создавать новое независимое соединение с СУБД на каждый чих приложения, выполнять один короткий запрос и закрывать коннект. Когда на сайт одновременно залетают сотни людей, сервер моментально упирается в системный лимит max_connections и падает с ошибкой OperationalError: (1040, 'Too many connections'), попутно забивая всю доступную оперативную память.

Решение

В больших системах эту проблему перекладывают на тяжелые ORM вроде SQLAlchemy, но для локальных утилит, легковесных микросервисов и CLI-скриптов тащить за собой мегабайты чужих зависимостей ради одного пула коннектов это оверхед.

Мы разработали кастомный, легковесный асинхронный пул подключений на Python и драйвере aiomysql, который работает по принципу «микросервисной архитектуры» и изолирует нагрузку на стороне клиента. Вместо постоянного открытия и закрытия коннектов «туда-сюда», наш пул при старте инициализирует фиксированное количество постоянных соединений и держит их в асинхронной очереди asyncio.Queue.

Когда прилетает запрос, он берет готовое соединение из коробки, выполняет команду и возвращает его обратно. Если все соединения заняты — новый запрос не плодит нагрузку на RAM сервера, а покорно и незаметно для пользователя ждет своей очереди доли секунды. Чтобы защитить пул от утечек при возможных сбоях внутри запросов, вся логика завернута в строгий блок try...finally.

Для кого это создано

Данный пул разрабатывался не для гигантов с миллионными бюджетами на инфраструктуру. Целевая - легковесные асинхронные микросервисы, Telegram-боты на aiogram и стартапы, работающие на бюджетных VPS-серверах. Когда покупать дорогое железо нет бюджета, а бд MySQL падает от резких пиков, легковесный пул на чистом asyncio позволяет копеечному серверу без проблем выдерживать наплыв в сотни параллельных запросов. Сознательно отказываюсь от тяжелых ORM ради экономии ресурсов сервера и высокой скорости производительности.

Результаты стресс-теста

Для проверки софта под нагрузкой мы написали встроенный симулятор Highload-наплыва трафика Хабраэффект, который в реальном времени отправляет 300 одновременных запросов к локальной СУБД.

  • Тест БЕЗ пула подключений: СУБД моментально захлебывается и падает с системной ошибкой. MySQL уходит в глухую защиту от лавины параллельных сокетов, полностью отключая сайт для пользователей.

  • 2. Тест С КАСТОМНЫМ ПУЛОМ (Размер пула = 5 коннектов): Все 300 параллельных запросов успешно обработаны без единой ошибки за 0.04 секунды. При этом общее время выполнения сокращается в разы, а потребление оперативной памяти сервера падает на 80%.

Весь проект полностью открыт, снабжен подробными комментариями и двуязычной README-инструкцией по быстрой установке и интеграции в ваши проекты ЗДЕСЬ (Если будет полезно, поддержите звездочкой). Каждый желающий может склонировать репозиторий, прописать конфиг своей локальной СУБД MySQL и лично проверить воспроизводимость результатов бенчмарка.

Комментарии (19)


  1. KKKSite
    02.07.2026 20:28

    Для этих целей есть же известное давнее решение: ProxySQL – это прокси-сервер MySQL с открытым исходным кодом, держит коннекты, пул из нескольких серверов и десятки параметров... Использую это на многих проектах


    1. laenij Автор
      02.07.2026 20:28

      Согласен с вами, ProxySQL - это хороший, проверенный временем индустриальный стандарт для балансировки и менеджмента пулов на уровне крупной инфраструктуры. На больших проектах с репликацией и десятками нод без него никуда.

      Разница здесь исключительно в слоях абстракции. ProxySQL требует развёртывания как отдельного демона, настройки конфигурационных слоёв и администрирования.

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


      1. FurySeer
        02.07.2026 20:28

        Не надо десятков нод, чтобы ProxySQL был оправдан.

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


        1. laenij Автор
          02.07.2026 20:28

          У меня другая задача. Пул решает конкретную проблему. Когда условно на бюджетной виртуалке с 512 МБ RAM прилетает 300 параллельных запросов, MySQL падает от Too many connections. Это не CPU, это именно лимит соединений. Пул даёт переиспользовать 5 соединений вместо 300 - и БД перестаёт захлёбываться. По CPU - если запросы тяжёлые, он убирает оверх на открытие и закрытие сокетов, а если CPU всё-таки упирается - это следующий уровень оптимизации: индексы, кэш, рефакторинг запросов. Проект делал под Python-ботов


          1. FurySeer
            02.07.2026 20:28

            Окей, если приложение дождётся выполнения 300-ого запроса - это конечно должно сработать

            Не воспринимайте за нападки - я целиком и полностью поддерживаю учебные проекты, вы молодец!


            1. laenij Автор
              02.07.2026 20:28

              Проект же для этого и делался - чтобы люди пробовали. Ну и опыт нужен, дальше можно развиваться в любую сторону, на Java например)


  1. Void-Cowboy
    02.07.2026 20:28

    так стоп - на прелоадере картинка с гошными маскотами, а под капотом питон. Репа тоже с питоном

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


    1. laenij Автор
      02.07.2026 20:28

      Спасибо за внимательность! На самом деле с прелоадером получилась пасхалка, я хотел использовать для след статьи.


  1. not_yours_ne
    02.07.2026 20:28

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

    Не каждый, а только тот, кто зачем-то пользуется MySQL


    1. FurySeer
      02.07.2026 20:28

      Точно, постргес из коробки держит любую нагрузку без лишних движений)


  1. BugM
    02.07.2026 20:28

    А зачем если есть HicariCP. Проверен годами, в продакшене давно.


    1. laenij Автор
      02.07.2026 20:28

      пул создавался именно для легковесных асинхронных микросервисов на Python, где нет места тяжеловесным ORM и JVM. Это решение для тех, кто пишет на asyncio/aiogram и хочет контролировать каждый байт RAM на бюджетном VPS. HikariCP не поможет Telegram-боту на aiogram, который работает на Python.


  1. coh
    02.07.2026 20:28

    Звучит так что в этом кейсе вы просто уперлись в дефолтные настройки mysql, вполне возможно, что достаточно было увеличить thread_cache_size и max_connections в настройках сервера (и вообще не использовать дефолты). Коннекты в mysql не такие дорогие как например в postgres.

    Ну и mysql.connector.pooling если мы про python приложение.


  1. coh
    02.07.2026 20:28

    Еще не понятно что значит в статье «Мы разработали кастомный, легковесный асинхронный пул подключений на Python и драйвере aiomysql». Какая связь между вами и разработкой aiomysql? Если я правильно понял, в вашем тесте на гитхабе вы используете именно эту библиотеку, но контрибьюшена с этого аккаунта в репозиторий aiomysql не видно.


    1. laenij Автор
      02.07.2026 20:28

      Поверх драйвера aiomysql мы реализовали свой пул с фиксированным числом соединений и очередью на asyncio.Queue. Извиняюсь за неточную формулировку


  1. Akina
    02.07.2026 20:28

    Когда прилетает запрос, он берет готовое соединение из коробки, выполняет команду

    Угу, прощайте, кастомные настройки, пользовательские переменные, вре́менные таблицы, и всё прочее со scope=connection.


  1. miharionov
    02.07.2026 20:28

    Неплохое решение для небольших проектов. Часто именно из-за неправильной работы с подключениями люди упираются в лимиты, хотя проблема не в самой MySQL.


  1. lapylia
    02.07.2026 20:28

    Перегружать проект тяжёлыми инструментами, чтобы бот не падал при 100 запросах - ну такое, а тут даже без перегруза


  1. Borikinternet
    02.07.2026 20:28

    А еще можно сделать пул динамическим (нижний/верхний уровень числа сессий). Плюс можно прикинуть, что некоторые запросы дешевле поставить в очередь, чем открывать к ним дополнительные соединения. А еще можно посчитать временнОй бюджет на исполнение запроса от пользователя и при нагрузочном тестировании разложить его на исполнение/ожидание внешних сервисов. Получится почти эталонная задача с собеседования в любой бигтех 10 лет назад.