Question

J'utilise django avec apache et mod_wsgi et PostgreSQL (tous sur la même hôte), et je dois gérer un grand nombre de requêtes de pages dynamiques simples (des centaines par seconde). Je confronté à problème que le goulot d'étranglement est que django ne pas connexion persistante et reconnecte sur chaque demande (qui prend près de 5ms). Tout en faisant une référence que je suis arrivé que, avec connexion persistante que je peux gérer près de 500 r / s alors sans que je ne reçois que 50 r / s.

Quelqu'un a des conseils? Comment modifier django d'utiliser une connexion persistante? Ou accélérer la connexion de python à DB

Merci d'avance.

Était-ce utile?

La solution

Django 1.6 a ajouté connexions persistantes support (lien vers doc pour django 1.9) :

  

Les connexions persistantes éviter les frais généraux de rétablir un   connexion à la base de chaque requête. Ils sont contrôlés par le   CONN_MAX_AGE paramètre qui définit la durée de vie maximale d'un   lien. Il peut être réglé indépendamment pour chaque base de données.

Autres conseils

pgbouncer - un concentrateur de connexion léger pour PostgreSQL. Caractéristiques:

  • Plusieurs niveaux de brutalité lorsque les connexions en rotation:
    • la mise en commun session
    • la mise en commun des transactions
    • la mise en commun Déclaration
  • besoins en mémoire faible (2k par connexion par défaut).

Dans le tronc Django, modifier django/db/__init__.py et commentez la ligne:

signals.request_finished.connect(close_connection)

Ce gestionnaire de signal amène à se déconnecter de la base de données après chaque demande. Je ne sais pas ce que tous les effets secondaires de ce fait sera, mais il ne fait pas de sens pour commencer une nouvelle connexion après chaque demande; il détruit la performance, comme vous l'avez remarqué.

J'utilise maintenant, mais je havn't fait un ensemble complet de tests pour voir si les pauses quoi que ce soit.

Je ne sais pas pourquoi tout le monde pense que cela a besoin d'un nouveau back-end ou un concentrateur de connexion spéciale ou d'autres solutions complexes. Cela semble très simple, mais je ne doute pas qu'il y ait des pièges obscurs qui les ont fait le font en premier lieu - qui devrait être traitée de façon plus sensiblement; les frais généraux 5ms pour chaque demande est beaucoup pour un service de haute performance, comme vous l'avez remarqué. (Il me prend 150ms -. Je havn't compris pourquoi encore)

Edit: un autre changement nécessaire est en django / middleware / transaction.py; retirer les deux tests transaction.is_dirty () et toujours appeler commit () ou rollback (). Dans le cas contraire, il ne commettra pas une transaction si elle en lecture seule de la base de données, ce qui laissera les verrous ouverts qui doivent être fermées.

J'ai créé un petit correctif Django qui implémente la mise en commun de connexion de MySQL et PostgreSQL via la mise en commun de sqlalchemy.

Cela fonctionne parfaitement sur la production de http://grandcapital.net/ pendant une longue période de temps.

Le patch a été écrit après googler le sujet un peu.

Disclaimer:. Je ne l'ai pas essayé

Je crois que vous avez besoin de mettre en œuvre une extrémité arrière de base de données personnalisée. Il y a quelques exemples sur le Web qui montre comment implémenter une base de données fin de retour avec le pool de connexions.

L'utilisation d'un pool de connexion serait probablement une bonne solution pour vous cas, les connexions réseau sont maintenues ouvertes lorsque les connexions sont retournées à la piscine.

  • Ce message Accomplit ce par rapiéçage Django (un des commentaires souligne qu'il est préférable de mettre en œuvre une coutume back-end en dehors du code de django de base)
  • Ce poste est une implémentation de back-end de coutume

Les deux messages utilisent MySQL - peut-être vous êtes en mesure d'utiliser des techniques similaires avec Postgresql

.

Modifier

  • Le Livre Django mentionne la mise en commun de connexion Postgresql, en utilisant pgpool ( tutoriel ).
  • Quelqu'un a posté un patch pour le backend psycopg2 qui implémente la mise en commun de connexion. Je suggère la création d'une copie de la fin existante en arrière dans votre propre projet et patcher celui-là.

J'ai fait un petit backend psycopg2 personnalisé qui implémente une connexion persistante à l'aide variable globale. Avec cela, je suis en mesure d'améliorer la amout des demandes par seconde de 350 à 1600 (à la page très simple avec quelques Selects) Il suffit de l'enregistrer dans le fichier appelé base.py dans un répertoire (par exemple postgresql_psycopg2_persistent) et définir dans les paramètres

DATABASE_ENGINE à projectname.postgresql_psycopg2_persistent

NOTE !!! le code est threadsafe - vous ne pouvez pas l'utiliser avec des fils de python en raison de résultats unexpectable, en cas de mod_wsgi s'il vous plaît utiliser le mode démon prefork avec des fils = 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

Ou ici est un thread-safe un, mais des fils de python ne pas utiliser plusieurs cœurs, donc vous ne serez pas cette amélioration des performances comme avec un précédent. Vous pouvez utiliser celui-ci avec plusieurs processus aussi.

# 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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top