Sauvegarde locale

Une architecture basique de type Oracle-like

      Une question est régulièrement posée au sujet de la possibilité de "multiplexer les redo" avec PostgreSQL. C'est du vocabulaire Oracle Database qui peut se traduire avec PostgreSQL par "Est-il possible d'écrire de manière synchrone les informations de journalisation WAL dans plusieurs emplacements différents ?"
      L'idée derrière le fait de "multiplexer les redo" est de se prémunir des corruptions de filesystems et de diminuer le risque de perdre des transactions validées (assurer le D de ACID).
      De manière plus générale, Oracle propose par défaut de créer une zone appelée FRA (Fast Recovery Area). Cette zone va contenir une copie des fichiers de journalisation courant (redo log online, WAL) mais aussi les fichiers de journalisation archivés (redo logs archivés, WAL archivés) et les sauvegardes des fichiers de données.
      Le principe de sauvegarde est alors de faire "backup database to FRA" suivi de "backup FRA to tape". L'idée est de sauvegarder la base dans la FRA afin de disposer d'une zone disque immédiatement disponible pour faire des PITR (point in time recovery) rapides mais limités au niveau de la période couverte mais aussi de remonter la FRA sur bande pour constituer des sauvegardes de plus long terme. Les bandes sont souvent à présent des librairies virtuelles mais le principe demeure le même.
      Nous allons constituer l'équivalent de la FRA pour PostgreSQL avec Barman, outil sous licence GPL édité par 2ndQuadrant. Cet outil est plutôt prévu pour faire des sauvegardes distantes mais qui peut le plus peut le moins et nous allons l'utiliser localement selon le schéma d'architecture suivant fourni dans leur documentation :

