Frage

Ich verwende Django mit Apache und mod_wsgi und PostgreSQL (alle auf demselben Host) und muss viele einfache dynamische Seitenanforderungen verarbeiten (Hunderte pro Sekunde).Ich hatte das Problem, dass der Engpass darin besteht, dass ein Django keine dauerhafte Datenbankverbindung hat und bei jeder Anfrage eine erneute Verbindung herstellt (das dauert fast 5 ms).Bei einem Benchmark habe ich festgestellt, dass ich mit dauerhafter Verbindung nahezu 500 U/s bewältigen kann, ohne dass ich nur 50 U/s erhalte.

Hat jemand einen Rat?Wie ändere ich Django so, dass eine dauerhafte Verbindung verwendet wird?Oder beschleunigen Sie die Verbindung von Python zur DB

Dank im Voraus.

War es hilfreich?

Lösung

Django 1.6 hat hinzugefügt Unterstützung für dauerhafte Verbindungen (Link zum Dokument für Django 1.9):

Persistente Verbindungen vermeiden den Aufwand, eine Verbindung zur Datenbank in jeder Anfrage wiederherzustellen.Sie werden vom Parameter conn_max_age gesteuert, der die maximale Lebensdauer einer Verbindung definiert.Sie kann für jede Datenbank unabhängig festgelegt werden.

Andere Tipps

Versuchen Sie PgBouncer - eine leichte Verbindung pooler für PostgreSQL. Features:

  • Mehrere Ebenen der Brutalität, wenn Verbindungen Drehen:
    • Sitzungspooling
    • Transaktions Pooling
    • Statement Pooling
  • Niedrige Speicheranforderungen (2k pro Verbindung Standard).

In Django Stamm, bearbeiten django/db/__init__.py und kommentieren Sie die Zeile:

signals.request_finished.connect(close_connection)

Dieses Signal Handler bewirkt, dass es aus der Datenbank nach jeder Anfrage trennen. Ich weiß nicht, was all die Nebenwirkungen, dies zu tun sein wird, aber es macht keinen Sinn, eine neue Verbindung nach jeder Anfrage zu starten; es zerstört Leistung, wie Sie bemerkt haben.

Ich benutze das jetzt, aber ich havn't eine ganze Reihe von Tests durchgeführt, wenn etwas kaputt zu sehen.

Ich weiß nicht, warum jeder denkt, das ein neues Backend benötigt oder eine spezielle Verbindung pooler oder andere komplexe Lösungen. Dies scheint sehr einfach, obwohl ich zweifle nicht daran, es gibt einige obskure gotchas sind, die sie tun dies in erster Linie gemacht - die mit mehr vernünftig behandelt werden sollten; 5ms Overhead für jede Anforderung ist ziemlich viel für einen leistungsfähigen Service, wie Sie bemerkt haben. (Es nimmt mich 150 ms . - Ich havn't herausgefunden, warum noch)

Edit: eine weitere notwendige Änderung ist in django / Middleware / transaction.py; entfernen Sie die beiden transaction.is_dirty () Tests und immer begehen () aufrufen oder Rollback (). Ansonsten wird es nicht um eine Transaktion begehen, wenn sie nur aus der Datenbank gelesen, die Schleusen öffnen lassen, die geschlossen werden soll.

Ich habe eine kleine Django Patch die Connection-Pooling von MySQL und PostgreSQL über sqlalchemy Pooling implementiert.

Das funktioniert perfekt auf die Produktion von http://grandcapital.net/ für eine lange Zeit.

Der Patch wurde geschrieben, nachdem das Thema ein bisschen googeln.

Disclaimer:. Ich habe nicht versucht

Ich glaube, Sie brauchen eine eigene Datenbank-Backend zu implementieren. Es gibt ein paar Beispiele auf dem Netz, das zeigt, wie eine Datenbank implementieren zurück mit Verbindungs-Pooling beenden.

einen Verbindungspool verwenden wäre wahrscheinlich eine gute Lösung für Sie Fall sein, da die Netzwerkverbindungen offen gehalten werden, wenn Verbindungen an den Pool zurückgegeben werden.

  • Dieser Beitrag vollbringt dies von Django Patchen (einer der Kommentare weist darauf hin, dass es besser ist, eine benutzerdefinierte zurück außerhalb des Kerns django Code beenden zu implementieren)
  • Dieser Beitrag ist eine Implementierung eines benutzerdefinierten db back-End

Beide Beiträge verwenden MySQL - vielleicht Sie ähnliche Techniken mit Postgresql zu verwenden, sind in der Lage

.

Edit:

  • Das Django Buch erwähnt Postgresql Connection Pooling, mit pgpool ( Tutorial ).
  • Jemand hat einem Patch für den psycopg2 Backend, das Connection-Pooling implementiert. Ich schlage vor, eine Kopie des bestehenden Backend in Ihrem eigenen Projekt zu schaffen und dass man das Patchen.

Ich habe einige kleine benutzerdefinierte psycopg2 Backend, die ständige Verbindung mit globalen Variablen implementiert. Damit konnte ich die amout von Anfragen pro Sekunde 350-1600 (auf sehr einfache Seite mit wenigen wählt) verbessern speichern Sie sie einfach in der Datei mit dem Namen base.py in einem beliebigen Verzeichnis (z postgresql_psycopg2_persistent) und stellen Sie in den Einstellungen

DATABASE_ENGINE projectname.postgresql_psycopg2_persistent

Hinweis !!! der Code nicht THREAD - Sie können es mit Python-Threads nicht verwenden können, weil unexpectable Ergebnisse, bei mod_wsgi bitte Prefork Daemon-Modus mit threads = 1

verwenden
# 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

Oder hier ist ein Thread sicher ein, aber Python Threads nicht verwendet mehrere Kerne, so dass Sie nicht so Leistungssteigerung wie bei vorherigen bekommen. Sie können diese mit zu einem Multi-Prozess verwenden.

# 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
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top