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

Una guía de Pgpool para PostgreSQL:segunda parte

Esta es la segunda parte del blog “Una guía de Pgpool para PostgreSQL”. La primera parte que cubre el equilibrio de carga, la agrupación de sesiones, la memoria caché y la instalación se puede encontrar aquí.

Muchos usuarios miran hacia pgpool específicamente para funciones de alta disponibilidad, y tiene mucho que ofrecer. Hay bastantes instrucciones para pgpool HA en la web (por ejemplo, una más larga y otra más corta), por lo que no tendría ningún sentido repetirlas. Tampoco queremos proporcionar otro conjunto ciego de valores de configuración. En cambio, sugiero jugar en contra de las reglas e intentar hacerlo de la manera incorrecta, así veremos un comportamiento interesante. Una de las características más esperadas (al menos está en la parte superior de la página) es la capacidad de reconocer la usabilidad de un ex maestro "muerto" y reutilizarlo con pg_rewind. Podría ahorrar horas al traer de vuelta el nuevo modo de espera con big data (ya que omitimos rsync o pg_basebackup, que efectivamente copia TODOS los archivos del nuevo maestro). Estrictamente hablando, pg_rewind está destinado a la conmutación por error planificada (durante la actualización o la migración a un nuevo hardware). Pero hemos visto cuándo es de gran ayuda con el apagado no planificado pero ordenado y la conmutación por error automatizada, por ejemplo, ClusterControl lo utiliza cuando realiza la conmutación por error automática de los esclavos de replicación. Supongamos que tenemos el caso:necesitamos que (cualquier) maestro sea accesible tanto como sea posible. Si por algún motivo (fallo de red, exceso de conexiones máximas o cualquier otro “fallo” que prohíba el inicio de nuevas sesiones) ya no podemos usar un maestro para las operaciones de RW, tenemos configurado un clúster de conmutación por error, con esclavos que pueden aceptar conexiones. Entonces podemos promocionar uno de los esclavos y conmutar por error.

Primero supongamos que tenemos tres nodos:

  • 10.1.10.124:5400 con /pg/10/m (pgpool gira aquí también)
  • 10.1.10.147:5401 con /pg/10/m2
  • 10.1.10.124:5402 con /pg/10/s2

Esos son efectivamente los mismos nodos que en la primera parte, pero el nodo de conmutación por error se mueve a un host diferente y $PGDATA. Lo hice para asegurarme de que no cometí un error tipográfico u olvidé alguna cita adicional en el comando ssh remoto. Además, la información de depuración se verá más simple porque las direcciones IP son diferentes. Finalmente, no estaba seguro de poder hacer que este caso de uso sin soporte funcione, así que tengo que verlo con mis propios ojos.

Conmutación por error

Primero configuramos failover_command y ejecutamos pgpool reload e intentamos la conmutación por error. Aquí y más adelante, enviaré información a /tmp/d en el servidor pgpool, así que puedo seguir -f /tmp/d para ver el flujo.

[email protected]:~$ grep failover_command /etc/pgpool2/pgpool.conf
failover_command = 'bash /pg/10/fo.sh %D %H %R'

[email protected]:~$ cat /pg/10/fo.sh
rem_cmd="pg_ctl -D $3 promote"
cmd="ssh -T [email protected]$2 $rem_cmd"
echo "$(date) $cmd" >>/tmp/d
$cmd &>>/tmp/d

NB:¿Tiene $PATH establecido en .bashrc en el host remoto? ..

Detengamos al maestro (sé que no es así como sucede el desastre, esperas que al menos un mono enorme o un robot rojo brillante aplaste el servidor con un martillo enorme, o al menos que mueran los aburridos discos duros, pero estoy usando este elegante variante para demostrar el posible uso de pg_rewind, por lo que aquí la conmutación por error será el resultado de un error humano o una falla de la red medio segundo durante el período_comprobación_de_salud), por lo que:

