PostgreSQL : procédure d’upgrade avec pg_upgrade

de | 2017-06-16

Principe

Si mettre à jour PostgreSQL d’une version mineure à une autre est aussi simple qu’un échange de binaires, c’est un peu plus compliqué pour un changement de versions majeures (exemple : 9.3 vers 9.6) (1).
Entre versions majeures, c’est surtout le catalogue qui change : nouvelles colonnes, nouvelles vues. C’est la principale cause d’incompatibilité.
Le stockage des données dans le sous-répertoire « bases » de $PGDATA change rarement. A notre connaissance, il est identique depuis le début de la version 9.

Dans ce cas, pourquoi déplacer des centaines de gigas de données si seulement quelques tables systèmes sont différentes ? Et comment éviter de le faire ?

C’est là qu’intervient l’utilitaire « pg_upgrade » : si vous mettez à jour sur la même machine, il permet de migrer l’instance sur place, sans dupliquer les données, grâce à un jeu de « hard links » Unix.

Conventions

Source : Instance (cluster) PostgreSQL version 9.3. Les anciens binaires sont dans le répertoire désigné par OLD_BINDIR. Les données sont dans le répertoire OLD_DATADIR.
Destination : Instance PostgreSQL version 9.6. Les nouveaux binaires seront dans le répertoire désigné par NEW_BINDIR. Les données sont dans le répertoire NEW_DATADIR.

 

Apparté unix

Rappel : sous Unix, tout est fichier.

Ce que vous appelez « fichier1.txt » n’est pas le fichier lui-même mais un pointeur commode dirigé vers le véritable point d’entrée sur le disque : l’inode (ou « noeud d’index« , si vous êtes payé au mot).
Il est possible de créer plusieurs noms de fichiers (« fichier1.txt », « fichier2.txt »…) pointant vers le même inode. Une sorte d’ubiquité unixienne où ils sont tous deux identiques mais accessibles par deux endroits différents.
Exemple :
Soitun fichier dans un répertoire :

-rw-rw-r--. 1 postgres postgres  85 9 juin 10:18 fichier1.txt

Création d’un lien, sans l’option ‘-s’. Le lien n’est donc plus symbolique (l’équivalent d’un raccourci d’une application sur votre bureau) mais « dur » (il semble y avoir deux applications identiques à deux endroits différents) :

$ ln fichier1.txt fichier2.txt
$ ll
-rw-rw-r-- 2 postgres postgres  85 9 juin 10:18 fichier2.txt
-rw-rw-r-- 2 postgres postgres  85 9 juin 10:18 fichier1.txt

Notez le « 2 » au lien du « 1 » dans la seconde colonne. Cela montre qu’il existe deux descripteurs pour le même inode.

Note : c’est comme cela que Cassandra fait ses snapshots, comme vous le savez déjà si vous avez lu les excellents articles traitant du sujet sur ce site.
Note 2 : pour obtenir deux fichiers complètement différents, il faut déplacer l’un d’entre eux sur un file system différent. Ainsi, les données sont copiées. Par contre, le volume occupé sur disque sera multiplié par deux.
Fin de l’aparté Unix.

État initial et installation des nouveaux binaires

Etat initial

Les binaires (OLD_BINDIR) sont dans /chemin/vers/anciens/binaires.
Les données (OLD_DATADIR) sont dans /chemin/vers/nouveaux/binaires.

Installation des nouveaux binaires

