sql >> Base de Datos >  >> RDS >> PostgreSQL

Una guía para usar pgBouncer para PostgreSQL

Al comenzar a leer PostgreSQL, verá la línea:“El servidor PostgreSQL puede manejar múltiples conexiones simultáneas de clientes. Para lograr esto, inicia (“bifurcaciones”) un nuevo proceso para cada conexión. A partir de ese momento, el cliente y el nuevo proceso del servidor se comunican sin la intervención del proceso postgres original. Por lo tanto, el proceso del servidor maestro siempre se está ejecutando, esperando las conexiones del cliente, mientras que los procesos del cliente y del servidor asociado van y vienen.

Brillante idea. Y, sin embargo, significa que cada nueva conexión genera un nuevo proceso, reserva RAM y posiblemente se vuelve demasiado pesado con múltiples sesiones. Para evitar problemas, postgres tiene una configuración max_connections con 100 conexiones predeterminadas. Por supuesto, puede aumentarlo, pero tal acción requeriría reiniciar (pg_settings.context es 'postmaster'):

t=# select name,setting,short_desc,context from pg_settings where name = 'max_connections';
-[ RECORD 1 ]--------------------------------------------------
name       | max_connections
setting    | 100
short_desc | Sets the maximum number of concurrent connections.
context    | postmaster
Algunas lecturas emocionantes Uso de PgBouncer ¿Cuál es el punto de rebotar? PgBouncer Changelog Publicaciones que contienen 'pgbouncer' en Stack Overflow Publicaciones etiquetadas como 'pgbouncer' en 2ndQuadrant

E incluso después de aumentar, en algún momento es posible que necesite más conexiones (por supuesto, con urgencia, como siempre, en la ejecución de prod). ¿Por qué aumentarlo es tan incómodo? Porque si fuera cómodo, probablemente terminaría con un aumento espontáneo descontrolado del número hasta que el grupo comience a retrasarse. Lo que significa que las conexiones antiguas son más lentas, por lo que toman más tiempo, por lo que necesita aún más y más nuevas. Para evitar tal posible avalancha y agregar algo de flexibilidad, tenemos superuser_reserved_connections, para poder conectarse y solucionar problemas con SU cuando se agota max_connections. Y obviamente vemos la necesidad de algún agrupador de conexiones. Como queremos que los nuevos candidatos de conexión esperen en una cola en lugar de fallar con una excepción FATAL:lo siento, ya hay demasiados clientes y no arriesgar al administrador de correos.

La agrupación de conexiones se ofrece en algún nivel por muchos "clientes" populares. Podrías usarlo con jdbc durante bastante tiempo. Recientemente, node-postgres ofreció su propio node-pg-pool. Más o menos la implementación es simple (como es la idea):pooler inicia las conexiones hacia la base de datos y las mantiene. El cliente que se conecta a db solo obtiene una conexión existente "compartida" y, después de cerrarla, la conexión vuelve al grupo. También tenemos un software mucho más sofisticado, como pgPool. Y, sin embargo, pgbouncer es una opción extremadamente popular para la tarea. ¿Por qué? Porque solo hace la parte de la agrupación, pero lo hace bien. Es gratis. Es bastante simple de configurar. Y lo encontrará en la mayoría de los proveedores de servicios más importantes según lo recomendado o usado, por ejemplo, citusdata, aws, heroku y otros recursos muy respetados.

Así que echemos un vistazo más de cerca a lo que puede y cómo lo usa. En mi configuración, uso pool_mode =transacción predeterminada (sección [pgbouncer]), que es una opción muy popular. De esta forma, no solo ponemos en cola las conexiones que exceden max_connections, sino que reutilizamos las sesiones sin esperar a que se cierre la conexión anterior:

[databases]
mon = host=1.1.1.1 port=5432 dbname=mon
mons = host=1.1.1.1 port=5432 dbname=mon pool_mode = session pool_size=2 max_db_connections=2
monst = host=1.1.1.1 port=5432 dbname=mon pool_mode = statement
[pgbouncer]
listen_addr = 1.1.1.1
listen_port = 6432
unix_socket_dir = /tmp
auth_file = /pg/pgbouncer/bnc_users.txt
auth_type = hba
auth_hba_file = /pg/pgbouncer/bnc_hba.conf
admin_users = root vao
pool_mode = transaction
server_reset_query = RESET ALL; --DEALLOCATE ALL; /* custom */
ignore_startup_parameters = extra_float_digits
application_name_add_host = 1
max_client_conn = 10000
autodb_idle_timeout = 3600
default_pool_size = 100
max_db_connections = 100
max_user_connections = 100
#server_reset_query_always = 1 #uncomment if you want older global behaviour

Breve resumen de las configuraciones y consejos y trucos más populares:

  • server_reset_query es muy útil e importante. En el modo de agrupación de sesiones, "borra" los "artefactos" de la sesión anterior. De lo contrario, tendría problemas con los mismos nombres para declaraciones preparadas, configuraciones de sesión que afectan las próximas sesiones, etc. El valor predeterminado es DESCARTAR TODO, que "restablece" todos los estados de sesión. Sin embargo, puede elegir valores más sofisticados, por ejemplo, RESTABLECER TODO; DESASIGNAR TODO; olvidarse solo de SET SESSION y declaraciones preparadas, manteniendo tablas y planes TEMP "compartidos". O lo contrario:es posible que desee hacer que las declaraciones preparadas sean "globales" desde cualquier sesión. Tal configuración es factible, aunque arriesgada. Tienes que hacer que pgbouncer reutilice la sesión para todos (haciendo así un tamaño de grupo muy pequeño o avalanchando las sesiones), lo cual no es completamente confiable. De todos modos, es una habilidad útil. Especialmente en configuraciones en las que desea que las sesiones del cliente cambien eventualmente (no inmediatamente) a la configuración de sesión agrupada configurada. Un punto muy importante aquí es el modo de grupo de sesiones. Antes de 1.6, esta configuración también afectaba a otros modos de grupo, por lo que si confiaba en ella, debe usar la nueva configuración server_reset_query_always =1. Probablemente, en algún momento, las personas querrán que server_reset_query sea aún más flexible y configurable por par de db/usuario ( y client_reset_query en su lugar). Pero a partir de la redacción actual, marzo de 2018, no es una opción. La idea detrás de hacer que esta configuración sea válida de forma predeterminada solo para el modo de sesión fue que, si comparte la conexión a nivel de transacción o estado de cuenta, no puede confiar en la configuración de la sesión en absoluto.

  • Tipo_autenticación =hba. Antes de 1.7, el gran problema con pgbouncer era la ausencia de autenticación basada en host:"firewall postgres". Por supuesto, todavía lo tenía para la conexión del clúster de Postgres, pero pgbouncer estaba "abierto" para cualquier fuente. Ahora podemos usar el mismo hba.conf para limitar las conexiones para host/db/usuario según la red de conexión.

  • connect_query no se realiza en cada "conexión" de cliente a pgbouncer, sino cuando pgbouncer se conecta a una instancia de Postgres. Por lo tanto, no puede usarlo para configurar o anular la configuración "predeterminada". En el modo de sesión, otras sesiones no se afectan entre sí y, al desconectarse, restablecer la consulta descarta todo, por lo que no necesita meterse con él. En el modo de agrupación de transacciones, esperaría usarlo para la configuración que anula la configuración errónea de otras sesiones, pero lamentablemente no funcionará. P.ej. desea compartir una declaración preparada entre "sesiones" en el modo de transacción, por lo que establece algo como

    trns = dbname=mon pool_mode = transaction connect_query = 'do $$ begin raise warning $w$%$w$, $b$new connection$b$; end; $$; prepare s(int) as select $1;'

    y, de hecho, cada nuevo cliente ve las declaraciones preparadas (a menos que haya dejado server_reset_query_always activado, por lo que pgbouncer lo descarta al confirmar). Pero si algún cliente ejecuta DISCARD s; en su sesión, afecta a todos los clientes en esta conexión y los nuevos clientes que se conecten ya no verán declaraciones preparadas. Pero si desea tener alguna configuración inicial para las conexiones de postgres provenientes de pgbouncer, entonces este es el lugar.

  • application_name_add_host se agregó en 1.6, tiene una limitación similar. "Coloca" la IP del cliente en application_name, por lo que puede obtener fácilmente su fuente de consulta incorrecta, pero se anula fácilmente con el simple set application_name TO 'no fui yo'; Aún así, puede "curar" esto usando vistas:siga esta publicación para hacerse una idea o incluso use estas breves instrucciones. Básicamente, la idea es mostrar a los clientes; mostrará la IP de los clientes, por lo que puede consultarla directamente desde la base de datos de pgbouncer en cada selección de pg_stat_activity para verificar si se restableció. Pero, por supuesto, usar una configuración simple es mucho más simple y acogedor. Aunque no garantiza el resultado...

  • pool_mode se puede especificar de forma predeterminada, por base de datos y por usuario, lo que lo hace muy flexible. Los modos de mezcla hacen que pgbouncer sea extremadamente efectivo para agrupar. Esta es una característica poderosa, pero hay que tener cuidado al usarla. A menudo, los usuarios lo usan sin comprender los resultados de combinaciones absolutamente atómicas de por transacción/por sesión/por usuario/por base de datos/configuraciones globales que funcionan de manera diferente para el mismo usuario o base de datos, debido a los diferentes modos de agrupación con pgbouncer. Esta es la caja de fósforos que no le das a los niños sin supervisión. También muchas otras opciones son configurables por defecto y por db y por usuario.

  • No lo tome literalmente, pero puede "comparar" diferentes secciones de ini con SET y ALTER:SET LOCAL afecta las transacciones y es bueno para usar cuando poll_mode=transaction, SET SESSION afecta las sesiones y es seguro para usar cuando poll_mode=session , ALTER USER SET afecta los roles e interferirá con pgbouncer.ini parte de la sección [usuarios], ALTER DATABASE SET afecta las bases de datos e interferirá con pgbouncer.ini parte de la sección [bases de datos], ALTER SYSTEM SET o editar postgres.conf globalmente afecta los valores predeterminados y es comparable en efecto a la sección predeterminada de pgbouncer.ini.

  • Una vez más, use el modo piscina de manera responsable. Las declaraciones preparadas o la configuración de toda la sesión serán un desastre en el modo de agrupación de transacciones. Igual que la transacción SQL no tiene sentido en el modo de agrupación de declaraciones. Elija un modo de agrupación adecuado para las conexiones adecuadas. Una buena práctica es crear roles con la idea de que:

    • algunos ejecutarán solo selecciones rápidas, por lo que pueden compartir una sesión sin transacciones para un centenar de selecciones diminutas no importantes simultáneas.
    • Algunos miembros de roles son seguros para la concurrencia a nivel de sesión y SIEMPRE usan transacciones. Por lo tanto, pueden compartir de forma segura varias sesiones para cientos de transacciones simultáneas.
    • Algunos roles son demasiado desordenados o complicados para compartir su sesión con otros. Por lo tanto, utiliza el modo de agrupación de sesiones para evitar errores en la conexión cuando ya se han ocupado todos los "espacios".
  • No lo use en lugar de HAProxy o algún otro balanceador de carga. A pesar del hecho de que pgbouncer tiene varias funciones configurables que abordan las direcciones de un balanceador de carga, como dns_max_ttl y puede configurar una configuración de DNS para él, la mayoría de los entornos de producción usan HAProxy o algún otro balanceador de carga para HA. Esto se debe a que HAProxy es realmente bueno en el equilibrio de carga entre servidores en vivo en forma de turno rotativo, mejor que pgbouncer. Aunque pgbouncer es mejor para la agrupación de conexiones de Postgres, podría ser mejor usar un demonio pequeño que realiza perfectamente una tarea, en lugar de uno más grande que realiza dos tareas, pero peor.

  • Los cambios de configuración pueden ser complicados. Algunos cambios en pgbouncer.ini requieren reiniciar (listen_port y similares), mientras que otros, como admin_users, requieren recargar o SIGHUP. Los cambios dentro de auth_hba_file requieren recarga, mientras que los cambios en auth_file no.

