Mettre à jour vos vieux clusters PostGIS

By jeudi 5 novembre 2020Database, GIS, PostGIS, PostgreSQL

Cela fait déjà quelques années que votre base de donnée PostGIS est votre fidèle compagne, gardienne de vos données géographiques, répondant avec diligence à vos requêtes les plus alambiquées. Et pourtant, malgré ces bons et loyaux services, ainsi va la logique du monde : il faut évoluer, bouger, se mettre à jour et donc mettre à jour également ce vieux cluster !

logo postgis

C’est alors que les problèmes commencent : entre les changements cassants des versions majeures de PostgreSQL, les fonctions dépréciées de PostGIS qui finissent par être supprimées et la taille de ce vieux cluster devenue conséquente au fil des années, l’opération peut ne pas être simple ! Cet article détaillera la procédure à grosse maille et évoquera certains points de vigilance à garder à l’esprit pour migrer avec sérénité.

On ne parlera que des migrations de versions majeures. En effet, pour les versions mineures de PostgreSQL, il n’y a rien à faire et pour PostGIS il suffit d’utiliser :

ALTER EXTENSION postgis UPDATE;

Les sauvegardes sont néanmoins conseillées, mais elles sont de toute façon faites régulièrement, n’est-ce pas ?

Sécuriser sa migration

Une migration réussie, c’est une migration sécurisée. La sécurisation d’une migration passe par 3 points principaux :

  • s’assurer de la pérennité des données
  • prévoir et minimiser autant que possible l’indisponibilité de la base
  • maîtriser les facteurs humains, notamment en communiquant clairement sur cette indisponibilité

Le dernier point peut sembler être une évidence pour certain, mais il est tout de même important qu’il soit mentionné. Sa bonne exécution conditionne souvent le sentiment de succès ou d’échec des acteurs en présence et donc la capacité globale de votre organisation à absorber ce type de changement.

Il convient de ne pas négliger la force des expériences passées – bonnes ou mauvaises – sur notre capacité à avancer en tant que groupe humain. Nous n’évoquerons pas davantage ce vaste sujet dans cet article (il faudrait un livre entier). À vous d’impliquer de la bonne façon les acteurs pertinents de vos organisations !

Parlons maintenant des points plus techniques.

Aperçu d’un processus de migration

Quelques généralités

Pour migrer sans risque de pertes de données, pensez bien à tester, tester et encore tester votre procédure ! Il est nécessaire d’effectuer vos tests sur une copie du cluster. Pour cela, pg_basebackup peut aider si vous optez pour une migration inplace.

Documentez bien votre procédure et mesurez le temps qu’elle prend afin de prévoir les temps d’indisponibilité. En effet, à partir du moment où la migration aura commencé (lors de la prise de sauvegarde), il faudra interdire les écritures sur le cluster. En revanche il sera souvent possible de faire des requêtes de lecture.

Enfin, pensez à établir une liste de tests à effectuer une fois la migration faite, pour s’assurer de sa bonne réalisation (par exemple en écrivant des tests pour toutes les vues modifiées lors des échecs précédents).

Cas simple : cluster sans PostGIS

Migrer un cluster sans PostGIS est souvent assez simple : on vérifie – toujours – le changelog, on corrige ce qui nous impacte, un coup de pg_upgrade et c’est finit.

On reteste quand même ses vues, parce que les versions récentes de PostgreSQL sont plus strictes sur le typage des requêtes (*). De plus, certaines données du méta-schéma peuvent changer, pensez à vérifier si vous vous appuyez dessus. Il y a d’autres petits changements cassants, mais tout cela est finalement assez facile à résoudre.

Avec PostGIS (et d’autres extensions, notamment celle utilisant des fonctions externes), il faut faire un peu plus attention.

Cas simple : même version de PostGIS

Le grand principe : utiliser pg_upgrade si vous mettez à jour uniquement la version de PostgreSQL (et gardez la même version de PostGIS donc).