Téléchargement depuis les dépôts officiels (https://www.postgresql.org/download/).
Packages, binaires, avec installeur ou non… Tout est bon. Au final, ils doivent se trouver dans le répertoire NEW_BINDIR. Choisissez également où va se trouver le nouveau dossier avec les données, « NEW_DATADIR ». Il faut qu’il soit sur le même point de montage si vous ne voulez pas (ou ne disposez pas) du double du volume.

Étapes préliminaires

Préparer la configuration de la nouvelle version. C’est un principe général : ne recopiez pas tel quel le fichier de configuration d’une version vers une autre. Les valeurs par défaut peuvent changer, de nouveaux paramètres apparaître, d’autres être dépréciés. Le plus sûr est de reporter votre configuration (mémoire, log…) vers le nouveau postgresql.conf.
C’est un travail supplémentaire qui vous évitera des problèmes dans le futur.

Arrêter le serveur PostgreSQL dans l’ancienne version :

pg_ctl stop -m fast

« -m fast » sur < 9.4. Depuis, c’est le mode d’arrêt par défaut.

 

Prise en compte des nouveaux binaires et création de l’instance

mkdir $NEW_DATADIR
export PGDATA=$NEW_DATADIR # adaptez à votre installation
export PATH=$NEW_BINDIR # idem

Puis sourcez le .profile ou reconnectez-vous.

Création de l’instance avec « initdb »

which initdb # vérifiez que c'est bien celui dans le $NEW_BINDIR
initdb [+options de collation, langue, comme l'existante...]

Récupération de la configuration précédente : postgresql.conf *et* pg_hba.conf (le fichier des accès réseau).

« pg_ctl start » et test que la connexion est OK. Vérification des logs.

Bien, si tout est OK, passons à la partie « upgrade »…

 

Upgrade

Dans un premier temps, il faut vérifier si les deux PostgreSQL (« clusters », dans la terminologie PostgreSQL) sont compatibles pour la mise à jour.

Il est temps de faire appel à « pg_update » :

which pg_update # vérifiez que vous êtes dans le bon environnement
pg_upgrade --check \
--old-datadir=$OLD_DATADIR \
--new-datadir=$NEW_DATADIR \
--old-bindir=$OLD_BINDIR \
--new-bindir=$NEW_BINDIR

A la fin des vérifications, l’utilitaire doit annoncer « Clusters are compatibles ». Sinon, il faut corriger.

Si les vérifications sont OK, vous pouvez passer à la migration proprement dite. C’est la même commande avec « –link » au lieu de « –check ». « –link » demande la mise à jour par hard link :

pg_upgrade --link \
--old-datadir=$OLD_DATADIR \
--new-datadir=$NEW_DATADIR \
--old-bindir=$OLD_BINDIR \
--new-bindir=$NEW_BINDIR

Après quelques secondes (dépendant du nombre de fichiers à lier), vous devez voir le message « Upgrade Complete », suivi de conseil sur la suite : mettre à jour les statistiques et supprimer l’ancien cluster.

Note : si, par curiosité, vous faites un « ls -altr » dans les $NEW_DATADIR ou $OLD_DATADIR, vous verrez que certains fichiers (ceux contenant les données) ont bien deux descripteurs par inode.

Note 2 : tant que vous n’avez pas démarré PostgreSQL avec les binaires récents, l’opération est encore réversible. Après le premier démarrage par contre seul une restauration rendra les données utilisables par l’ancienne version.

 

Lancement et post-opérations

Démarrez le cluster avec les nouveaux binaires :

which pg_ctl # toujours prudence !
pg_ctl start

Le journal d’évènement doit être sans erreur.

Connectez vous : le prompt doit afficher la version la plus récente.

Mettez à jour les fichiers d’environnement selon le shell que vous utilisez (.bash_profile, .profile).

Supprimez l’ancien cluster avec le script fourni par pg_upgrade ou à la main. Cela supprimera le répertoire $OLD_DATADIR.

Calculez les statistiques avec le script fourni ou bien avec la commande ANALYZE.

Ouvrez le service. Savourez votre réussite.

Pour en savoir plus, la documentation officielle de pg_upgrade est ici.

Conclusion

Si vous avez connu les upgrades Oracle ou Sybase, durant lesquels il y a toujours un frisson d’angoisse, vous apprécierez la simplicité de la migration PostgreSQL.
Le problème principal est humain : après des décennies d’angoisses à chaque montée de version, il est difficile de convaincre les chefs de projets.
Pour cela, un conseil : évitez de mentionner les numéros des versions mineures. Contentez vous de parler de « 9.4 » ou de « 9.6 » sans descendre à « 9.4.1 » ou « 9.6.3 ». Ainsi, vous vous réserverez la décision de mettre à jour vers les versions mineures et éviterez – espérons – le phénomène de blocage d’évolution.

 

Des problèmes ? des questions ? Exprimez-vous ! Les commentaires sont ouverts. Coquilles et fautes de grammaires sont notre lot quotidien : signalez-les nous à m.capello@dbsqware.com

 

(1) ce point est souvent mal compris pour les personnes découvrant PostgreSQL. Il faut savoir que, contrairement à d’autres moteurs, les versions mineures  (x.y. »z ») sont uniquement des corrections de bugs. Pas de changements, pas de nouvelles fonctionnalités. Rien que des binaires dont les erreurs ont été répérées et corrigées à l’usage. Aucune raison de ne pas mettre à jour.