Voici de quoi constituer une FRA

      Le serveur pg et le serveur backup seront ici un seul et même serveur.
      Le streaming WAL synchrone (WAL streaming via pg_receivexlog) va nous apporter la copie synchrone du WAL courant. Petit point notable, pg_receivexlog s'appelle pg_receivewal depuis PostgreSQL 10, ce qui est plus clair.
      L'archivage des WAL (archive_command via rsync/SSH) va nous apporter les WAL archivés.
      Enfin, la sauvegarde (backup via rsync/SSH) va nous apporter les fichiers de données sauvegardés. Il serait possible d'utiliser pg_basebackup à la place de rsync/ssh mais la méthode rsync/ssh dispose toujours de quelques atouts puisqu'elle permet d'effectuer les sauvegardes en parallèle et intègre une forme limitée de déduplication.
      Trêve de théorie, démonstration avec PostgreSQL 10 et Barman 2.3 sous Debian Buster (l'environnement est similaire à celui présenté ici mais en version 10).
      Tout d'abord, installation de barman et échange de clés ssh entre les utilisateurs barman et postgres :

id uid=0(root) gid=0(root) groupes=0(root) apt-get install barman ... Paramétrage de barman (2.3-2) ... apt-get install barman-cli ... Paramétrage de barman-cli (1.2-1) ... su - postgres ssh-keygen exit su - barman ssh-keygen exit cat /var/lib/barman/.ssh/id_rsa.pub >> /var/lib/postgresql/.ssh/authorized_keys chown postgres /var/lib/postgresql/.ssh/authorized_keys chmod 600 /var/lib/postgresql/.ssh/authorized_keys cat /var/lib/postgresql/.ssh/id_rsa.pub >> /var/lib/barman/.ssh/authorized_keys chown barman /var/lib/barman/.ssh/authorized_keys chmod 600 /var/lib/barman/.ssh/authorized_keys su - barman ssh postgres@localhost id yes exit su - postgres ssh barman@localhost id yes


      A présent, paramétrage du streaming et de l'archivage des WAL :

id uid=108(postgres) gid=114(postgres) groupes=114(postgres),113(ssl-cert) psql select version(); version -------------------------------------------------------------------------------------------------------- PostgreSQL 10.2 (Debian 10.2-1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 7.3.0-1) 7.3.0, 64-bit (1 ligne) show wal_level; wal_level ----------- replica (1 ligne) show max_replication_slots; max_replication_slots ----------------------- 10 (1 ligne) show max_wal_senders; max_wal_senders ----------------- 10 (1 ligne) show archive_command; archive_command ----------------- (disabled) (1 ligne) alter system set archive_command = 'rsync -a %p barman@localhost:/var/lib/barman/apptra001/incoming/%f'; ALTER SYSTEM show archive_mode; archive_mode -------------- off (1 ligne) alter system set archive_mode=on; ALTER SYSTEM \q exit pg_ctlcluster 10 apptra001 restart


      Nous constatons que le cluster est paramétré par défaut pour permettre le PITR (point in time recovery) et le streaming WAL. Le niveau de journalisation est en effet fixé à REPLICA. Cet aspect a été simplifié par rapport aux versions précédentes. Si vous ne voulez pas faire de PITR ou de réplication avec une standby alors le niveau à fixer est MINIMAL sinon il est à positionner à REPLICA. Un niveau supérieur à REPLICA existe, LOGICAL. Il permet de faire de la réplication logique, de décoder les WAL pour en extraire le SQL. Ce dernier niveau est équivalent à positionner le "supplemental logging" qui permet d'utiliser Streams ou Golden Gate avec Oracle Database.
      Le nombre maximal de flux de streaming sortants est fixé à 10 via MAX_WAL_SENDERS tout comme le nombre de slots permettant d'éviter que les informations de journalisation soient supprimées avant d'avoir été transmises. Bref, rien à faire côté paramétrage pour le streaming WAL.
      Au sujet de l'archivage des WAL, nous avons positionné archive_mode à ON et nous avons utilisé rsync pour archive_command. Les WAL archivés arriveront dans /var/lib/barman lorsque barman sera configuré. A noter que var/lib/barman doit bien sûr être un filesystem distinct de /var/lib/postgresql et pas seulement un dossier distinct.
      Il faut aussi disposer d'un superutilisateur autorisé notamment à transmettre les informations WAL. Nous pourrions utiliser postgres mais nous allons créer un utilisateur dédié appelé localsuper en musclant sa méthode d'authentification au passage :

psql set password_encryption='SCRAM-SHA-256'; SET create role localsuper with login superuser password 'RJoindaAimablDefndersmyHckgrp98'; CREATE ROLE \du Liste des rôles Nom du rôle | Attributs | Membre de -------------+---------------------------------------------------------------------------------+----------- localsuper | Superutilisateur | {} postgres | Superutilisateur, Créer un rôle, Créer une base, Réplication, Contournement RLS | {}

      La méthode md5 étant toujours activée par défaut dans pg_hba.conf, nous allons remplacer md5 par scram-sha256 pour les connexions locales dans /etc/postgresql/10/apptra001/pg_hba.conf (en fait cela fonctionnerait en laissant md5 puisque md5 permet ici d'utiliser md5 et scram-sha256 mais nous allons ainsi interdire explicitement md5) :

host all all 127.0.0.1/32 scram-sha-256 host all all ::1/128 scram-sha-256 host replication all 127.0.0.1/32 scram-sha-256 host replication all ::1/128 scram-sha-256 pg_ctlcluster 10 apptra001 reload


      C'est fini pour la partie "postgres". À présent la partie "barman" en commançant par le stockage du mot de passe de localsuper dans un fichier dédié à l'accès restreint :

id uid=109(barman) gid=115(barman) groupes=115(barman) vi /var/lib/barman/.pgpass localhost:5432:postgres:localsuper:RJoindaAimablDefndersmyHckgrp98 localhost:5432:replication:localsuper:RJoindaAimablDefndersmyHckgrp98 chmod 600 /var/lib/barman/.pgpass

      Place à présent à la configuration de barman. Le fichier de configuraiton va être renseigné de manière à garantir une fenêtre de recover de 5 jours, c'est à dire qu'il sera toujours possible de faire revenir les bases du cluster en arrière de 5 jours avec ce que contient l’espace Barman. Avec une sauvegarde planifiée de manière hebdomadaire, le nombre de sauvegardes présentes en ligne sera au maximum de 2 :

id uid=0(root) gid=0(root) groupes=0(root) vi /etc/barman.d/01-apptra001.conf [apptra001] description = "Sauvegarde apptra001" ssh_command = ssh postgres@localhost retention_policy = RECOVERY WINDOW OF 5 days compression = gzip reuse_backup = link minimum_redundancy = 1 last_backup_maximum_age = '8 days' recovery_options = 'get-wal' conninfo = port=5432 host=localhost user=localsuper dbname=postgres archiver = on streaming_conninfo = port=5432 host=localhost user=localsuper streaming_archiver = on streaming_archiver_name = local_barman_receive_wal slot_name = barman_local chown barman /etc/barman.d/01-apptra001.conf su - barman barman receive-wal --create-slot apptra001 Creating physical replication slot 'barman_local' on server 'apptra001' Replication slot 'barman_local' created barman check apptra001 ... barman backup apptra001 ... barman check apptra001 Server apptra001: PostgreSQL: OK is_superuser: OK PostgreSQL streaming: OK wal_level: OK replication slot: OK directories: OK retention policy settings: OK backup maximum age: OK (interval provided: 8 days, latest backup age: 46 seconds) compression settings: OK failed backups: OK (there are 0 failed backups) minimum redundancy requirements: OK (have 1 backups, expected at least 1) ssh: OK (PostgreSQL server) not in recovery: OK archive_mode: OK archive_command: OK continuous archiving: OK pg_receivexlog: OK pg_receivexlog compatible: OK receive-wal running: OK archiver errors: OK crontab -e 0 20 * * 0 barman backup all 2>&1 > /dev/null


      Tout est OK. En fait, le slot n'est pas réellement nécessaire puisque nous archivons de toute façon chaque WAL via rsync/ssh mais il ne fait pas de mal.
      Dernier point. Pour avoir réellement une copie conforme du WAL courant dans cet espace Barman, il faut imposer la synchronisation au niveau du streaming WAL :

psql alter system set synchronous_standby_names = 'local_barman_receive_wal'; ALTER SYSTEM select pg_reload_conf(); pg_reload_conf ---------------- t (1 ligne)


      Attention à ce dernier point, il faut à présent absolument que le streaming WAL synchrone fonctionne pour pouvoir valider une transaction. Dans le cas contraire, c'est le blocage. Le fait de passer d'un RPO (recovery point objective, perte de données maximale admissible) proche de 0 à un RPO de 0 peut ainsi se payer par un risque accru sur la disponibilité ET la performance. Ce RPO de 0 s'entend de toute façon sous réserve de ne pas perdre simultanément /var/lib/barman ET /var/lib/postgresql. Il est dans tous les cas recommandé d'avoir plusieurs destinations si vous mettez en place du streaming WAL synchrone (raisonnement proche de celui à avoir avec les Dataguard en "max protection" pour les DBA Oracle)
      Comme d'habitude, il est possible d'automatiser tout cela via Ansible, de superviser le bon fonctionnement de l'ensemble via Nagios etc.

Mise à jour : 17/02/2018