Replicación, recuperación en linea y alta disponibilidad con pgpool2 (3.1.1) Parte II

A continuación os voy a exponer algunas cosas que he aprendido con pgpool en producción. Cosas que en una maqueta no ocurren, pero al utilizar la herramienta en el mundo real… peta y te cagas en su puta madre. Básicamente.


Pool de conexiones y conexiones persistentes


Si os leéis bien la documentación, no como yo, el creador de pgpool menciona que no se deben de utilizar conexiones persistentes a la base de datos porque se llena el pool de conexiones y os lo tira abajo, como un ataque de denegación pero vosotros solitos, sin ayuda de “juaquers” ni nada.

En mi caso existían unas conexiones idle persistentes, no muchas, pero las había. Y por la naturaleza de lo que hay montado, no se pueden cambiar. Deben de ser persistentes. ¿Qué hacemos si nos ocurre esto y no podemos utilizar conexiones no persistentes?, afortunadamente el creador de pgpool pensó en ello y disponemos de varios parámetros de la configuración que podemos modificar para que funcione nuestro pool:

#——————————————————————————
# POOLS
#——————————————————————————

# – Pool size –

num_init_children = 128
                                   # Number of pools
                                   # (change requires restart)
max_pool = 4
                                   # Number of connections per pool
                                   # (change requires restart)

# – Life time –

child_life_time = 300
                                   # Pool exits after being idle for this many seconds
child_max_connections = 0
                                   # Pool exits after receiving that many connections
                                   # 0 means no exit
connection_life_time = 300
                                   # Connection to backend closes after being idle for this many seconds
                                   # 0 means no close
client_idle_limit = 450
                                   # Client is disconnected after being idle for that many seconds
                                   # (even inside an explicit transactions!)
                                   # 0 means no disconnection
En la sección de “pool size” tenemos dos valores claros. El número de pools y las conexiones máximas por pool. Estos valores dependerán de vuestra instalación, en mi caso con esos dos valores es más que suficiente, de hecho con 64 hijos sería suficiente, pero me reservo el doble porque puedo (está montado en un pepino de servidor) y porque en epocas de trafico intenso no vendrá mal ir sobrado. Esto os dará margen de maniobra, tener el pool bastante libre, para jugar con los timeouts que están en la sección “Life time”.
Por defecto cada pool tiene un tiempo de vida de 300 segundos. Bien, este parámetro está bien así. El segundo parámetro tampoco es necesario tocarlo, pero tampoco pasa nada si se establece un límite de conexiones (dependerá de para que lo queráis). Ahora, lo importante. El tiempo de las conexiones están abiertas después de entrar en idle. Lo ideal sería que pusieseis aquí un valor elevado y monitorizaseis vuestra base de datos en producción. En mi caso he utilizado una gráfica de munin para saber la media de tiempo que están mis conexiones en idle y he ajustado este valor en función de esto mismo. Mi media estaba en torno a 230 segundos, pero me he dejado margen para no cortar nada vivo. Por otro lado está el parámetro “client_idle_limit”, para las persistentes. Lo mismo, averiguad a partir del punto en el cual vuestra persistente se vuelve idle y poned el valor con cierto coeficiente de seguridad extra. Esto cortará esas persistentes después de estar idle durante 450 segundos. Podréis elevar este valor más en función del número de pools que hayáis configurado en la sección “pool size”. Si vais muy justos de conexiones, no podréis elevar mucho este valor porque entonces la frecuencia de apertura de conexiones será mayor que la frecuencia de cierre de las idles y se llenará. Cuidado con esto.

Comandos PCP de recuperación de un nodo caido en producción.

