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

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

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

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

Спасибо

Ответ 1

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

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

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

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

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

Ответ 2

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