/usr/lib/postgresql/10/bin/pg_ctl -D /pg/10/m stop
2018-04-18 13:53:55.469 IST [27433]  LOG:  received fast shutdown request
waiting for server to shut down....2018-04-18 13:53:55.478 IST [27433]  LOG:  aborting any active transactions
2018-04-18 13:53:55.479 IST [28855] postgres t FATAL:  terminating connection due to administrator command
2018-04-18 13:53:55.483 IST [27433]  LOG:  worker process: logical replication launcher (PID 27440) exited with exit code 1
2018-04-18 13:53:55.484 IST [27435]  LOG:  shutting down
2018-04-18 13:53:55.521 IST [27433]  LOG:  database system is shut down
 done
server stopped

Ahora verificando la salida del comando de conmutación por error:

[email protected]:~$ cat /tmp/d
Wed Apr 18 13:54:05 IST 2018 ssh -T [email protected]
pg_ctl -D /pg/10/f promote
waiting for server to promote.... done
server promoted

Y comprobando después de un rato:

t=# select nid,port,st, role from dblink('host=localhost port=5433','show pool_nodes') as t (nid int,hostname text,port int,st text,lb_weight float,role text,cnt int,cur_node text,del int);
 nid | port |  st  |  role
-----+------+------+---------
   0 | 5400 | down | standby
   1 | 5401 | up   | primary
   2 | 5402 | up   | standby
(3 rows)

También vemos en los registros del clúster de conmutación por error anterior:

2018-04-13 14:26:20.823 IST [20713]  LOG:  received promote request
2018-04-13 14:26:20.823 IST [20713]  LOG:  redo done at 0/951EC20
2018-04-13 14:26:20.823 IST [20713]  LOG:  last completed transaction was at log time 2018-04-13 10:41:54.355274+01
2018-04-13 14:26:20.872 IST [20713]  LOG:  selected new timeline ID: 2
2018-04-13 14:26:20.966 IST [20713]  LOG:  archive recovery complete
2018-04-13 14:26:20.998 IST [20712]  LOG:  database system is ready to accept connections

Comprobando la replicación:

[email protected]:~$ psql -p 5401 t -c "select now() into test"
SELECT 1
[email protected]:~$ psql -p 5402 t -c "select * from test"
              now
-------------------------------
 2018-04-13 14:33:19.569245+01
(1 row)

El esclavo /pg/10/s2:5402 cambió a una nueva línea de tiempo gracias a recovery_target_timeline =latest en recovery.conf, así que estamos bien. No necesitamos ajustar recovery.conf para que apunte al nuevo maestro, porque apunta a la IP y el puerto de pgpool y permanecen iguales sin importar quién esté desempeñando la función de maestro principal.

Comprobando el equilibrio de carga:

[email protected]:~$ (for i in $(seq 1 9); do psql -h localhost -p 5433 t -c "select current_setting('port') from ts limit 1" -XAt; done) | sort| uniq -c
      6 5401
      3 5402

Lindo. Las aplicaciones detrás de pgpool notarán una segunda interrupción y seguirán funcionando.

Reutilización de ex-maestro

Ahora podemos cambiar el ex-maestro al modo de espera de conmutación por error y recuperarlo (sin agregar un nuevo nodo a pgpool, ya que ya existe allí). Si no tiene wal_log_hints habilitados o sumas de verificación de datos (la diferencia completa entre estas opciones está aquí), debe volver a crear el clúster en ex-master para seguir una nueva línea de tiempo:

[email protected]:~$ rm -fr /pg/10/m
[email protected]:~$ pg_basebackup -h localhost -p 5401 -D /pg/10/m/

¡Pero no se apresure a ejecutar las declaraciones anteriores! Si tuvo cuidado con wal_log_hints (requiere reinicio), puede intentar usar pg_rewind para cambiar mucho más rápido del ex-maestro a un nuevo esclavo.

