使用Django的CONN_MAX_AGE设置pgbouncer的理想配置

27
我在运行一个多租户网站,在这里我想减少每个请求创建一个PostgreSQL连接的开销。Django的CONN_MAX_AGE可以实现这一点,但会产生很多空闲的 PostgreSQL 连接(8个工作进程 * 20个线程 = 160个连接)。每个连接占用10MB内存,这将消耗大量内存。
主要目的是减少连接时间开销。 因此,我的问题如下: Django 1.6 设置:
DATABASES['default'] = {
    'ENGINE':   'django.db.backends.postgresql_psycopg2',

     ....

    'PORT': '6432'
    'OPTIONS': {'autocommit': True,},
    'CONN_MAX_AGE': 300,
}

ATOMIC_REQUESTS = False   # default

Postgres:

max_connections = 100

PgBouncer:

pool_mode = session     # Can this be transaction?
max_client_conn = 400   # Should this match postgres max_connections?
default_pool_size = 20
reserve_pool_size = 5

请问您最终做了什么更新吗? - Anurag
max_client_conn - 不应该与Postgres设置匹配。 pgbouncer 应该接受这么多连接,这些连接将在池中等待处理,当 pgbouncer 真正的数据库连接被释放/未使用时。 - smido
1个回答

19

这是我用过的一个设置。

pgbouncer与gunicorn、celery等运行在同一台机器上。

pgbouncer.ini:

[databases]
<dbname> = host=<dbhost> port=<dbport> dbname=<dbname>

[pgbouncer]
: your app will need filesystem permissions to this unix socket
unix_socket_dir = /var/run/postgresql
; you'll need to configure this file with username/password pairs you plan on
; connecting with.
auth_file = /etc/pgbouncer/userlist.txt

; "session" resulted in atrocious performance for us. I think
; "statement" prevents transactions from working.
pool_mode = transaction

; you'll probably want to change default_pool_size. take the max number of
; connections for your postgresql server, and divide that by the number of
; pgbouncer instances that will be conecting to it, then subtract a few
; connections so you can still connect to PG as an admin if something goes wrong.
; you may then need to adjust min_pool_size and reserve_pool_size accordingly.
default_pool_size = 50
min_pool_size = 10
reserve_pool_size = 10
reserve_pool_timeout = 2
; I was using gunicorn + eventlet, which is why this is so high. It
; needs to be high enough to accommodate all the persistent connections we're
; going to allow from Django & other apps.
max_client_conn = 1000
...

/etc/pgbouncer/userlist.txt:

"<dbuser>" "<dbpassword>"

Django的settings.py:

...
DATABASES = {
    'default': {
        'ENGINE': 'django.contrib.gis.db.backends.postgresql_psycopg2',
        'NAME': '<dbname>',
        'USER': '<dbuser>',
        'PASSWORD': '<dbpassword>',
        'HOST': '/var/run/postgresql',
        'PORT': '',
        'CONN_MAX_AGE': None,  # Set to None for persistent connections
    }
}
...
如果我没记错的话,你可以在pgbouncer上拥有任意数量的“持久性”连接,因为pgbouncer会在Django完成对它们的使用后将服务器连接释放回池中(只要你在pool_mode中使用transactionstatement)。当Django尝试重用其持久连接时,pgbouncer会等待可用的与Postgres的连接。

1
我还发现了这个解释,非常有帮助:http://comments.gmane.org/gmane.comp.db.postgresql.pgbouncer.general/979 - Seán Hayes
1
使用pgbouncer最困难的部分是弄清楚哪些设置是针对PG,哪些是针对pgbouncer的。它们真的应该有前缀或其他标识。 - Seán Hayes
是的,在我的示例配置中使用了它。pool_mode = transaction - Seán Hayes
在pgbouncer.ini文件中,我有unix_socket_dir = /var/run/postgresql,因此在这个设置中,PG Bouncer正在使用Unix套接字。 - Seán Hayes
你需要让Django设置指向pgbouncer所在的位置。描述的设置将仅指向与pgbouncer相同的PG实例,从而绕过它。另外,据我所知,DATABASE_URL不是Django支持的设置,我假设你正在使用一些代码将其转换为标准的DATABASES dict - Seán Hayes
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接