Как pgBouncer помогает ускорить Django

У меня есть несколько команд управления, которые основаны на Gevent. Поскольку моя команда управления выполняет тысячи запросов, я могу превратить все вызовы сокетов в неблокирующие вызовы с помощью Gevent. Это действительно ускоряет мое приложение, так как я могу делать запросы одновременно.

В настоящее время узким местом в моем приложении является Postgres. Похоже, это потому, что библиотека Psycopg, которая используется для подключения к Django, написана на C и не поддерживает асинхронные подключения.

Я также читал, что использование pgBouncer может ускорить Postgres в 2 раза. Это звучит здорово, но было бы здорово, если бы кто-то мог объяснить, как работает и помогает pgBouncer?

Спасибо

 wildplasser02 мая 2012 г., 20:48
Существует также вероятность того, что модель вашей базы данных не соответствует запросам, которые вы запускаете. Обычно нагрузка на сеть очень мала по сравнению с работой, необходимой для извлечения блоков данных с диска, а также: это не снижает производительность, а только задержку. (за исключением, может быть, в случае очень частых подключений / отключений)

Ответы на вопрос(2)

выступая в качестве прокси-сервера, который поддерживает пул соединений. Это может помочь ускорить ваше приложение, если вы открываете много кратковременных подключений к Postgres. Если у вас есть только небольшое количество соединений, вы не увидите большую часть выигрыша.

 02 мая 2012 г., 20:59
Вы можете найтиthis question есть еще немного интересной информации. Но обратите внимание, что есть причина, по которой новые соединения открываются при каждом запросе. Если запрос обнаруживает ошибку, возможно, транзакция может быть не закрыта должным образом (среди прочего), что приводит к неожиданным результатам.
 03 мая 2012 г., 00:29
Вы можете подключиться к сигналуdjango.db.backends.signals.connection_created а затем сделать некоторые записи. (Обратите внимание, что вы не захотите делать это в работе, поскольку это приведет к ненужным накладным расходам.)
 02 мая 2012 г., 20:58
Да, Django создаст новое соединение, но соединение будет установлено быстрее, так как это будет локальный экземпляр PgBouncer. Django будет использовать новое соединение для каждого веб-запроса, а не для запроса к базе данных.
 Mridang Agarwalla02 мая 2012 г., 21:06
Есть ли способ проверить, сколько раз Django создает и уничтожает соединение за время выполнения моей команды управления. Я мог бы проверить это, и если DJango устанавливает много новых соединений, было бы хорошо использовать pgBouncer, в противном случае я рассмотрю другой сценарий. Это команда управления a, а не запрос веб-страницы, поэтому мне интересно, действительно ли соединение с базой данных создано только один раз. У меня есть тысячи обращений в дб от моей команды управления. Благодарю.
 Mridang Agarwalla02 мая 2012 г., 20:46
Если я правильно понял это - Django по-прежнему создает соединения снова и снова, но pgBouncer сокращает время, необходимое для создания этого соединения. Я слышал, что Django создает новое соединение для каждого запроса. Под запросом подразумевается ли веб-запрос на получение страницы (что означает, что каждая отдельная команда, выполняемая в цикле просмотра, проходит через одно соединение с базой данных), или под запросом подразумевается каждый отдельный удар по базе данных (SELECT, INSERT, UPDATE и DELETE ) в этом случае каждая отдельная команда будет выполняться в новом соединении, даже если они будут в одном цикле просмотра
Решение Вопроса

е, если это делается в противном случае для каждого запроса, диспетчер соединений может передавать большое количество клиентских подключений на небольшое количество реальных подключений к базе данных. В PostgreSQL оптимальное количество активных соединений с базой данных обычно где-то около ((2 * core_count) +ffective_spindle_count). Выше этого числа и пропускная способность, и задержка ухудшаются.