En la maqueta todo funciona fetén, ¿verdad?, probamos cuarenta veces la simulación de un nodo caído y la recuperación en línea. Y todo marchaba viento en popa a toda vela. Lo ponemos en producción y ocurre, un nodo se sale del pool. Genial, vamos a probar la recuperación en linea en producción. Te excitas, se te pone el vello de punta, los pezones endurecen, vas a recuperar un nodo en linea sin downtime. Te dispones a ello, escribes el comando tecleando como si estuvieses tocando en un piano la pieza más difícil de Rachmaninov ante un público exigente y en el mejor teatro del mundo (respirad). Respiras unos segundos y relees el comando, está correcto, el tiempo se para y… le das a intro esperando los aplausos y la gloria pero…
Una mierda. Te comes una mierda. Y bien gorda.
No solo el nodo no recupera, no… además te causa un downtime en producción. Los lobos se te echan encima y, menos mal Diocito Santo, existe un timeout para los comandos pcp que avispadamente e inadvertidamente habías puesto a 90 segundos y, solamente en ese tiempo, vuelve todo a funcionar.
Menos mal. Respiras. Los usuarios vuelven a lo suyo después de amenazarte con ir a tu casa a violar a tu mujer y matar a tus hijos mientras miras. Y tu no entiendes que coño pasa. Si en pruebas todo iba genial. Hiciste millones de pruebas: apagando la máquina, reiniciando el servicio, parando el servicio e incluso apagando de botón. Y siempre, siempre, recuperaba el nodo; ¡y rapidisimo!
Y te pasas una semana no entiendo nada, intentando diferentes cosas hasta que; una vez más, te lees bien la documentación y descubres que el pool no recupera un nodo si hay conexiones idle abiertas. Cojones. Otra vez topamos con las peuteas idles.
Deduciréis, amigos, que a pgpool no le gustan las persistentes. Pero es que a nadie le gustan las persistentes y no deberían de usarse. Pero se usan a veces. Aunque sea esa sesión abierta en un screen para hacer pruebas de vez en cuando y consultas a pelo. Eso es una persistente idle, amigos. Y vuestros devops seguro que tienen más de un screen de esos abierto desde 2011 y ni se acuerdan.
Otra vez más, amigos, parametritos pensados para salvar esta inconveniencia:
#——————————————————————————
# ONLINE RECOVERY
#——————————————————————————

recovery_user = ‘postgres’
                                   # Online recovery user
recovery_password = ‘postgres’
                                   # Online recovery password
recovery_1st_stage_command = ‘base-backup’
                                   # Executes a command in first stage
recovery_2nd_stage_command = ‘pgpool-recovery-pitr’
                                   # Executes a command in second stage
recovery_timeout = 500
                                   # Timeout in seconds to wait for the
                                   # recovering node’s postmaster to start up
                                   # 0 means no wait
client_idle_limit_in_recovery = 10
                                   # Client is disconnected after being idle
                                   # for that many seconds in the second stage
                                   # of online recovery
                                   # 0 means no disconnection
                                   # -1 means immediate disconnection
En la sección de “Online recovery” encontramos nuestros famosos comandos de primera y segunda fase que ya comentamos en su momento (ver el archivo de este blog si no sabes de que mierda hablo). Y luego dos maravillosos parámetros, recovery_timeout que podeis poner el tiempo máximo que asumis que vais a esperar a que vuestro nodo recupere y será exactamente el mismo tiempo que vuestra base de datos no acepte conexiones.
Sí amigos, pgpool se vende como algo maravilloso con lo que no sufriréis más downtime pero es mentira. Como todo en esta vida, siempre hay letra pequeña. Esto es falso pero puede parecer verdadero, como las tetas operadas. Supongamos que tenéis una WEB que se conecta a un postgresql. Bien, vuestra WEB es normalita y no tenéis muchas conexiones simultaneas ni nada. Lanzáis una recuperación de nodo y no notáis ese downtime. ¿Por qué?, porque pgpool va a encolar las peticiones hasta que el nodo recupere, son muy pocas y recupera en un segundo. Por tanto, a lo sumo, notáis un pequeño retraso en la consulta. Retraso que puede ocurrir por otros motivos como que vuestra conexión sea lenta o cualquier otra situación cotidiana utilizando Internet. Y pensáis, pgpool es la hostia. Pero, ¿qué pasa cuando tenéis una WEB grande con mucho trafico?. Pues ocurre que pgpool para las peticiones hasta que el nodo recupera (es normal si queréis tener consistencia en los datos, que de eso va esta movida), como tenías chorrocientas idles esperando, pcp no recupera hasta que esas idles no terminan. Aquí entra en juego el parámetro “client_idle_limit_in_recovery” que cortará todas las idles en un máximo de 10 segundos (en mi caso, que si sois valientes deberíais de poner vuestro tiempo idle medio). Pero ojo. Hay persistentes en transacción que puede que no sean cortadas o que puede que sean cortadas pero originen errores. Lo más recomendable es parar vuestra WEB (y aquí está la mentira cazada, hay downtime), cortar a mano las idles y aseguraros de que no tenéis a nadie pidiendo nada. Pero bueno, todo dependerá de vuestro caso concreto y de lo osados que seáis.
Si no tenéis persistentes abiertas y todo va como debe y de verdad de deporte, recuperará el nodo correctamente.
Y por hoy, amigos, esto es todo. Espero que estas aclaraciones os sirvan de algo.
Anuncios

Dime si me equivoco

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s