Si vous restez sur les mêmes versions de PostGIS, alors le processus de migration sera le suivant:

  • installer les paquets de la nouvelle version de PostgreSQL et ceux de PostGIS qui correspondent à cette version de PostgreSQL (ou compiler les sources par exemple)
  • utiliser pg_upgrade (ou pg_upgradecluster sous debian/ubuntu) pour migrer le cluster. Il peut être sage de bloquer le port temporairement, car pg_upgrade utilisera ce port pour le nouveau cluster (le vieux cluster sera sur le port libre suivant), il faudra que vous fassiez quelques vérifications de donnée avant d’ouvrir le nouveau cluster aux utilisateurs.

Cas plus compliqué : version différente de PostGIS

Là, on sera obligé de passer par un pg_dump / pg_restore, à l’ancienne.

Par soucis de complétude, sachez que certaines personnes tentent des opérations de haute voltige à coup de liens symboliques dans le répertoire de lib de PostgreSQL. Je le déconseille (**) : vous n’aurez aucun retour si certaines de vos vues sont invalides car utilisant des fonctions supprimées par exemple. Au contraire, pg_restore refusera de rétablir les vues en question ce qui vous permettra de les corriger immédiatement.

Il ne sera pas possible ici de détailler précisément le processus car il va dépendre de beaucoup de facteurs. Néanmoins, dans les grandes lignes :

  • quand on migre un cluster, on migre les bases de données avec pg_dump, mais aussi les objets globaux (roles, permissions globales, etc…) avec pg_dumpall –globals-only. pg_dumpall est également capable de sauvegarder les bases de données (comme pg_dump), mais il ne sait pas le faire dans le format custom (option -Fc de pg_dump), ce qui est pour moi une grosse perte de flexibilité dans notre cas.
    # Les objets globaux
    pg_dumpall --globals <options de connexion>  > globals.sql
    # et pour chaque base
    pg_dump -Fc <options de connexion> > db.dump
    exemple de commandes pour un dump
  • il faut d’abord restaurer les objets globaux, puis chaque DB après l’avoir créé et activé PostGIS.
    # restauration des objets globaux
    psql <options de connexion> -f ./globals.sql
    # puis pour chaque base
    psql <options de connexion> -c "create database foo"
    psql <options de connexion> -d foo -c "create extension postgis"
    pg_restore --exit-on-error <options de connexion> db.dump
    Exemple de commandes pour la restauration
  • Utilisez l’option –exit-on-error de pg_restore. C’est essentiel pour ne pas manquer des erreurs à la restauration. Alternativement, vous pouvez rediriger tous les logs dans un fichier et l’examiner ultérieurement. Mais après la première erreur, vous n’aurez pas la certitude que les suivantes ne sont pas simplement une conséquence de celle-ci. Avec exit-on-error,  pg_restore s’arrête immédiatement et vous oblige à corriger au fur et à mesure vos vues, ce qu’il faudra faire de toutes façons.
  • Certaines erreurs ne sont pas importantes. Par exemple, la création du schéma public échouera probablement. Vous pouvez supprimer ce schéma avant la restauration, mais il est aussi possible d’exclure des instructions de façon sélective lors de la restauration, avec la fonction de liste de pg_restore :
    # récupérer la liste et y enlever les deux instructions de création et de commentaire du schéma public 
    pg_restore --list fichier.dump | grep -v "SCHEMA.*public" > valid_schemas.list
    # puis on peut utiliser ce fichier de list avec --use-list
    pg_restore --use-list valid_schemas.list [...] fichier.dump
    Exclure le schéma public de la restauration
  • puis il faut itérer sur ce processus en corrigeant / mettant à jour la base source jusqu’à ce que la restauration passe !

Parmi les incompatibilités que vous pouvez rencontrer :

  • Celles liés aux changements PostgreSQL (voir la partie sur la migration sans postgis).
  • remplacer les fonctions PostGIS qui ont été renommées ou supprimées.