Así que ATM tenemos el ex-maestro fuera de línea, nuevo maestro con la próxima línea de tiempo iniciada. Si el ex-maestro estaba fuera de línea debido a una falla temporal en la red y regresa, primero debemos apagarlo. En el caso anterior, sabemos que está inactivo, por lo que podemos intentar rebobinar:

[email protected]:~$ pg_rewind -D /pg/10/m2 --source-server="port=5401 host=10.1.10.147"
servers diverged at WAL location 0/40605C0 on timeline 2
rewinding from last common checkpoint at 0/4060550 on timeline 2
Done!

Y de nuevo:

[email protected]:~$ pg_ctl -D /pg/10/m2 start
server started
...blah blah 
[email protected]:~$ 2018-04-16 12:08:50.303 IST [24699]  LOG:  started streaming WAL from primary at 0/B000000 on timeline 2

t=# select nid,port,st,role from dblink('host=localhost port=5433','show pool_nodes') as t (nid int,hostname text,port int,st text,lb_weight float,role text,cnt int,cur_node text,del int);
 nid | port |  st  |  role
-----+------+------+---------
   0 | 5400 | down | standby
   1 | 5401 | up   | primary
   2 | 5402 | up   | standby
(3 rows)

operaciones ¡Eh! A pesar de que el clúster en el puerto 5400 está en línea y sigue una nueva línea de tiempo, debemos decirle a pgpool que lo reconozca:

[email protected]:~$ pcp_attach_node -w -h 127.0.0.1 -U vao -n 0
 pcp_attach_node  -- Command Successful

Ahora los tres están activos (y pgpool lo sabe) y sincronizados:

[email protected]:~$ sql="select ts.i::timestamp(0), current_setting('data_directory'),case when pg_is_in_recovery() then 'recovering' else 'mastering' end stream from ts order by ts desc"
[email protected]:~$ psql -h 10.1.10.147 -p 5401 t -c "$sql";
          i          | current_setting |  stream
---------------------+-----------------+-----------
 2018-04-30 14:34:36 | /pg/10/m2       | mastering
(1 row)

[email protected]:~$ psql -h 10.1.10.124 -p 5402 t -c "$sql";
          i          | current_setting |   stream
---------------------+-----------------+------------
 2018-04-30 14:34:36 | /pg/10/s2       | recovering
(1 row)

[email protected]:~$ psql -h 10.1.10.124 -p 5400 t -c "$sql";
          i          | current_setting |   stream
---------------------+-----------------+------------
 2018-04-30 14:34:36 | /pg/10/m        | recovering
(1 row)

Ahora intentaré usar recovery_1st_stage_command para reutilizar ex-maestro:

[email protected]:~# grep 1st /etc/pgpool2/pgpool.conf
recovery_1st_stage_command = 'or_1st.sh'

Pero recovery_1st_stage_command no ofrece los argumentos necesarios para pg_rewind, que puedo ver si agrego a recovery_1st_stage_command:

echo "online recovery started on $(hostname) $(date --iso-8601) $0 $1 $2 $3 $4"; exit 1;

La salida:

online recovery started on u2 2018-04-30 /pg/10/m2/or_1st.sh /pg/10/m2 10.1.10.124 /pg/10/m 5401

Bueno, usar pg_rewind está solo en la lista de tareas pendientes, ¿qué esperaba? Entonces, necesito hacer un truco para obtener la IP maestra y el puerto (recuerde que seguirá cambiando después de la conmutación por error).

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

Un truco de mono

Así que tengo algo como esto en recovery_1st_stage_command:

[email protected]:~# cat /pg/10/or_1st.sh
pgpool_host=10.1.10.124
pgpool_port=5433
echo "online recovery started on $(hostname) $(date --iso-8601) $0 $1 $2 $3 $4" | ssh -T $pgpool_host "cat >> /tmp/d"
master_port=$(psql -XAt -h $pgpool_host -p $pgpool_port t -c "select port from dblink('host=$pgpool_host port=$pgpool_port','show pool_nodes') as t (nid int,hostname text,port int,st text,lb_weight float,role text,cnt int,cur_node text,del int) where role='primary'")
master_host=$(psql -XAt -h $pgpool_host -p $pgpool_port t -c "select hostname from dblink('host=$pgpool_host port=$pgpool_port','show pool_nodes') as t (nid int,hostname text,port int,st text,lb_weight float,role text,cnt int,cur_node text,del int) where role='primary'")
failover_host=$(psql -XAt -h $pgpool_host -p $pgpool_port t -c "select hostname from dblink('host=$pgpool_host port=$pgpool_port','show pool_nodes') as t (nid int,hostname text,port int,st text,lb_weight float,role text,cnt int,cur_node text,del int) where role!='primary' order by port limit 1")
src='"port=$master_port host=$master_host"'
rem_cmd="'pg_rewind -D $3 --source-server=\"port=$master_port host=$master_host\"'"
cmd="ssh -T $failover_host $rem_cmd"
echo $cmd | ssh -T $pgpool_host "cat >> /tmp/d"
$cmd

tmp=/tmp/rec_file_tmp
cat > $tmp <<EOF
standby_mode          = 'on'
primary_conninfo      = 'host=$master_host port=$master_port user=postgres'
trigger_file = '/tmp/tg_file'
recovery_target_timeline  = latest
EOF

scp $tmp $failover_host:$3/recovery.conf

rem_cmd="pg_ctl -D $3 start"
cmd="ssh -T $failover_host $rem_cmd"
echo $cmd | ssh -T $pgpool_host "cat >> /tmp/d"
$cmd
echo "OR finished $(date --iso-8601)" | ssh -T $pgpool_host "cat >> /tmp/d"
exit 0;

