Вопрос

Я использую django с apache, mod_wsgi и PostgreSQL (все на одном хостинге), и мне нужно обрабатывать множество простых запросов динамической страницы (сотни в секунду).Я столкнулся с проблемой, что узким местом является то, что django не имеет постоянного подключения к базе данных и переподключается при каждом запросе (что занимает около 5 мс).Выполняя тест, я получил, что при постоянном соединении я могу обрабатывать около 500 об / с, в то время как без него я получаю только 50 об / с.

У кого-нибудь есть какой-нибудь совет?Как изменить django, чтобы использовать постоянное соединение?Или ускорить соединение с python к БД

Заранее благодарю.

Это было полезно?

Решение

Джанго 1.6 добавил поддержка постоянных подключений (ссылка на документ для django 1.9):

Постоянные соединения позволяют избежать накладных расходов на повторное установление подключение к базе данных в каждом запросе.Они управляются параметром CONN_MAX_AGE, который определяет максимальное время жизни соединения .Он может быть установлен независимо для каждой базы данных.

Другие советы

Попробуй ПгБоунсер - облегченный пул подключений для PostgreSQL.Характеристики:

  • Несколько уровней жестокости при вращении соединений:
    • Объединение сеансов
    • Объединение транзакций
    • Объединение утверждений
  • Низкие требования к памяти (по умолчанию 2 кб на подключение).

В магистрали Django редактировать django/db/__init__.py и закомментируйте строку:

signals.request_finished.connect(close_connection)

Этот обработчик сигнала заставляет его отключаться от базы данных после каждого запроса.Я не знаю, каковы будут все побочные эффекты от этого, но нет никакого смысла запускать новое соединение после каждого запроса;как вы уже заметили, это снижает производительность.

Я использую это сейчас, но я еще не провел полный набор тестов, чтобы увидеть, не сломается ли что-нибудь.

Я не знаю, почему все думают, что для этого нужен новый серверный сервер, или специальный пул подключений, или другие сложные решения.Это кажется очень простым, хотя я не сомневаюсь, что есть какие-то неясные ошибки, которые заставили их сделать это в первую очередь - с которыми следует разобраться более разумно;как вы заметили, накладные расходы в 5 мс на каждый запрос - это довольно много для высокопроизводительного сервиса.(Это забирает меня 150 мс-- Я еще не понял почему.)

Редактировать:еще одно необходимое изменение заключается в django/middleware/transaction.py;удалите два теста transaction.is_dirty() и всегда вызывайте commit() или rollback().В противном случае он не зафиксирует транзакцию, если будет только считывать данные из базы данных, что оставит открытыми блокировки, которые должны быть закрыты.

Я создал небольшой Патч Django это реализует объединение MySQL и PostgreSQL в пул соединений через sqlalchemy pooling.

Это отлично работает при производстве http://grandcapital.net/ в течение длительного периода времени.

Патч был написан после того, как я немного погуглил тему.

Отказ от ответственности:Я этого не пробовал.

Я считаю, что вам нужно реализовать серверную часть пользовательской базы данных.В Интернете есть несколько примеров, показывающих, как реализовать серверную часть базы данных с объединением в пул соединений.

Использование пула подключений, вероятно, было бы хорошим решением в вашем случае, поскольку сетевые подключения остаются открытыми, когда соединения возвращаются в пул.

  • Этот пост достигает этого путем исправления Django (в одном из комментариев указывается, что лучше реализовать пользовательский сервер вне основного кода django)
  • Этот пост является реализацией пользовательского серверного модуля базы данных

Оба сообщения используют MySQL - возможно, вы можете использовать аналогичные методы с Postgresql.

Редактировать:

  • В книге Django упоминается пул соединений Postgresql, использующий пгпул (Учебник).
  • Кто-то опубликовал заплатка для серверной части psycopg2, которая реализует объединение в пул соединений.Я предлагаю создать копию существующей серверной части в вашем собственном проекте и исправить ее.

Я создал небольшой пользовательский сервер psycopg2, который реализует постоянное соединение с использованием глобальной переменной.Благодаря этому я смог увеличить количество запросов в секунду с 350 до 1600 (на очень простой странице с несколькими выборками) Просто сохраните это в файле под названием base.py в любом каталоге (например,postgresql_psycopg2_persistent) и установить в настройках

DATABASE_ENGINE для имяпроекта.postgresql_psycopg2_persistent

ОБРАТИТЕ ВНИМАНИЕ!!!код не является потокобезопасным - вы не можете использовать его с потоками python из-за неожиданных результатов, в случае mod_wsgi, пожалуйста, используйте режим демона предварительной обработки с потоками = 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

Или вот потокобезопасный вариант, но потоки python не используют несколько ядер, поэтому вы не получите такого повышения производительности, как в предыдущем.Вы также можете использовать этот вариант с многопроцессорным.

# 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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top