Django的持久数据库连接Django的持久数据库连接(Django persistent dat

2019-06-14 09:42发布

我使用的是Apache和mod_wsgi的和PostgreSQL(所有同一台主机上)Django的,我需要处理很多简单的动态页面请求(每秒数百个)的。 我面临的问题,瓶颈是一个Django不具有持久的数据库连接并重新连接上的每个请求(即需要近5毫秒)。 虽然做基准我得到了持续性方面,我可以接近500 R / S处理,而没有我只得到50 R / S。

任何人有什么建议吗? 如何修改Django的使用持续连接? 或加速从蟒蛇DB连接

提前致谢。

Answer 1:

Django的1.6增加了持久连接支持(文档链接Django的1.9) :

持久连接避免重新建立在每个请求到数据库的连接的开销。 他们通过定义一个连接的最大寿命CONN_MAX_AGE参数控制。 它可以为每个独立的数据库进行设置。



Answer 2:

尝试PgBouncer - PostgreSQL的一个轻量级的连接池。 特征:

  • 旋转连接时残酷的几个层次:
    • 会话池
    • 交易池
    • 语句池
  • 内存要求低(每默认连接2K)。


Answer 3:

在Django的树干,编辑django/db/__init__.py并注释掉行:

signals.request_finished.connect(close_connection)

此信号处理器使得它从每一个请求后与数据库断开连接。 我不知道所有的这样做将是副作用,但它没有任何意义,开始每次请求后一个新的连接; 它破坏性能,因为你已经注意到了。

现在我用这个,但我没有带做了全套的测试,看看是否有任何中断。

我不知道为什么每个人都认为这需要一个新的后端或特殊的连接池或者其他复杂的解决方案。 这似乎很简单,但我不怀疑有一些让他们在第一时间做一些不起眼的陷阱 - 这应该更理智地处理; 5ms的开销为每个请求是相当多了一个高性能的服务,因为你已经注意到了。 (我花了150毫秒 -我没有带想通了,为什么呢。)

编辑:另一种必要的变化是在Django /中间件/ transaction.py; 拆下两个transaction.is_dirty()测试,并始终调用commit()或rollback()。 否则,如果只是从数据库中,这将离开锁打开应该关闭读也不会提交事务。



Answer 4:

我创建了一个小型的Django补丁是通过SQLAlchemy的池实现MySQL和PostgreSQL的连接池。

这工作完全在生产http://grandcapital.net/为很长一段时间。

该补丁google搜索话题位之后写的。



Answer 5:

免责声明:我没有尝试这样做。

我相信你需要实现自定义数据库后端。 有迹象表明,展示了如何实现数据库回来连接池结束在网络上的几个例子。

使用连接池可能会是你的情况下很好的解决方案,因为网络连接保持打开状态时,连接返回到池中。

  • 这篇文章通过修补Django的完成这个(一个评论指出,这是更好地实现定制后端的核心Django的代码外)
  • 这个职位是一个自定义数据库后端的实现

这两个职位使用MySQL - 也许你可以使用类似的技术在PostgreSQL。

编辑:

  • Django的书中提到PostgreSQL的连接池,使用pgpool ( 教程 )。
  • 有人发布一个补丁用于实现连接池的psycopg2后端。 我建议您在自己的项目创建现有后端的副本,并修补一个。


Answer 6:

我做了使用全局变量实现永久连接一些较小的定制psycopg2后端。 有了这个,我能提高每秒请求数从350到1600(除了少数选择非常简单的网页)的大写金额只需将其称为保存在文件中base.py在任何目录(如postgresql_psycopg2_persistent),并在设置中设置

DATABASE_ENGINE到projectname.postgresql_psycopg2_persistent

注意!!! 代码不是线程安全的-你不能因为不可预料的结果蟒蛇线程使用它,在mod_wsgi的情况下,请使用带有线程= 1 prefork的守护模式


# 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

或者这里是一个线程安全的,但蟒蛇线程不使用多个内核,这样你就不会得到这样的性能提升与前一个。 您可以使用这一个多过程中的一个了。

# 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


文章来源: Django persistent database connection