La breve descripción general de los ajustes anteriores está limitada por el formato. Te invito a que le eches un vistazo a la lista completa. Pgbouncer es el tipo de software con una cantidad muy pequeña de "configuraciones aburridas":todas tienen un gran potencial y son de un interés increíble.

Descargue el documento técnico hoy Administración y automatización de PostgreSQL con ClusterControlObtenga información sobre lo que necesita saber para implementar, monitorear, administrar y escalar PostgreSQLDescargar el documento técnico

Y, por último, pasar de una breve revisión entusiasta a algo en lo que podría estar menos feliz:la instalación. El proceso se describe claramente en esta sección de documentación. La única opción descrita es compilar a partir de fuentes de git. ¡Pero todo el mundo sabe que hay paquetes! Probando los dos más populares:

sudo yum install pgbouncer
sudo apt-get install pgbouncer

puede trabajar. Pero a veces hay que dar un paso más. Por ejemplo, cuando no haya un paquete pgbouncer disponible, intente esto.

O incluso:

sudo yum install pgbouncer
Loaded plugins: priorities, update-motd, upgrade-helper
amzn-main                                                                                                                    | 2.1 kB  00:00:00
amzn-updates                                                                                                                 | 2.5 kB  00:00:00
docker-ce-edge                                                                                                               | 2.9 kB  00:00:00
docker-ce-stable                                                                                                             | 2.9 kB  00:00:00
docker-ce-test                                                                                                               | 2.9 kB  00:00:00
pgdg10                                                                                                                       | 4.1 kB  00:00:00
pgdg95                                                                                                                       | 4.1 kB  00:00:00
pgdg96                                                                                                                       | 4.1 kB  00:00:00
pglogical                                                                                                                    | 3.0 kB  00:00:00
sensu                                                                                                                        | 2.5 kB  00:00:00
(1/3): pgdg96/x86_64/primary_db                                                                                              | 183 kB  00:00:00
(2/3): pgdg10/primary_db                                                                                                     | 151 kB  00:00:00
(3/3): pgdg95/x86_64/primary_db                                                                                              | 204 kB  00:00:00
50 packages excluded due to repository priority protections
Resolving Dependencies
--> Running transaction check
---> Package pgbouncer.x86_64 0:1.8.1-1.rhel6 will be installed
--> Processing Dependency: libevent2 >= 2.0 for package: pgbouncer-1.8.1-1.rhel6.x86_64
--> Processing Dependency: c-ares for package: pgbouncer-1.8.1-1.rhel6.x86_64
--> Processing Dependency: libcares.so.2()(64bit) for package: pgbouncer-1.8.1-1.rhel6.x86_64
--> Running transaction check
---> Package c-ares.x86_64 0:1.13.0-1.5.amzn1 will be installed
---> Package pgbouncer.x86_64 0:1.8.1-1.rhel6 will be installed
--> Processing Dependency: libevent2 >= 2.0 for package: pgbouncer-1.8.1-1.rhel6.x86_64
--> Finished Dependency Resolution
Error: Package: pgbouncer-1.8.1-1.rhel6.x86_64 (pgdg10)
           Requires: libevent2 >= 2.0
 You could try using --skip-broken to work around the problem
 You could try running: rpm -Va --nofiles --nodigest

Por supuesto, agregar pgdg a /etc/yum.repos.d/ ya no ayudará. Ni el --skip-broken ni el rpm -Va --nofiles --nodigest. Un sencillo

sudo yum install libevent2
Loaded plugins: priorities, update-motd, upgrade-helper
50 packages excluded due to repository priority protections
No package libevent2 available.
Error: Nothing to do

sería demasiado fácil. Por lo tanto, debe compilar libevent2 usted mismo, lo que lo lleva de vuelta a la posición en la que debe compilar las cosas usted mismo. O es pgbouncer o una de sus dependencias.

Nuevamente, profundizar demasiado en las particularidades de la instalación está fuera del alcance. Debe saber que tiene una gran oportunidad de instalarlo como paquete.

Por último, preguntas como "por qué Postgres no ofrece un agrupador de sesiones nativo" aparecen una y otra vez. Incluso hay sugerencias y pensamientos muy frescos al respecto. Pero hasta ahora, el enfoque más popular aquí es usar pgbouncer.