C’est trop long, que faire ?

J’ai déjà rencontré des bases si grosses que le temps d’indisponibilité nécessaire à la migration semblait ingérable.

On parle de bases de taille supérieure à 100GB et dont la restauration dépassait la semaine ! Là, normalement, le sysDBA chevronné que vous êtes doit se dire : « mais attends, même pour 200GB ça ne doit pas prendre la semaine non ? ».

Tout à fait ! Dans tous les cas de restauration très longue que j’ai rencontré, c’était en fait le rafraîchissement des vues matérialisées, que certains utilisateurs semblent beaucoup beaucoup aimer, qui était interminable.

Si vous pensez être concerné, pensez à faire le ménage dans vos anciennes vues (« cette vue qui mets 8 jours à se rafraîchir est-elle vraiment critique pour mon activité ? »). Voire même prendre un peu de temps pour l’optimiser (« Oh, une vue qui dépend de cette autre vue qui elle-même dépend d’une autre… et aucune n’a d’index géographique ! »).

Mais quelque fois, ce n’est pas si simple et surtout, celui qui migre n’est pas nécessairement celui qui a créé ces vues, ce qui peut rendre le travail très fastidieux voire impossible à court terme. Dans ce cas, pensez à utiliser le système de liste d’archive décrit plus haut (options –list et –use-list de pg_restore avec le format d’archive custom de pg_dump). En excluant toutes les lignes contenant « MATERIALIZED VIEW DATA », vous pourrez restaurer votre archive sans rafraîchir ces vues, et le faire plus tard.

# récupérer la liste et enlever le rafraîchissement des vues matérialisées
pg_restore --list fichier.dump | grep -v "MATERIALIZED VIEW DATA" > without_refresh.list
# puis on peut utiliser ce fichier de list avec --use-list
pg_restore --use-list without_refresh.list [...] fichier.dump
Exclure les rafraîchissement de vues matérialisées

Pour ce rafraîchissement, vous pouvez vous inspirer de ces requêtes d’exploration du graphe de dépendances des vues. Il est même possible de n’en restaurer qu’une partie, si vous sélectionnez les parties de l’arbre de dépendances qui correspondent ! C’est un peu technique mais très efficace 🙂

Conclusion

Migrer un vieux cluster PostgreSQL avec PostGIS n’est pas forcément une mince affaire. Elle demandera de prendre le temps de tester et de mettre à jour l’ancienne base de donnée, ce qui est long et fastidieux. Si vous pouvez, il est toujours mieux de le faire régulièrement, car cela diminue la surface de migration et en général permet de rendre le processus moins difficile.

Si vous avez déjà plusieurs versions de retard, pas de panique ! Les outils à votre disposition de l’univers PostgreSQL vous permettront d’arriver à vos fins, au prix d’un peu d’effort.

Quelques conseils pour rendre les prochaines migrations plus faciles :

  • Migrez régulièrement
  • Faites du ménage régulièrement
  • Faites des sauvegardes régulièrement
  • Rajoutez des test unitaires pour les données et fonctions critiques (pourquoi pas avec pgtap si vous êtes du genre postgres-centrique ?)
  • Ne céder à la tentation de la vue matérialisée qu’en ultime recours ! Avant cela optimisez vos vues en vérifiant leur plan d’exécution, posez des index, revoyez les requêtes et éventuellement votre modèle, etc. Faites simple !
  • Quand on peut, avoir un environnement de pré-prod ou recette pour tester le bon fonctionnement des applicatifs utilisant votre base est un vrai plus.

 

(*) Je n’ai pas trouvé dans les changelogs la référence à ce changement cassant, mais je l’ai souvent constaté sur des upgrade de versions < 10.

(**) Ceci étant dit, si vous êtes joueurs et sûrs de vous, n’hésitez pas à tester et à me faire un retour ! J’ai tenté, ça peut marcher, mais c’est finalement moins pratique que le pg_dump/pg_restore selon moi.