2 points par GN⁺ 2023-07-16 | 1 commentaires | Partager sur WhatsApp
  • 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 test avec une clé primaire id et les colonnes value1~value4 (float8) et ts (timestamp)
    • Création d’un index sur value1, value2, value3, value4 et ts
  • Le script pgbench est de type upsert, avec mise à jour clairsemée d’un index en cas de conflit
    • Il exécute des INSERT avec des id aléatoires dans la plage 1~10,000,000 et, en cas de conflit, met à jour uniquement ts
    • Cette mise à jour clairsemée provoque du bloat d’index dans les tables PostgreSQL heap classiques
  • 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

 
GN⁺ 2023-07-16
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 arbitraire
    PostgreSQL est très, voire extrêmement, conservateur sur la sécurité des données, et cela est principalement assuré par des fsync au bon moment, avec un impact qui se propage à toute la pile d’I/O, jusqu’au firmware des SSD, ce qui ralentit l’ensemble
    Le 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

    • OrioleDB utilise un WAL au niveau des lignes, mais continue d’utiliser des pages. Ce WAL au niveau des lignes est rendu possible par des checkpoints en copy-on-write, qui fournissent une image structurellement cohérente du B-tree. Voir le document d’architecture pour les détails
      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

    • L’auteur y a déjà répondu dans une réponse au billet
      « 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 »
    • C’est un peu agressif alors que personne ne va mettre ça en production dans les prochains jours. Il n’y a même pas d’intention de soutenir financièrement le projet, et en plus, comme d’autres l’ont souligné, la question avait déjà reçu une réponse
      La prochaine fois, mieux vaudrait éviter d’entrer aussi durement dans le sujet dès le départ
    • Il y a un lien de référence qui répond déjà à la question :)
      https://news.ycombinator.com/item?id=36742001
    • C’est un point raisonnable. Ayant déjà rencontré des problèmes de VACUUM par le passé, je me demandais si c’était fondamentalement nécessaire ou si cela pouvait être corrigé
      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

    • Les enregistrements d’annulation sont tronqués dès qu’ils ne sont plus nécessaires à aucune transaction
      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
    • SQL Server évite lui aussi VACUUM, donc c’est peut-être le même genre d’approche
      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 pense que tu parles probablement de ce passage : « OrioleDB consists of an extension, building on the innovative table access method framework and other standard Postgres extension interfaces. »
      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 à GiST, nous réfléchissons à construire un B-tree sur une courbe de remplissage de l’espace. Nous prévoyons aussi d’ajouter une union key aux pages internes afin de rendre la recherche dans cet arbre plus rapide et plus simple
      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 ?

    • OrioleDB est vu comme le moteur du futur pour PostgreSQL, et on aimerait qu’il devienne le moteur par défaut.
      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.
    • L’avis d’Alexander Korotkov semble fondé sur son expérience de committer Postgres : ces changements sont trop vastes pour être acceptés dans l’upstream, donc ils passent par un moteur séparé.
      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.
    • Ces changements sont trop importants pour être intégrés au moteur PostgreSQL lui-même. Ils modifient fondamentalement la méthode MVCC.
  • 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.

    • Si PostgreSQL a besoin d’une procédure de mise à niveau, ce n’est généralement pas à cause du format on-disk bas niveau du heap Postgres ou de la méthode d’accès aux tables d’OrioleDB, mais à cause des modifications du catalogue Postgres.
      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.
    • À première vue, cela semble impossible à atteindre, sauf à accepter de sacrifier beaucoup de performances. Le format on-disk n’est modifié que lorsqu’il y a de bonnes raisons de le faire.
    • Je ne vois pas très bien en quoi cela aiderait. PostgreSQL promet déjà en pratique un format on-disk stable pour les tables et les index, ce qui permet à pg_upgrade de fonctionner.
      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 ?

    • En général, mieux vaut exploiter le CPU au maximum. Oriole semble avoir des besoins en I/O bien plus faibles, traiter bien plus de transactions et être ainsi devenu limité par le CPU
      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
    • Mon interprétation, c’est que le CPU a été saturé à 90 % à cause du seuil de TPS utilisé pour la comparaison. Au moins sur ce graphique, le TPS d’Oriole est stable et bien plus élevé que celui de pg
      Si on baisse le TPS, le CPU baissera proportionnellement lui aussi, et ici ils semblent vouloir montrer jusqu’où ça peut monter
    • Une fois la limite d’utilisation CPU levée, ce n’est pas vraiment un problème, car il devient facile de réduire l’utilisation tout en conservant une certaine proportionnalité des performances
      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
    • Les performances sont maintenant 5x meilleures sur le même matériel. Le TPS est 5x plus élevé. Il faudrait refaire des tests avec davantage de matériel, mais si 3x les performances se maintiennent aussi dans la partie basse, cela pourrait être une bonne alternative pour certains utilisateurs
      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
    • C’était un test de performance, et l’objectif était probablement d’appliquer en continu la charge maximale que chaque moteur de base de données pouvait supporter sur une longue durée
      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

    • Rick est un diminutif de Richard
    • « Richard Branson » n’est pas un identifiant unique. On devrait peut-être tous utiliser des UUID
    • Moi aussi, ça m’a sauté aux yeux. Je me demandais bien pourquoi je devrais me soucier de l’avis du CEO de Virgin sur les bases de données
      Ah, ce n’était pas cette personne