Django django.db.utils.OperationalError:致命:剩余连接槽保留用于非复制超级用户连接

问题描述 投票:0回答:3
  File "/usr/local/lib/python3.7/dist-packages/psycopg2/__init__.py", line 126, in connect    conn = _connect(dsn, connection_factory=connection_factory, **kwasync)
django.db.utils.OperationalError: FATAL:  remaining connection slots are reserved for non-replication superuser connections

根据 Postgres 文档,当 Django 与 Postgres DB 建立的连接数量超过默认连接限制时,就会发生此错误。

  • 我想知道 Django 启动/打开大量与数据库的连接的原因是什么。
  • 我想知道我们可以采取哪些最佳实践来防止出现异常。
  • 如何增加Postgres的默认连接限制?
#settings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'xxxxx',
        'USER': 'xxxxx',
        'PASSWORD':'xxxxx',
        'HOST':'localhost',
        'PORT':'5432',
    }
django postgresql django-models django-views postgresql-9.1
3个回答
1
投票

我相信这是由于 Django 框架不进行数据库池而发生的。查看 Django 文档(https://docs.djangoproject.com/en/3.2/ref/databases/#transaction-pooling-and-server-side-cursors)我可以找到对用户 pgBouncer 的建议(http: //www.pgbouncer.org/)来处理这个问题。


0
投票

这是一个使用线程和中间件的 Django PostgreSQL 解决方案。

数据库视图 您需要在数据库中创建一个视图 格式:应用程序_视图名称 我称我的为“configuration_terminate_idle_connections”

SELECT row_number() OVER (PARTITION BY true::boolean) AS id,
pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE 
datname = 'database_name'
    AND pid <> pg_backend_pid()
    AND state = 'idle'
    AND extract(epoch from (current_timestamp - query_start)) > 15*60;

型号

class terminate_idle_connections(models.Model):
    pg_terminate_backend = models.BooleanField(default=True)

    class Meta:
        ordering = ['id']
        managed = False
        db_table = 'appname_terminate_idle_connections'
        verbose_name_plural = "Database Terminate Idle Connections"

Admin(通过/admin手动运行)

class terminate_idle_connectionsView(admin.ModelAdmin):
    list_display = ('id', 'pg_terminate_backend')             


admin.site.register(terminate_idle_connections,terminate_idle_connectionsView)

设置.py 设置为你想要的

DB_MAX_CONNECTIONS = 700
DB_MAX_IDLE_CONNECTIONS = 150

中间件(提交请求时运行它) 我在 my_project_folder/middleware 中调用了我的“DbConnections.py”,与 settings.py 文件位于同一位置 完整文件路径:“my_project_folder/middleware/DbConnections.py”

from django.conf import settings
from appname.models import *

class DbConnections:
    
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        response = self.get_response(request)
        return response
    # PROCESSED BEFORE THE REQUESTED VIEW FUNCTION OR CLASS
    def process_view(self, request, view_func, view_args, view_kwargs):
        if settings.DEBUG: print("\nRemove idle Connections")
        dbConection= database_activity.objects.all()
        dbConectionCountAll= dbConection.count()
        dbConectionCountIdle= dbConection.filter(state="idle").count()
        if settings.DEBUG: print("    - Allowed Connections:",settings.DB_MAX_CONNECTIONS, "Actual Connections:",dbConectionCountAll)
        if settings.DEBUG: print("    - Allowed Idle Connections:",settings.DB_MAX_IDLE_CONNECTIONS, "Actual Idle Connections:",dbConectionCountIdle)
        if dbConectionCountAll >= settings.DB_MAX_CONNECTIONS or dbConectionCountIdle >= settings.DB_MAX_IDLE_CONNECTIONS:
            terminateIdelConections = terminate_idle_connections.objects.all()
            if settings.DEBUG: print("\n    - Terminated Connections:", terminateIdelConections.count(),"\n")

设置中间件

MIDDLEWARE = [
    'my_project_folder.Middleware.DbConnections.DbConnections',
    'django.middleware.security.SecurityMiddleware',
    ...
]

查看线程(在计时器上运行) 在您的应用程序views.py文件中:

import threading
from django.conf import settings
from appname.models import *

def removeIdleDbConnections():
    threading.Timer(900, removeIdleDbConnections).start()


    # REMOVE IDLE CONNECTIONS
    try:
        dbConection= database_activity.objects.all()
        dbConectionCountAll= database_activity.objects.all().count()
        dbConectionCountIdle= database_activity.objects.filter(state="idle").count()
        if dbConectionCountAll >= settings.DB_MAX_CONNECTIONS or dbConectionCountIdle >= settings.DB_MAX_IDLE_CONNECTIONS:
            terminateIdelConections = terminate_idle_connections.objects.all()
            if settings.DEBUG: print("Terminated Connections:", terminateIdelConections.count())
    except:
        pass

removeIdleDbConnections()

0
投票

我在使用 Postgresql 数据库的 Django 项目中使用

concurrent
时遇到了类似的问题。我总是耗尽连接(要么与你有相同的操作错误,要么有一些变化)。

我的解决方案是使用包

django-db-connection-pool
。它对我来说是开箱即用的,似乎解决了 django 中缺少数据库池的问题。

只需安装软件包:

pip install django-db-connection-pool[postgresql]

settings.py
中的后端引擎替换为

DATABASES = {
    'default': {
        'ENGINE': 'dj_db_conn_pool.backends.postgresql'
    }
}

如果需要,您还可以使用

POOL_OPTIONS
添加一些选项(请参阅包文档)。

© www.soinside.com 2019 - 2024. All rights reserved.