sábado, 6 de agosto de 2016

Esperando a 9.0 -- WAITING FOR 9.0 – STREAMING REPLICATION

Esta entrada es una traducción de https://www.depesz.com/2010/02/01/waiting-for-9-0-streaming-replication/
La traducción puede contener errores.
This entry is a translation of https://www.depesz.com/2010/02/01/waiting-for-9-0-streaming-replication/
The translation may contain errors.

La GRAN característica. La característica que hizo que Postgresql salte de 8.4 a 9.0. El parche fue escrito por Fujii Masao, y subido por Heikki Linnakangas el 15 de enero de 2010:

Log Message:
-----------
Introduce Streaming Replication.

This includes two new kinds of postmaster processes, walsenders and
walreceiver. Walreceiver is responsible for connecting to the primary server
and streaming WAL to disk, while walsender runs in the primary server and
streams WAL from disk to the client.

Documentation still needs work, but the basics are there. We will probably
pull the replication section to a new chapter later on, as well as the
sections describing file-based replication. But let's do that as a separate
patch, so that it's easier to see what has been added/changed. This patch
also adds a new section to the chapter about FE/BE protocol, documenting the
protocol used by walsender/walreceivxer.

Bump catalog version because of two new functions,
pg_last_xlog_receive_location() and pg_last_xlog_replay_location(), for
monitoring the progress of replication.

Fujii Masao, with additional hacking by me
 


¿Qué significa exactamente?

Bueno. Como tú tal vez eres consciente, Postgresql ofrece replicación usando segmentos WAL - lo cual, hasta 8.4, podía ser usado para tener Warm Standby, aunque desde 9.0 tendrás la capacidad para hacerlo actualmente Hot Standby.

El problema con esta replicación es muy simple - la repliación está basada en ficheros, los cuales son rotados (and por lo tanto la replicación) después de 16 MB de datos. En algunos escenarios no es un problema - si estás generando constantemente al mes 16 MB de escrituras por minuto - tu diferencia (lag) de replicación es básicamente siempre por debajo de un minuto.

¿Pero qué ocurre si tú no tienes muchas escrituras? Por supuesto puedes forzar la rotación de WAL, pero esto no es realmente una buena idea, y no es sugerido forzarlo por debajo de un minuto en cualquier caso.

Pero ahora, gracias a la replicación en streaming (streaming replication), la diferencia debe ser cercana a cero. Por supuesto es aún replicación asíncrona, pero para la mayoría de los casos de uso - asíncrona es realmente bastante buena.

Así, vamos a ver cómo configurarla

En mi máquina de test, yo tengo los binarios de Postgresql en /home/pgdba/work, y el directorio de datos principal en /home/pgdba/data (escucha en puerto 5850)

Ahora. Vamos a configurar streaming replication y el sevidor standby, en la misma máquina en /home/pgdba/data2, escuchando en 5851.

Lo primero, yo necesitaré parar el Postgresql principal.

/home/pgdba/work/bin/pg_ctl -D /home/pgdba/data stop

Ahora vamos a hacer algunos cambios en la configuración. Antes de aplicar los cambios, he copiado postgresql.conf a postgresql.conf.before, así yo puedo ahora mostrarte la diferencia sencilla.

=> diff -u postgresql.conf.before postgresql.conf
--- postgresql.conf.before      2010-01-31 23:27:24.000000000 +0100
+++ postgresql.conf     2010-01-31 23:29:29.000000000 +0100
@@ -175,9 +175,9 @@

 # - Archiving -

-#archive_mode = off            # allows archiving to be done
+archive_mode = on              # allows archiving to be done
                                # (change requires restart)
-#archive_command = ''          # command to use to archive a logfile segment
+archive_command = 'cp "%p" /home/pgdba/wal_archive/"%f"'               # command to use to archive a logfile segment
 #archive_timeout = 0           # force a logfile segment switch after this
                                # number of seconds; 0 disables

@@ -190,7 +190,7 @@

 # - Replication -

-#max_wal_senders = 0           # max number of walsender processes
+max_wal_senders = 1            # max number of walsender processes
 #wal_sender_delay = 200ms      # 1-10000 milliseconds