Иногда люди говорят: «Я хочу поддержать 2000 пользователей с быстрым временем отклика». В значительной степени гарантируется, что если вы попытаетесь сделать это с 2000 реальных подключений к базе данных, производительность будет ужасной. Если у вас есть машина с четырьмя четырехъядерными процессорами и активный набор данных полностью кэширован, вы увидите гораздо более высокую производительность для этих 2000 пользователей, направив запросы через 35 соединений с базой данных.

Чтобы понять, почему это так, этот мысленный эксперимент должен помочь. Рассмотрим гипотетическую машину сервера баз данных с одним и тем же ресурсом - одним ядром. Это ядро будет равномерно распределяться по времени среди всех одновременных запросов без дополнительных затрат. Допустим, все 100 запросов поступают в один и тот же момент, каждому из которых требуется одна секунда процессорного времени. Ядро работает на всех из них, разделяя время между ними, пока все они не закончат 100 секунд спустя. Теперь рассмотрим, что произойдет, если вы разместите пул соединений впереди, который будет принимать 100 клиентских подключений, но одновременно отправлять только один запрос серверу базы данных, помещая любые запросы, поступающие, когда соединение занято, в очередь. Теперь, когда 100 запросов поступают одновременно, один клиент получает ответ в течение 1 секунды; другой получает ответ через 2 секунды, а последний клиент получает ответ через 100 секунд. Никто не должен был ждать дольше, чтобы получить ответ, пропускная способность такая же, но средняя задержка составляет 50,5 секунд, а не 100 секунд.

Реальный сервер баз данных имеет больше ресурсов, которые можно использовать параллельно, но тот же принцип действует, если они насыщены, вы только вредите, добавляя больше параллельных запросов к базе данных. Это на самом деле хуже, чем в примере, потому что с большим количеством задач у вас больше переключателей задач, повышенная конкуренция за блокировки и кэш, конфликты строк кэша L2 и L3 и многие другие проблемы, которые влияют на пропускную способность и задержку. Кроме того, в то время как высокийwork_mem настройка может помочь запросу несколькими способами, эта настройка является пределомper plan node for each connectionтаким образом, при большом количестве соединений вы должны оставить это очень маленьким, чтобы избежать очистки кэша или даже перестановки, что приводит к более медленным планам или таким вещам, как хеш-таблицы, выпадающие на диск.

Некоторые продукты баз данных эффективно встраивают пул соединений в сервер, но сообщество PostgreSQL заняло позицию, что поскольку наилучший пул соединений делается ближе к клиентскому программному обеспечению, они предоставят пользователям возможность управлять этим. У большинства пуловеров есть некоторый способ ограничить соединения с базой данных жестким числом, допуская при этом больше одновременных клиентских запросов, помещая их в очередь по мере необходимости. Это то, что вы хотите, и это должно быть сделано наtransactional основа, а не на утверждение или связь.

 03 мая 2012 г., 00:36
@kgrittn Я предполагаю, что в вашем мысленном эксперименте выше, каждый запрос выполняется за одну секунду при отсутствии других запросов?
 03 мая 2012 г., 01:01
@MichaelMior: Да, я определенно хотел поместить это туда, но пропустил это. Благодарю. Отредактировано, чтобы включить это предположение.
 03 мая 2012 г., 00:27
Все эти внешние хиппи хотят как можно быстрее создавать и разрывать соединения, а также помещать перед ними пули соединений, если они не могут достичь своего естественного высокого уровня. Мне нравится формула 2 * ncore + nspindle. Каждый процесс считается заблокированным при чтении диска.
 02 мая 2012 г., 21:41
Отличный ответ. Не могу не согласиться.
 03 мая 2012 г., 16:20
@MichaelMior: в PostgreSQL есть одна ОСprocess для каждого клиентского соединения, и это зависит от ОС для планирования. Различные процессы взаимодействуют через сегмент совместно используемой памяти, сигналы ОС (если они доступны) и самоссылающийся сокет UDP.

Ваш ответ на вопрос