Le 23 mars 2017, s’est déroulé le PGDAY Paris. Petite session d’approfondissement sur un sujet où l’on trouve tout et son contraire : l’utilisation de pgbench
pour tester les performances de son serveur.
Pour les détails et les résultats en chiffres et en graphiques, c’est sur le site de l’orateur.
Un bon benchmark
Measuring and Reducing PostgreSQL Transaction Latency par Fabien Coelho
Je dois reconnaître que pendant cette conférence dynamique et passionante, la rigueure scientifique était au premier plan. Fabien Coelho est chargé de recherche à l'école des Mines de Paris, et cela se voit.
Il explique pourquoi le benchmarking des bases de données est important, comment celui-ci peut être fait avec rigueur, mais aussi comment utiliser pgbench de la bonne façon.
**Note du rédacteur :** Si cette information n'était pas jusqu'à présent une évidence pour vous, sachez qu’utiliser cet outil dans son mode par défaut est clairement dénué de sens. Ce que j’entends par là : multiplier clients, threads, nombre de transactions avec des sessions de benchmarking uniques sur une durée inférieure à 1 minute.
Autre non-sens : ne pas tenir compte de la vie d’une BDD (augmentation de la fragmentation et du volume de données sans parler des spécificités dues au schéma ou à l’utilisation). Fin de la parenthèse
Pour résumer, le nombre de transactions par seconde (tps) n’est pas tout, il faut également garder en ligne de mire une autre résultante : la latence (en ms). L’intervenant se base donc sur les tps et la latence pour faire ses mesures et il argumente parfaitement sa thèse. L’initialisation de la BDD de bench est variable selon le cas : base de données principalement en cache ? En RAM ? Sur disque ?
Je vous conseille pour démarrer ce wiki qui permet de choisir la taille de jeu de données correspondante à vos besoins.
Le paramètre -i avec l’option -s permet de choisir l'échelle de la BDD de bench avec l'échelle correspondant à l’ensemble de données à tester. Sont utilisés les scripts tpc-b like de bench de Postgres ainsi que les scripts de lecture seule, instruction préparée (prepared statement) ou language procédural.
Hacks
-
Tout d’abord, les “Hacks” de l’intervenant et ici première remarque : si vous activez le ssl sur votre instance assurez vous que vous avez un certificat pour aller avec. Sans celui-ci la sécurité du ssl n’a pas d’intérêt et c’est un gouffre en performance. En second lieu, les connexions à l’instance peuvent s’avérer coûteuses il faut donc les prendre en compte (option -C).
-
Si vous avez des problèmes de performances, et que vous vous trouvez en version inférieure à 9.6, migrez (VITE) car la gestion du flush sur disque des checkpoints comporte des améliorations avec un impact important sur les performances en écriture. On passe donc d’une écriture sur disque aléatoire auparavant à une écriture ordonnée (sorted) et un flush des instructions plus régulier (256kB) qui permet d'éviter un goulet d'étranglement (tempête d’entrées/sorties = i/o storm).
Tests
Par la suite, les tests de performance s’effectuent avec deux paramètres ajoutés assez récemment, -R (rate) et -L (limit), qui permettent de définir un taux cible et un taux limite de tps que le test doit atteindre. Les transactions ne parvenant pas à passer le test sont tracées dans un log à part. De plus, le paramètre -N permet d'éviter certains UPDATE (script avec update unique par transaction).
- Le gain de performance sur l’option fillfactor (defaut=100 contre 95) est appréciable mais ceci n’est que l’apéritif.
- Encore une fois, il est conseillé d’acquérir du matériel (et notamment des disques) de qualité. Préférez donc le SSD au HDD lorsque c’est possible. La différence de performance entre les 2 est flagrante : latence 10 fois plus petite et tps 10 fois plus nombreuses.
- Table UNLOGGED contre table standard, l’avantage performance va clairement à UNLOGGED (au détriment de l’ACIDité des transactions) qui donne un résultat comparable au hack précédent (10 fois meilleur).
- Les instructions préparées (prepared statements) montrent un gain (20%) par rapport aux requêtes simples.
- Les requêtes avec client combiné (;) permettent d'éviter d’attendre la réponse de la transaction au serveur pour renvoyer un requête et obtenir un ensemble de résultats en liste à la suite les uns des autres (e.g. pour une série de SELECT). Gain de facteur 2.
- Dans le cas de language procédural (ici une fonction stockée) on trouve une différence de facteur 3 (le PL/pgSQL garde le plan en cache après la première exécution).
Par la suite, l’impact du réseau est abordé avec par ordre croissant de performance : LAN, local, Socket Unix, sur disque dur puis sur SSD.
- HDD : Socket et local sont 10% plus rapides que LAN (tps et latence)
- SDD : local et socket sont environ 3 fois plus rapides que LAN (et le socket est 10% plus rapide que local)
Plus de Tests
Puis on passe par l'étape du compromis : latence et tps ne vont pas forcément de pair, cela dépend du nombre de clients. Les deux décrivent chacun une courbe croissante mais ont un profil assez différent. Il faut trouver le point qui maximise les tps avec un minimum de latence. Ceci permet de déterminer le niveau de fonctionnement optimal de la configuration avec nos données, nos paramètres Postgres et système, la qualité de notre matériel.
En guise d’ouverture pour la suite, les paramètres d’optimisation que l’on retrouve classiquement sont mentionnés pour permettre de faire évoluer les résultats obtenus pour tenter d’améliorer encore les performances : shared_buffers
, effective_cache_size
, format des FS (ext4 ou xfs), et ainsi de suite…
Conclusion
Pour conclure, petit rappel :
- ne pas se focaliser sur les TPS uniquement (regarder la latence également) ;
- Utiliser la version 9.6 (ou au dessus quand celle-ci sera disponible).
Mais ce n’est pas tout. Un test de benchmarking doit être suffisamment long, c’est à dire qu’il doit inclure des évènements tels que Checkpoints, VACUUM, ANALYZE qui modifient sensiblement la réponse du serveur.
Commencer par choisir la bonne configuration de départ (échelle) en fonction de la taille du jeu de données que l’on cherche à optimiser.
Les tests doivent être reproductibles et lisser les artéfacts, facteurs aléatoires et le bruit de fond en faisant des moyennes.
Il faut donc faire donc plusieurs fois le même test sans changer les paramètres.
Surtout ne pas se fier aux tests faits par d’autres sur des configurations matérielles, systèmes, serveur Postgres inconnues et non documentées : il est important de faire vos propres tests dans le contexte qui vous concerne.
Vos instances ne fonctionnent pas toujours au maximum de leurs capacités ? C’est une bonne nouvelle et c’est pour cette raison qu’un bench ne devrait pas (uniquement) tester avec des gros volumes de transactions (e.g.-T 1000000) qui ne reflètent pas la réalité de la vie de vos instances. Il faut aussi tester des plus longs bench avec -R, -L et -N (mais aussi -C).
Tout ceci doit sembler fastidieux, et une automatisation des tests peut donc sembler une bonne solution…
Conclusion du rédacteur
Pour ceci, tentez votre chance avec pgbench_tools !
Et si vous voulez bencher Postgres 9.6 tentez cette version avec les modifications ad hoc.