Como puedes ver no es realmente complicado

Ahora, yo puedo arrancar el maestro Postgresql

/home/pgdba/work/bin/pg_ctl -D /home/pgdba/data start

OK, Ahora, yo generé algún tráfico en la base de datos, para hacer generar algunos segmentos WAL. No muchos - digamos 100.

Mi script de test genera en torno a 7 segmentos de wal por minuto.

Ahora. Teniendo esto, vamos a configurar el servidor esclavo:

=> /home/pgdba/work/bin/psql -U postgres -p 5850 -c "SELECT pg_start_backup('depesz')"

 pg_start_backup

-----------------

 0/74C645E8

(1 row)

=> rsync -a /home/pgdba/data/ /home/pgdba/data2/

=> /home/pgdba/work/bin/psql -U postgres -p 5850 -c "SELECT pg_stop_backup()"

 pg_stop_backup

----------------

 0/7A8FB9A8

(1 row)


Ahora, vamos a limpiar data2:

rm -f /home/pgdba/data2/postmaster.pid /home/pgdba/data2/pg_xlog/archive_status/* /home/pgdba/data2/pg_xlog/0*

Y cambia la configuración. Diferencia entre data y data2:

=> diff -u data/postgresql.conf data2/postgresql.conf
--- data/postgresql.conf        2010-01-31 23:34:11.000000000 +0100
+++ data2/postgresql.conf       2010-02-01 00:02:18.000000000 +0100
@@ -60,7 +60,7 @@
                                        # comma-separated list of addresses;
                                        # defaults to 'localhost', '*' = all
                                        # (change requires restart)
-#port = 5850                           # (change requires restart)
+port = 5851                            # (change requires restart)
 max_connections = 100                  # (change requires restart)
 # Note:  Increasing max_connections costs ~400 bytes of shared memory per
 # connection slot, plus lock space (see max_locks_per_transaction).

@@ -175,7 +175,7 @@

 # - Archiving -

-archive_mode = on              # allows archiving to be done
+archive_mode = off             # allows archiving to be done
                                # (change requires restart)
 archive_command = 'cp "%p" /home/pgdba/wal_archive/"%f"'               # command to use to archive a logfile segment
 #archive_timeout = 0           # force a logfile segment switch after this

@@ -190,7 +190,7 @@

 # - Replication -

-max_wal_senders = 1            # max number of walsender processes
+max_wal_senders = 0            # max number of walsender processes
 #wal_sender_delay = 200ms      # 1-10000 milliseconds

En el esclavo yo creé recovery.conf:

=> cat /home/pgdba/data2/recovery.conf

standby_mode = 'on'
primary_conninfo = 'host=127.0.0.1 port=5850 user=postgres'
trigger_file = '/home/pgdba/data2/finish.replication'
restore_command = 'cp -i /home/pgdba/wal_archive/%f "%p" </dev/null'


Es crítico que tú no puedas usar pg_standby o cualquier otra cosa como esto que esperará para el siguiente segmento WAL.

Además - hasta donde yo comprendo - los segmentos de wal deben de ser enviados directamente desde el maestro al esclavo usando archive_command - es decir, copiándolos a algún directorio temporal, y después resincronizando desde cron, probablemente no trabajará.

De todas formas. Después de algún tiempo, el sistema esclavo cogerá todos los segmentos wal desde el directorio de archivo, y conmutará a streaming.

Puede ser visto porque ahora nosotros tenemos 2 nuevos, interesantes procesos:

=> ps uw --ppid $( head -n 1 /home/pgdba/data2/postmaster.pid )

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND

pgdba    13384  0.0  0.0  28712  1056 ?        Ss   00:22   0:00 postgres: logger process

pgdba    13385  1.1  0.2  59916 27200 ?        Ss   00:22   0:03 postgres: startup process   recovering 0000000100000000000000EE

pgdba    13390  0.0  0.2  59812 26208 ?        Ss   00:22   0:00 postgres: writer process

pgdba    13397  0.0  0.0  30800  1052 ?        Ss   00:22   0:00 postgres: stats collector process

pgdba    13402  0.4  0.0  77016  7368 ?        Ss   00:22   0:01 postgres: wal receiver process   streaming 0/EE2B7FD8



=> ps uw --ppid $( head -n 1 /home/pgdba/data/postmaster.pid )

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND

pgdba     6904  0.9  0.0  28716  1056 ?        Ss   Jan31   0:31 postgres: logger process

pgdba     6906  0.1  0.2  60092 27060 ?        Ss   Jan31   0:04 postgres: writer process

pgdba     6907  0.0  0.0  59652  1304 ?        Ss   Jan31   0:00 postgres: wal writer process

pgdba     6908  0.0  0.0  62624  3992 ?        Ss   Jan31   0:00 postgres: autovacuum launcher process

pgdba     6909  0.0  0.0  30912  1024 ?        Ss   Jan31   0:00 postgres: archiver process   last was 0000000100000000000000ED

pgdba     6910  0.0  0.1  47356 12896 ?        Ss   Jan31   0:00 postgres: stats collector process

pgdba     8713 85.6  0.6 118308 80628 ?        Rs   Jan31  31:35 postgres: depesz depesz [local] DROP TABLE

pgdba     8818  0.0  0.5 110428 66604 ?        Ss   Jan31   0:01 postgres: autovacuum worker process   depesz

pgdba     8887  0.0  0.6 134780 84884 ?        Ss   Jan31   0:01 postgres: autovacuum worker process   depesz

pgdba     8952  0.0  0.6 126812 83580 ?        Ss   Jan31   0:01 postgres: autovacuum worker process   depesz

pgdba    13403  1.4  0.0  69224  8580 ?        Ss   00:22   0:04 postgres: wal sender process postgres 127.0.0.1(52186) streaming 0/EE3D8090


Como tú puedes ver el maestro está aún haciendo el archivado de los segmentos de wal - el cual debe continuar, pero tú debes de usar algún trabajo programados con cron para eliminar los segmentos de wal no necesitados. Por no necesitados yo quiero decir - más viejos que "Latest checkpoint's REDO location" desde "pg_controldata SLAVE_DATA_DIR/".

Ahora. Vamos a ver cómo realmente funciona.

Yo paré my generador de carga - gracias a esto no habrá básicamente ningún tráfico en la base de datos - tan pronto como autovacuums finalicen 🙂


Después, I hice un sencillo test. Yo tengo la tabla:


# \d test
              Table "public.test"
 Column |           Type           | Modifiers
--------+--------------------------+-----------
 x      | timestamp with time zone | not null
Indexes:
    "test_pkey" PRIMARY KEY, btree (x)



Primera prueba:

=$ /home/pgdba/work/bin/psql -U depesz -p 5850 -c "insert into test (x) values (now()) returning x"
               x
-------------------------------
 2010-02-01 00:33:29.543639+01
(1 row)

INSERT 0 1

=$ /home/pgdba/work/bin/psql -U depesz -p 5851 -c "select * from test"

 x

---

(0 rows)


Por supuesto yo no lo veo - streaming replication is rápido, but not tan rápido  🙂

Aunque añadiendo incluso 1 segundo de retraso funcionó perfectamente.

=$ /home/pgdba/work/bin/psql -U depesz -p 5850 -c "insert into test (x) values (now()) returning x"
               x
-------------------------------
 2010-02-01 00:35:13.520617+01
(1 row)

INSERT 0 1

=$ sleep 1

=$ /home/pgdba/work/bin/psql -U depesz -p 5851 -c "select * from test order by x desc limit 1"
               x
-------------------------------
 2010-02-01 00:35:13.520617+01
(1 row)


(Estos comandos han sido copiados-pegados al terminal, así que no hubo retrasdo inducido por el tecleado).

Así, como nosotros podemos ver funciona.

¿Está listo? Definitivamente no. Para los que empiezan - los documentos están lejos de ser usables. Si te gustaría jugar contigo mismo - tú puedes comprobar la documentación pero tú debes de comprobar la página Wiki.

¿Me gusta? SÍ! Incluso con la documentación no lista, la configuración no fue realmente larga, y el resultado es bueno digno de un poco de sudor 🙂

No hay comentarios:

Publicar un comentario