PostgreSQL : fini VACUUM et le bloat
(orioledata.com)- OrioleDB, un nouveau moteur de stockage pour PostgreSQL, élimine le processus VACUUM, gourmand en ressources, et résout le problème de bloat des tables
- Dans PostgreSQL classique, l’architecture MVCC impose le vacuum manuel et l’autovacuum, deux mécanismes qui consomment tous deux beaucoup de ressources système
- OrioleDB traite efficacement les modifications de données et consolide les données fragmentées grâce à un undo log au niveau ligne et bloc et à la fusion automatique des pages
- Dans un benchmark synthétique, avec mise à jour d’un seul index, fusion automatique des pages clairsemées et WAL au niveau ligne, il atteint un TPS 5 fois supérieur tout en réduisant la consommation de ressources
- En réglant ce problème historique qu’est VACUUM, il allège la maintenance et améliore les performances et l’expérience utilisateur de PostgreSQL
Histoire et limites de VACUUM dans PostgreSQL
- Le processus VACUUM est un héritage historique du concept d’infinite time-travel du projet Berkley Postgres, concept qui a ensuite été abandonné par la communauté
- Il a toutefois conduit à une implémentation du système MVCC (Multi-Version Concurrency Control) vulnérable au bloat des tables
- Le MVCC est avantageux pour le traitement des transactions concurrentes, mais il introduit la nécessité d’un vacuum manuel pour nettoyer les données anciennes et inutiles
- Le vacuum manuel est une tâche très laborieuse et une source potentielle d’inefficacité système
- Pour réduire ensuite la charge du travail manuel, un autovacuum automatisé a été introduit
- Ce fut un grand progrès, mais pas une solution parfaite, et malgré son automatisation, il consomme toujours beaucoup de ressources système
- C’est l’une des raisons pour lesquelles Uber a migré de PostgreSQL vers MySQL, et l’un des 10 points de mécontentement vis-à-vis de PostgreSQL évoqués par Richard Branson
- L’introduction des mises à jour Heap-Only Tuples (HOT) et du microvacuum a réduit le besoin d’un vacuum complet des tables
- Malgré cela, VACUUM reste une opération gourmande en ressources, et les tables restent vulnérables au bloat
- Il est mentionné comme l’aspect de PostgreSQL que l’équipe d’OtterTune déteste le plus
- Malgré ces limites, de nombreuses organisations et développeurs continuent d’utiliser PostgreSQL pour sa robustesse, son extensibilité et la force de sa communauté
- OtterTune a reconnu le problème tout en décidant de continuer à utiliser PostgreSQL
Fonctionnalités clés d’OrioleDB
- OrioleDB est un nouveau moteur PostgreSQL développé avec pour objectif principal de protéger les tables contre le bloat et d’éliminer le besoin de maintenance périodique comme VACUUM
- Il y parvient grâce à un undo log au niveau ligne et bloc et à la fusion automatique des pages
- L’undo log au niveau ligne et bloc offre un contrôle plus fin, permettant de gérer plus efficacement les modifications de données
- La fonction de fusion automatique des pages consolide en continu les données fragmentées en arrière-plan
- Fonctionnement de chaque technique
- L’undo log au niveau ligne permet les mises à jour in-place
- L’undo log au niveau bloc supprime du stockage principal les tuples supprimés mais encore visibles pour certaines transactions, libérant ainsi de l’espace pour de nouveaux tuples
- La fusion automatique des pages clairsemées protège tables et index contre le bloat, même après de nombreuses suppressions
- Au final, l’intervention manuelle diminue, la consommation de ressources baisse et la vulnérabilité des tables au bloat recule
Benchmark
- Un benchmark synthétique a été construit à partir d’un script d’initialisation créant 1 table et 5 index
- Création de la table
testavec une clé primaireidet les colonnesvalue1~value4(float8) etts(timestamp) - Création d’un index sur
value1,value2,value3,value4etts
- Création de la table
- Le script pgbench est de type upsert, avec mise à jour clairsemée d’un index en cas de conflit
- Il exécute des
INSERTavec desidaléatoires dans la plage 1~10,000,000 et, en cas de conflit, met à jour uniquementts - Cette mise à jour clairsemée provoque du bloat d’index dans les tables PostgreSQL heap classiques
- Il exécute des
- Ce benchmark met en évidence les avantages de la conception d’OrioleDB
- Grâce à l’undo log et aux mises à jour in-place, OrioleDB ne met à jour que l’index dont la valeur a changé, alors que dans le moteur heap de PostgreSQL, la mise à jour d’un seul champ indexé désactive HOT et force la mise à jour de tous les index
- La fusion automatique des pages protège les index clairsemés contre le bloat, les pages clairsemées étant fusionnées automatiquement
- Le WAL au niveau ligne occupe bien moins d’espace que le WAL au niveau bloc, ce qui réduit les IOPS lors de l’écriture du WAL
- Résultats chiffrés cumulés apportés par OrioleDB
- TPS 5 fois supérieur par transaction
- Charge CPU 2,3 fois plus faible par transaction
- IOPS 22 fois plus faibles par transaction
- Aucun bloat des tables ni des index
Importance d’OrioleDB
- Avec l’arrivée d’OrioleDB, la communauté PostgreSQL entre dans une nouvelle ère où VACUUM peut appartenir au passé
- Il propose une solution à l’un des plus anciens problèmes de PostgreSQL, tout en apportant aux utilisateurs plus d’efficacité et moins de maintenance
1 commentaires
Avis sur Hacker News
Il reste quand même quelques points qui me gênent. Le traitement au niveau des lignes crée des problèmes d’ordonnancement des écritures et de
fsync, alors que les pages sont plus faciles à ordonner que des lignes de taille arbitrairePostgreSQL est très, voire extrêmement, conservateur sur la sécurité des données, et cela est principalement assuré par des
fsyncau bon moment, avec un impact qui se propage à toute la pile d’I/O, jusqu’au firmware des SSD, ce qui ralentit l’ensembleLe MVCC est excellent pour les accès concurrents, mais la documentation d’Oriole n’indique pas dans quelles conditions de concurrence les graphiques ont été obtenus
Le titre et l’introduction de la documentation d’Oriole mettent l’accent sur la résolution de VACUUM, mais cela ne semble pas vraiment démontrer que le graphique en « onde carrée » observé dans PostgreSQL est, dans la plupart des cas, principalement dû à VACUUM. D’autres benchmarks de Percona (https://www.percona.com/blog/evaluating-checkpointing-in-postgresql/) ne montrent pas un motif en onde carrée aussi net
Les auteurs sont sûrement au courant de ces questions, donc un aperçu de leur approche serait bienvenu
https://github.com/orioledb/orioledb/blob/main/doc/arch.md
Comme PostgreSQL est conservateur sur la sécurité des données, le premier objectif est d’en faire une extension pure. Pour devenir une partie de PostgreSQL, il faudra l’épreuve du temps
Il est vrai que les informations sur la concurrence manquaient, et le billet de blog a été mis à jour avec le type de VM et les informations de concurrence
Le motif en onde carrée est bien dû aux checkpoints. Ici, l’amélioration ne vient pas en fait de VACUUM, mais de la manière de ne modifier que les index concernés, ainsi que du WAL au niveau des lignes qui réduit les I/O globales
C’est impressionnant, mais je me demande comment ils comptent suivre le cycle de release du projet parent
Ils ont forké un grand projet open source et y ont ajouté des modifications importantes ; si l’on ne pense pas que ces changements seront acceptés en upstream, je ne suis pas sûr que ce soit une bonne idée
Il faut clarifier s’il s’agit d’un jouet fait pour le plaisir ou d’un projet sérieux destiné à être maintenu à long terme
Si c’est un projet sérieux, il faudrait indiquer le plan pour éviter qu’il ne devienne un logiciel abandonné, le plan pour absorber les futures releases du projet d’origine, ou bien le plan pour partir sur un projet complètement séparé
Comme c’est une extension, on peut imaginer qu’elle pourra intégrer les changements upstream de PostgreSQL, mais si c’était si simple, elle ferait probablement déjà partie du projet PostgreSQL ; cela ne semble donc pas si facile
« Exact. Mais la route est longue. Pour l’instant, OrioleDB est une extension livrée avec des patchs sur le cœur de PostgreSQL. L’objectif à moyen terme est de faire d’OrioleDB une extension pure, et l’objectif à long terme est de faire d’OrioleDB une partie du cœur de PostgreSQL »
La prochaine fois, mieux vaudrait éviter d’entrer aussi durement dans le sujet dès le départ
https://news.ycombinator.com/item?id=36742001
Voir un exemple de correction est en soi clairement utile. Si une entreprise a les ressources pour maintenir un fork de Postgres, tant mieux ; sinon, il faut évaluer si la difficulté d’utiliser ce fork vaut le gain de performance
J’aimerais qu’on arrête avec les histoires du genre « Uber est passé de Postgres à MySQL ». Uber n’a pas migré depuis Postgres utilisé comme base de données relationnelle vers MySQL utilisé comme base relationnelle, mais vers ce qui est en pratique sa propre base de données non relationnelle, utilisant MySQL comme magasin distribué clé-valeur, donc ce n’est pas une situation applicable telle quelle à la plupart des utilisateurs de Postgres
Quoi qu’il en soit, ce type de conception MVCC qui déplace les anciennes données vers des logs/segments d’annulation est aussi utilisé dans Oracle DB, donc son fonctionnement est éprouvé
La difficulté commune, c’est que la lecture d’anciennes versions des données devient plus lente. Il faut les retrouver dans les logs et, parfois, les données sont supprimées des logs avant la fin de la transaction, ce qui peut provoquer la tristement célèbre erreur Snapshot Too Old
Je n’ai pas vu dans l’article à quel moment une ligne est supprimée du log d’annulation. Si c’est supprimé quand ce n’est plus nécessaire, il faudra sans doute une quantité de maintenance comparable, donc je ne vois pas bien d’où viendrait l’amélioration ; et si c’est un tampon circulaire pouvant se retrouver à court d’espace comme dans Oracle, alors, sous forte charge d’écriture, les transactions longues commencent à échouer, ce qui est assez désagréable
Cela dépend de ce qu’on entend exactement par « travail de maintenance ». En termes de volume de travail, les anciens enregistrements d’annulation peuvent être supprimés en lot à très faible coût, par exemple en unlinkant des fichiers. Il n’y a pas besoin de scan VACUUM
En termes d’utilisation de l’espace, oui, le même nombre de versions occupera la même quantité d’espace. Mais stocker les anciennes versions de lignes dans un stockage séparé peut empêcher la dégradation à long terme du stockage principal. OrioleDB implémente aussi une fusion automatique des pages clairsemées
OrioleDB implémente un tampon circulaire en mémoire pour le log d’annulation. Si le tampon circulaire ne peut pas contenir tous les enregistrements d’annulation, les plus anciens sont déversés vers le stockage. Actuellement, il n’y a pas de limite sur la taille du log d’annulation, et les enregistrements sont conservés tant qu’une transaction quelconque peut en avoir besoin, donc il n’y a pas d’erreur « Snapshot Too Old »
Cela dit, on pourrait envisager d’implémenter en option une erreur à la Oracle afin de pouvoir limiter la taille des annulations. Cela vaut aussi le coup de consulter le document d’architecture sur GitHub
https://github.com/orioledb/orioledb/blob/main/doc/arch.md
Bien sûr, MySQL évite VACUUM en faisant d’importantes concessions sur la concurrence
Le titre m’avait donné envie, mais ma première impression a été la frustration. Le README principal sur GitHub[1] ressemble à du blabla marketing d’entreprise
Tout ce que j’ai compris jusqu’ici, c’est qu’OrioleDB est un nouveau moteur de stockage pour PostgreSQL, que PostgreSQL est la base de données « la plus appréciée », qu’OrioleDB est une extension construite au-dessus d’autres extensions, et qu’OrioleDB ouvre les portes du cloud
Après les arnaques crypto et Web 3.0, j’ai l’impression qu’on aurait évité ce genre d’approche pour présenter un projet qui étend et améliore quelque chose d’aussi important que PostgreSQL
[1] https://github.com/orioledb/orioledb
Je ne vois pas trop comment l’écrire plus clairement. La méthode d’accès aux tables est une fonctionnalité introduite dans PostgreSQL pour prendre en charge des stockages alternatifs comme zheap ou des stockages en colonnes
Le mentionner est important. Il existe pas mal de forks de PostgreSQL qui superposent un système de stockage alternatif, alors qu’OrioleDB est conçu pour fonctionner comme extension sur un PostgreSQL non forké. Ce n’est pas encore le cas aujourd’hui, mais c’est bien la direction visée
Si on connaît bien PostgreSQL, le README paraît assez clair
La conception d’Oriole semble exiger des index conscients des transactions et la suppression d’entrées au niveau ponctuel, ce qui a un coût spécifique
Par exemple, l’équivalent de GiST pour les index spatiaux semble difficile à maintenir à cause de la nature même de ces index, où l’on ne peut pas connaître précisément la position de chaque tuple d’index ; et l’équivalent de GIN pour l’indexation full-text pourrait devenir énorme à cause d’une moins bonne compressibilité des posting trees
J’ai aussi du mal à imaginer comment implémenter un équivalent de BRIN dans une situation où l’on utilise une table de composition d’index. BRIN est utile parce qu’il permet d’exclure rapidement de grands intervalles de la table physique des résultats de requête quand ils ne contiennent rien d’intéressant. On pourrait partitionner par plages de clés primaires, mais la densité des valeurs d’une clé primaire peut varier énormément selon le temps et la plage de valeurs
Je suis curieux de savoir comment ils prévoient d’implémenter ces méthodes d’index plus complexes mais très utiles
Il y a aussi le problème potentiel des règles de tri, c’est-à-dire des collations, quand elles changent. Le heap et VACUUM de Postgres ne connaissent pas l’ordre de tri, donc après un changement de collation, on peut souvent corriger une corruption en supprimant puis en réinsérant les lignes mal placées, et VACUUM finit par nettoyer les tuples cassés
Avec Oriole, cela semble plus difficile parce qu’on ne peut pas retrouver le tuple d’origine à supprimer via une recherche ponctuelle, et il est probable qu’il faille reconstruire l’index en entier pour corriger des cas connus de corruption d’index, ce qui donne l’impression d’une maintenance assez lourde
Pour quelque chose de comparable à GIN, la compression des posting lists reste possible. Une option envisageable est de relier les enregistrements d’annulation à la posting list entière plutôt qu’à un seul élément de la posting list
Pour BRIN, comme nous utilisons une table de composition d’index, il ne semble pas possible d’avoir un équivalent direct. En revanche, il pourrait y avoir des choses intéressantes à faire avec les union keys dans les pages internes de la clé primaire
Le problème des collations est réel et grave. Avant d’atteindre la GA, il faudra figer tous les index sensibles à la collation sur une version de collation libicu donnée
Le raisonnement de l’article est convaincant et les benchmarks semblent étayer les affirmations sur les performances, mais la distinction proposée entre le nouveau moteur de stockage, à savoir OrioleDB, et PostgreSQL lui-même n’est pas très claire.
En dehors des motivations commerciales et de la volonté de monétiser les innovations présentées dans l’article, y a-t-il une raison de le commercialiser comme une nouvelle base de données appelée OrioleDB au lieu de contribuer cette amélioration à l’upstream ?
Mais les changements d’OrioleDB sont trop importants pour être intégrés progressivement. C’est pourquoi la comparaison porte sur OrioleDB face au moteur actuel de PostgreSQL, non seulement le heap mais aussi plusieurs sous-systèmes sous-jacents.
Pour plus de détails, voir notamment les slides 9 à 11 de https://www.socallinuxexpo.org/sites/default/files/presentations/solving-postgres-wicked-problems.pdf.
S’il s’agit d’une extension de moteur, je me demande s’il y a un impact lorsqu’on l’utilise avec d’autres extensions. Par exemple, timescaledb[0] fonctionne sur des tables sous-jacentes.
Je me demande quel effet cela aurait de faire quelque chose comme ceci :
create table xyz(...) using orioledb;select create_hypertable(xyz, ts);[0] https://github.com/timescale/timescaledb
OrioleDB souhaite-t-il promettre un format on-disk stable afin d’éliminer la nécessité d’une procédure de mise à niveau entre les versions majeures de Postgres ? Cela semble être une occasion de résoudre ce problème.
L’ajout de nouveaux types et de leurs fonctions de support, par exemple, doit être injecté via une procédure de mise à niveau. Il existe aussi d’autres changements du catalogue, comme la modification de l’agencement des colonnes dans les tables du catalogue, qui nécessitent également une procédure pour mettre à jour les données stockées entre les versions.
Sans procédure de mise à niveau, il serait impossible de modifier le catalogue. C’est pour cela que seules les mises à niveau mineures de PostgreSQL peuvent se faire par simple remplacement des binaires, avec possibilité de rollback sûr et sans problème.
Si les mises à niveau étaient limitées aux seuls changements d’API internes, du planner et de l’exécuteur, le développement serait fortement contraint. Il semble peu probable qu’OrioleDB puisse supprimer la nécessité de cette procédure de mise à niveau.
L’essentiel du travail lors d’une mise à niveau de cluster vient de la réécriture des tables du catalogue. En outre, pour la plupart des workloads, pg_upgrade est déjà très rapide, donc je ne vois pas vraiment où se situerait le gros gain.
La formulation « réduction de 2,3x de la surcharge CPU par transaction » me gêne. Postgres voit son utilisation CPU varier de 5 % à 65 %, alors qu’Oriole reste constamment à 90 %
La prévisibilité, c’est bien, mais faire grimper de 85 % la partie basse, ça semble quand même assez préoccupant, non ?
La bonne nouvelle, c’est qu’en faisant du scale-up avec un CPU plus puissant, on peut obtenir davantage de performances avec Oriole. À l’inverse, Postgres ne continuera probablement pas à monter en performances de la même manière
Du point de vue d’un OS de bureau, on pourrait utiliser les temps morts du serveur Postgres à autre chose, mais sur un serveur on veut généralement une machine qui fait une seule chose et qui est optimisée pour cette tâche
Si on baisse le TPS, le CPU baissera proportionnellement lui aussi, et ici ils semblent vouloir montrer jusqu’où ça peut monter
Si on limite le système à 60 % de CPU, les chiffres globaux peuvent changer, mais si le TPS est 1,8x plus élevé à utilisation égale, ça reste une victoire. Ça ressemble moins à un tour de passe-passe marketing qu’à un chiffre plutôt solide
Si un CPU serveur coûteux vaut X dollars l’unité, mais qu’on ne peut en utiliser que 60 % et qu’en pratique on n’utilise que ça, alors on brûle en quelque sorte 0,4X dollar par unité
Si on peut verticaliser la charge et saturer une machine à 90 %, il est généralement facile d’appliquer des techniques de QoS et d’isolation pour garder une saturation plus faible et des performances proportionnelles. L’inverse n’est pas vrai. Si on ne peut utiliser que 60 % de la saturation totale de la machine et qu’il faut faire du scale-out, il faut une refonte pour dépasser 90 %, et c’est précisément la refonte qui a eu lieu ici
D’après les résultats cumulés des améliorations, OrioleDB offrirait un TPS 5x plus élevé, une charge CPU par transaction 2,3x plus faible, 22x moins d’IOPS par transaction, et aucune inflation des tables ni des index
Si la charge CPU monte et descend, ce n’est pas parce que Postgres « scale », c’est parce qu’il rencontre périodiquement un goulet d’étranglement de performance. Probablement à cause de la nécessité d’exécuter VACUUM, qui est très sensible aux I/O
Postgres consacre donc ses I/O au nettoyage au lieu de les utiliser pour traiter les requêtes, et le TPS comme l’utilisation CPU chutent brutalement ensemble
À l’inverse, Oriole gère un débit bien plus élevé de façon bien plus constante. Que préférez-vous : une voiture qui tient régulièrement les 100 mph quand on appuie à fond, ou une voiture dont la pédale est au plancher mais qui oscille violemment entre 40 et 70 mph ?
L’article contient un lien avec un titre plutôt intriguant : « 10 choses que Richard Branson déteste à propos de PostgreSQL ». En regardant de plus près, on découvre que l’auteur du blog n’était pas Richard mais Rick Branson
Ah, ce n’était pas cette personne