django - postgres - heroku python
Configuraciones ideales para pgbouncer con CONN_MAX_AGE de Django (1)
Estoy ejecutando un sitio web multi-tennant, donde me gustaría reducir la sobrecarga de crear una conexión PostgreSQL por solicitud. ConN_MAX_AGE de Django permite esto, a costa de crear una gran cantidad de conexiones inactivas abiertas para PostgreSQL (8 trabajadores * 20 subprocesos = 160 conexiones). Con 10MB por conexión, esto consume mucha memoria.
El objetivo principal es reducir la sobrecarga de tiempo de conexión. De ahí mis preguntas:
- ¿Qué configuración debo usar para dicha solución? (PgBouncer?)
- ¿Puedo usar el modo de grupo ''transacción'' con Django?
- ¿Estaría mejor usando algo como: https://github.com/kennethreitz/django-postgrespool lugar de la agrupación de Django?
Configuraciones de 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
Aquí hay una configuración que he usado.
pgbouncer corriendo en la misma máquina que Gunicorn, apio, etc.
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
}
}
...
Si recuerdo correctamente, básicamente puedes tener cualquier número de conexiones "persistentes" con pgbouncer, ya que pgbouncer libera las conexiones del servidor a la agrupación cuando Django termina con ellas (siempre y cuando pool_mode
transaction
o la statement
para pool_mode
). Cuando Django intenta reutilizar su conexión persistente, pgbouncer se encarga de esperar una conexión utilizable a Postgres.