Соединения с базой данных пикают при запуске Heroku Dyno с помощью django-db-geventpool - MAX_CONNS Not Enforced

Я использую Django, Gunicorn с Gevent и django-db-geventpool на Heroku (Performance L dynos, WEB_CONCURRENCY=17). Количество соединений с базой данных значительно увеличивается при запуске дино, превышая ожидаемое количество соединений.

Ожидаемое поведение

Учитывая мою установку:

  • MAX_CONNS=4 (на одного рабочего)
  • REUSE_CONNS=2
  • WEB_CONCURRENCY=17 (рабочих на одну диномашину)
  • 6 динамо-машин в производстве

Я ожидаю, что каждый dyno будет держать не более 68 соединений (17 рабочих * 4 MAX_CONNS). Однако при запуске я вижу, что отдельные дино временно удерживают 150+ незадействованных соединений, что способствует превышению лимита Heroku в 500 соединений.

Ключевые вопросы

  • Что делает django-db-geventpool, если запрашивается больше MAX_CONNS соединений?
    • Ставятся ли запросы в очередь и вынуждены ли они ждать, пока освободится соединение?
    • Или же django-db-geventpool игнорирует MAX_CONNS и позволяет соединениям превышать лимит?
  • Почему я могу наблюдать скачки соединений во время запуска dyno?

Шаги, предпринятые до сих пор

  • Убедились, что всплеск происходит только при запуске, а не при нормальном трафике.
  • Проверил pg_stat_activity и увидел много незадействованных соединений с того же дино.
  • Убедился, что у меня нет утечки соединений от Celery, заданий cron или фоновых задач.

Кто-нибудь сталкивался с этой проблемой при использовании django-db-geventpool на Heroku? Есть ли какие-нибудь соображения по поводу того, относится ли это к MAX_CONNS или соединения могут превысить лимит при высоком параллелизме?

Да, это должно абсолютно соответствовать MAX_CONNS, равному на одного работника. Я полагаю, что происходит то, что у вас на короткое время вдвое больше работников. Я столкнулся с чем-то подобным в AWS Elastic Beanstalk. Виновником были Все сразу Развертывание, которое отвечало за наличие 2-х экземпляров и, таким образом, удвоило количество подключений и превысило лимит подключений к базе данных. Все, что было нужно, - это изменить его на пакетный запуск. К сожалению, в Heroku, похоже, нет подобной опции. Что вы можете сделать, так это временно уменьшить масштаб вашего приложения heroku ps:scale worker=5, поработать с динамометром и снова увеличить его, как только закончите heroku ps:scale worker=17

Я предполагаю, что ваш динамометр использует множество процессов (я думаю, что выше 8 для каждого динамометра)

итак, MAX_CONNS x WEB_CONCURRENCY x No. of processes = По всем соединениям

, что в данном случае равно 4 x 17 x 8 = 544 или больше.

из django-db-geventpool GITHUB:

Ваш веб-сервер использует более одного процесса? В этом случае каждый процесс независим и соединения с базой данных не могут быть общими, таким образом, 2 процесса по 15 подключений в каждом могут открывать 30 подключений

источник

Из-за того, как работают python и gevent, пул разделяется между потоками (или гринлетами) внутри одного и того же процесса python, соединение не может быть разделено с другим процессом. Помните, что с gevent один процесс может использовать сотни или тысячи подключений одновременно, этот пул позволяет установить ограничение для каждого процесса, а также избежать запросов django DB для блокировки процесса, что сделает gevent бесполезным. Если вам нужен глобальный пул, следует использовать pgbouncer или что-то подобное.

Таким образом, значение MAX_CONNS должно быть равно (разрешенные подключения postgres / количество процессов) или меньше.

источник

Вернуться на верх