static_root postgres example app python django postgresql connection-pooling pgbouncer

python - postgres - ¿Cómo ayuda pgBouncer a acelerar Django?



procfile heroku python (2)

Además de ahorrar la sobrecarga de conectar y desconectar cuando esto se hace de otra manera en cada solicitud, un agrupador de conexiones puede canalizar una gran cantidad de conexiones de clientes a una pequeña cantidad de conexiones de base de datos reales. En PostgreSQL, el número óptimo de conexiones de base de datos activas suele estar en algún lugar alrededor de ((2 * core_count) + Effective_spindle_count) . Por encima de este número, tanto el rendimiento como la latencia empeoran.

A veces la gente dice "Quiero apoyar a 2000 usuarios, con un tiempo de respuesta rápido". Está bastante garantizado que si intenta hacer eso con 2000 conexiones de base de datos reales, el rendimiento será horrible. Si tiene una máquina con cuatro procesadores de cuatro núcleos y el conjunto de datos activo está completamente almacenado en caché, verá un rendimiento mucho mejor para esos 2000 usuarios al canalizar las solicitudes a través de aproximadamente 35 conexiones de base de datos.

Para entender por qué eso es cierto, este experimento mental debería ayudar. Considere una máquina de servidor de base de datos hipotética con un solo recurso para compartir: un solo núcleo. Este núcleo se dividirá en el mismo tiempo entre todas las solicitudes concurrentes sin sobrecarga. Digamos que 100 solicitudes entran todas en el mismo momento, cada una de las cuales necesita un segundo de tiempo de CPU. El núcleo funciona en todos ellos, dividiendo el tiempo entre ellos hasta que todos terminan 100 segundos después. Ahora considere qué sucede si coloca un grupo de conexiones en frente que aceptará 100 conexiones de clientes pero solo realiza una solicitud a la vez al servidor de la base de datos, poniendo todas las solicitudes que llegan mientras la conexión está ocupada en una cola. Ahora que cuando llegan 100 solicitudes al mismo tiempo, un cliente recibe una respuesta en 1 segundo; otro recibe una respuesta en 2 segundos, y el último cliente recibe una respuesta en 100 segundos. Nadie tuvo que esperar más tiempo para obtener una respuesta, el rendimiento es el mismo, pero la latencia promedio es de 50,5 segundos en lugar de 100 segundos.

Un servidor de base de datos real tiene más recursos que se pueden usar en paralelo, pero el mismo principio se sostiene: una vez que están saturados, solo afecta las cosas agregando más solicitudes de base de datos concurrentes. En realidad, es peor que en el ejemplo, porque con más tareas tiene más interruptores de tareas, mayor contención para bloqueos y caché, contención de línea de caché L2 y L3, y muchos otros problemas que afectan tanto el rendimiento como la latencia. Además de eso, mientras que una configuración de work_mem alta puede ayudar a una consulta de varias maneras, esa configuración es el límite por nodo del plan para cada conexión , por lo que con una gran cantidad de conexiones debe dejar esto muy pequeño para evitar el vaciado de caché. o incluso llevar a un intercambio, lo que lleva a planes más lentos o cosas como tablas hash que se derraman en el disco.

Algunos productos de base de datos construyen efectivamente un conjunto de conexiones en el servidor, pero la comunidad PostgreSQL ha tomado la posición de que, dado que la mejor agrupación de conexiones se realiza más cerca del software cliente, dejarán a los usuarios administrar esto. La mayoría de los agrupadores tendrán alguna forma de limitar las conexiones de la base de datos a un número fijo, al tiempo que permiten más solicitudes de clientes concurrentes que eso, y las ponen en cola según sea necesario. Esto es lo que desea, y debe hacerse de forma transaccional , no por declaración o conexión.

Tengo algunos comandos de gestión basados ​​en gevent. Como mi comando de administración hace miles de solicitudes, puedo convertir todas las llamadas de socket en llamadas no bloqueadas usando Gevent. Esto realmente acelera mi aplicación ya que puedo hacer solicitudes simultáneamente.

Actualmente el cuello de botella en mi aplicación parece ser Postgres. Parece que esto se debe a que la biblioteca Psycopg que se usa para conectarse a Django está escrita en C y no admite conexiones asíncronas.

También he leído que usar pgBouncer puede acelerar Postgres en 2X. Esto suena bien, pero sería genial si alguien pudiera explicar cómo funciona y ayuda pgBouncer.

Gracias


PgBouncer reduce la latencia en el establecimiento de conexiones al actuar como un proxy que mantiene un grupo de conexiones. Esto puede ayudar a acelerar su aplicación si está abriendo muchas conexiones de corta duración a Postgres. Si solo tiene un pequeño número de conexiones, no verá una gran ganancia.