¡Ahora qué lío! Bueno, si decide utilizar una función que no existe, prepárese:se verá mal, funcionará peor y se sentirá permanentemente avergonzado de lo que hizo. Así que paso a paso:

  • Necesito la IP y el puerto de pgpool para conectarme de forma remota, tanto para consultar "show pool_nodes" como para registrar pasos y ejecutar comandos.
  • Estoy canalizando información de dbg a /tmp/d a través de ssh, porque el comando se ejecutará en el lado maestro, lo que cambiará después de la conmutación por error
  • Puedo usar el resultado de "show pool_nodes" para obtener la información de la conexión maestra en ejecución simplemente filtrando con la cláusula WHERE
  • Necesitaré comillas dobles en el argumento para pg_rewind, que deberá ejecutarse sobre ssh, así que solo divido el comando para facilitar la lectura, luego lo hago eco y lo ejecuto
  • Preparando recovery.conf basado en la salida de "show pool_nodes" (escribiéndolo, me pregunto:¿por qué no usé la IP y el puerto de pgpool en su lugar?...
  • Iniciando un nuevo esclavo de conmutación por error (sé que se supone que debo usar el segundo paso; simplemente lo omití para evitar que todas las IP y el puerto se repita)

Ahora lo que queda:tratar de usar este lío en pcp:

[email protected]:~# pcp_recovery_node -h 127.0.0.1 -U vao -n 0 -w
pcp_recovery_node -- Command Successful
[email protected]:~# psql -h localhost -p 5433 t -c"select nid,port,st,role from dblink('host=10.1.10.124 port=5433','show pool_nodes') as t (nid int,hostname text,port int,st text,lb_weight float,role text,cnt int,cur_node text,del int)"
 nid | port | st |  role
-----+------+----+---------
   0 | 5400 | up | standby
   1 | 5401 | up | primary
   2 | 5402 | up | standby
(3 rows)

Comprobando /tmp/d en el servidor pgpool:

[email protected]:~# cat /tmp/d
Tue May  1 11:37:59 IST 2018 ssh -T [email protected] /usr/lib/postgresql/10/bin/pg_ctl -D /pg/10/m2 promote
waiting for server to promote.... done
server promoted
online recovery started on u2 2018-05-01 /pg/10/m2/or_1st.sh /pg/10/m2
ssh -T 10.1.10.124 'pg_rewind -D --source-server="port=5401 host=10.1.10.147"'
ssh -T 10.1.10.124 pg_ctl -D start
OR finished 2018-05-01

Ahora, obviamente, queremos pasarlo de nuevo para ver si funciona en cualquier host:

[email protected]:~$ ssh -T 10.1.10.147 pg_ctl -D /pg/10/m2 stop             waiting for server to shut down.... done
server stopped
[email protected]:~$ psql -h localhost -p 5433 t -c"select nid,port,st,role from dblink('host=10.1.10.124 port=5433','show pool_nodes') as t (nid int,hostname text,port int,st text,lb_weight float,role text,cnt int,cur_node text,del int)"
 nid | port |  st  |  role
-----+------+------+---------
   0 | 5400 | up   | primary
   1 | 5401 | down | standby
   2 | 5402 | up   | standby
(3 rows)

[email protected]:~# pcp_recovery_node -h 127.0.0.1 -U vao -n 1 -w

[email protected]:~$ psql -h localhost -p 5433 t -c"select nid,port,st,role from dblink('host=10.1.10.124 port=5433','show pool_nodes') as t (nid int,hostname text,port int,st text,lb_weight float,role text,cnt int,cur_node text,del int)"
 nid | port | st |  role
-----+------+----+---------
   0 | 5400 | up | primary
   1 | 5401 | up | standby
   2 | 5402 | up | standby
(3 rows)

El registro es similar:solo han cambiado la IP y los puertos:

 Tue May  1 11:44:01 IST 2018 ssh -T [email protected] /usr/lib/postgresql/10/bin/pg_ctl -D /pg/10/m promote
waiting for server to promote.... done
server promoted
online recovery started on u 2018-05-01 /pg/10/m/or_1st.sh /pg/10/m 10.1.10.147 /pg/10/m2 5400
ssh -T 10.1.10.147 'pg_rewind -D /pg/10/m2 --source-server="port=5400 host=10.1.10.124"'
ssh -T 10.1.10.147 pg_ctl -D /pg/10/m2 start
online recovery started on u 2018-05-01 /pg/10/m/or_1st.sh /pg/10/m
ssh -T 10.1.10.147 'pg_rewind -D --source-server="port=5400 host=10.1.10.124"'
ssh -T 10.1.10.147 pg_ctl -D start
OR finished 2018-05-01

En este sandbox, el maestro se movió a 5401 en la conmutación por error y después de vivir allí por un tiempo se movió de nuevo a 5400. El uso de pg_rewind debería hacerlo lo más rápido posible. Anteriormente, la parte aterradora de la conmutación por error automática era:si realmente estropeaba la configuración y no preveía alguna fuerza mayor, podía encontrarse con una conmutación por error automática al siguiente esclavo y al siguiente y al siguiente hasta que no quedara ningún esclavo libre. Y después de eso, terminas con varios maestros de cerebro dividido y sin repuestos de conmutación por error. Es un pobre consuelo en tal escenario tener aún más esclavos para la conmutación por error, pero sin pg_rewind no tendría ni siquiera eso. Rsync "tradicional" o pg_basebackup copian TODOS LOS $PGDATA para crear un modo de espera y no pueden reutilizar el ex maestro "no demasiado diferente".

En conclusión de este experimento, me gustaría enfatizar una vez más:esta no es una solución adecuada para pegar copias ocultas. No se recomienda el uso de pg_rewind para pg_pool. No es utilizable en todos los cajeros automáticos. Quería agregar un poco de aire fresco a la configuración de pgpool HA, para que nubes como yo observen un poco más de cerca cómo funciona. Que corifeo sonría ante un enfoque ingenuo y tal vez lo vea con nuestros ojos de nubes.