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

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

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

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

Спасибо

2 ответа

Решение

Помимо экономии накладных расходов на подключение и отключение, когда это делается в противном случае при каждом запросе, диспетчер соединений может направлять большое количество клиентских подключений на небольшое количество реальных подключений к базе данных. В 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 настройка может помочь в запросах несколькими способами, эта настройка является лимитом на узел плана для каждого соединения, поэтому при большом количестве соединений вам нужно оставить это очень маленькое значение, чтобы избежать очистки кеша или даже привести к перестановке, что приводит к более медленные планы или такие вещи, как хэш-таблицы, выплескивающиеся на диск.

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

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

Другие вопросы по тегам