I'm running a multi-tennant website, where I would like to reduce the overhead of creating a PostgreSQL connection per request. Django's CONN_MAX_AGE allows this, at the expense of creating a lot of open idle connections to PostgreSQL (8 workers * 20 threads = 160 connections). With 10MB per connection, this consumes a lot of memory.
The main purpose is reducing connection-time overhead. Hence my questions:
- Which setup should I use for such solution? (PgBouncer?)
- Can I use 'transaction' pool mode with Django?
- Would I be better off using something like: https://github.com/kennethreitz/django-postgrespool instead of Django's pooling?
Django 1.6 settings:
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
Here's a setup I've used.
pgbouncer running on same machine as gunicorn, celery, etc.
pgbouncer.ini:
/etc/pgbouncer/userlist.txt:
Django settings.py:
If I remember correctly, you can basically have any number of "persistent" connections to pgbouncer, since pgbouncer releases server connections back to the pool when Django is done with them (as long as you're using
transaction
orstatement
forpool_mode
). When Django tries to reuse its persistent connection, pgbouncer takes care of waiting for a usable connection to Postgres.