Pregunta

Estoy usando Django con Apache y mod_wsgi y PostgreSQL (todo el mismo host), y tengo que manejar una gran cantidad de simples solicitudes de páginas dinámicas (cientos por segundo). Me encontré con un problema que el cuello de botella es que un django no tienen conexión a la base de datos persistente y vuelve a conectar en cada uno de peticiones (que lleva cerca de 5 ms). Mientras que hace un punto de referencia que llegué con conexión persistente que puede manejar cerca de 500 r / s, mientras que sin consigo sólo el 50 r / s.

Alguien tiene algún consejo? Cómo modificar Django para utilizar la conexión persistente? O acelerar la conexión de pitón a DB

Gracias de antemano.

¿Fue útil?

Solución

Django 1.6 ha añadido conexiones persistentes apoyo (enlace a doc para django 1.9) :

  

Las conexiones persistentes evitar la sobrecarga de re-establecimiento de una   conexión a la base de datos en cada solicitud. Están controlados por el   parámetro CONN_MAX_AGE que define la vida útil máxima de una   conexión. Se puede ajustar independientemente para cada base de datos.

Otros consejos

Trate PgBouncer - pooler una conexión ligera para PostgreSQL. Características:

  • Varios niveles de brutalidad cuando rotativos conexiones:
    • agrupación de sesiones
    • Transacción puesta en común
    • Declaración de la puesta en común
  • requisitos
  • Baja memoria (2k por conexión por defecto).

En trunk de Django, editar y django/db/__init__.py comentario la línea:

signals.request_finished.connect(close_connection)

Este manejador de la señal hace que se desconecte de la base de datos después de cada petición. No sé lo que todos los efectos secundarios de hacer esto será, pero que no tiene ningún sentido para iniciar una nueva conexión después de cada petición; destruye el rendimiento, como se ha notado.

Estoy usando esto ahora, pero no te has hecho un conjunto completo de pruebas para ver si se rompe nada.

No sé qué todo el mundo piensa que esto necesita un nuevo backend o una conexión especial pooler u otras soluciones complejas. Esto parece muy simple, aunque no cabe duda de que hay algunas trampas oscuras que les hizo hacer esto en primer lugar - que debe tratarse con más sensatez; 5ms rendimiento para cada petición es bastante para un servicio de alto rendimiento, como se ha notado. (Me toma 150 ms -. Yo no te has descubierto por qué aún)

Edit: otro cambio necesario es en django / middleware / transaction.py; eliminar las pruebas de dos transaction.is_dirty () y llamar siempre a cometer () o rollback (). De lo contrario, no va a confirmar una transacción si sólo se lee de la base de datos, lo que dejará abrir cerraduras que debe ser cerrado.

I creado un pequeño Django parche que implementa la agrupación de conexiones de MySQL y PostgreSQL a través de la agrupación de sqlalchemy.

Esto funciona perfectamente en la producción de http://grandcapital.net/ durante un largo periodo de tiempo.

El parche fue escrito después de googlear un poco el tema.

exención de responsabilidad:. No he probado este

Creo que es necesario implementar un back-end base de datos personalizada. Hay algunos ejemplos en la web que muestra cómo implementar una base de datos back-end con la agrupación de conexiones.

El uso de un conjunto de conexiones, probablemente sería una buena solución para usted caso, ya que las conexiones de red se mantienen abiertas cuando las conexiones son devueltos a la piscina.

  • Este post logra el esto mediante parches Django (uno de los comentarios señala que es mejor aplicar una costumbre posterior terminar en el exterior del código del núcleo de Django)
  • Este post es una implementación del extremo posterior db una costumbre

Tanto los mensajes utilizan MySQL - tal vez usted es capaz de utilizar técnicas similares con PostgreSQL

.

Editar

  • El libro de Django menciona Postgresql la agrupación de conexiones, utilizando pgpool ( tutorial ).
  • un parche para el backend psycopg2 que implementa la agrupación de conexiones. Sugiero crear una copia de la parte final existente en su propio proyecto y parches que uno.

he hecho alguna pequeña backend psycopg2 personalizado que implementa conexión persistente mediante la variable global. Con este pude mejorar la cantidad que de solicitudes por segundo de 350 a 1600 (en la página muy simple, con pocas selecciona) Sólo tiene que guardar en el archivo llamado base.py en cualquier directorio (por ejemplo postgresql_psycopg2_persistent) y ajuste en la configuración

DATABASE_ENGINE a projectname.postgresql_psycopg2_persistent

NOTA !!! el código no es multi-hilo - no se puede utilizar con hilos de pitón a causa de los resultados unexpectable, en caso de mod_wsgi por favor utilice modo demonio prefork con hilos = 1


# Custom DB backend postgresql_psycopg2 based
# implements persistent database connection using global variable

from django.db.backends.postgresql_psycopg2.base import DatabaseError, DatabaseWrapper as BaseDatabaseWrapper, \
    IntegrityError
from psycopg2 import OperationalError

connection = None

class DatabaseWrapper(BaseDatabaseWrapper):
    def _cursor(self, *args, **kwargs):
        global connection
        if connection is not None and self.connection is None:
            try: # Check if connection is alive
                connection.cursor().execute('SELECT 1')
            except OperationalError: # The connection is not working, need reconnect
                connection = None
            else:
                self.connection = connection
        cursor = super(DatabaseWrapper, self)._cursor(*args, **kwargs)
        if connection is None and self.connection is not None:
            connection = self.connection
        return cursor

    def close(self):
        if self.connection is not None:
            self.connection.commit()
            self.connection = None

O aquí es una caja fuerte hilo, pero las discusiones pitón no utilizan múltiples núcleos, por lo que no conseguirá tales como aumento de rendimiento con el anterior. Puede utilizar éste con un solo proceso de múltiples también.

# Custom DB backend postgresql_psycopg2 based
# implements persistent database connection using thread local storage
from threading import local

from django.db.backends.postgresql_psycopg2.base import DatabaseError, \
    DatabaseWrapper as BaseDatabaseWrapper, IntegrityError
from psycopg2 import OperationalError

threadlocal = local()

class DatabaseWrapper(BaseDatabaseWrapper):
    def _cursor(self, *args, **kwargs):
        if hasattr(threadlocal, 'connection') and threadlocal.connection is \
            not None and self.connection is None:
            try: # Check if connection is alive
                threadlocal.connection.cursor().execute('SELECT 1')
            except OperationalError: # The connection is not working, need reconnect
                threadlocal.connection = None
            else:
                self.connection = threadlocal.connection
        cursor = super(DatabaseWrapper, self)._cursor(*args, **kwargs)
        if (not hasattr(threadlocal, 'connection') or threadlocal.connection \
             is None) and self.connection is not None:
            threadlocal.connection = self.connection
        return cursor

    def close(self):
        if self.connection is not None:
            self.connection.commit()
            self.connection = None
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top