Reviers, le 10 février 2025
Cela fait plusieurs mois maintenant que nous avons envoyé des patchs sur la liste de discussion des développeurs de PostgreSQL pour améliorer la supervision de la parallélisation. J’avais promis de revenir vers vous à ce sujet. Je l’ai fait lors d’une conférence à la pgsession 17 et je vais revenir rapidement ici sur ce sujet pour ceux et celles qui n’ont pas pu y assister.
En septembre 2024, Benoît et moi avons envoyé quatre patchs pour améliorer la supervision de la parallélisation d’une requête. Détaillons ces patchs et le retour qu’ils ont reçu.
Patch #1 : traces supplémentaires
L’idée des quatre participants (Benoît, Franck, Jehan-Guillaume et moi) du cowork de Nantes est d’avoir une trace permettant de savoir quand la parallélisation d’un nœud d’une requête a été demandée, le niveau de parallélisation demandé (nombre de workers planifiés), et le niveau de parallélisation atteint (nombre de workers réellement exécutés). Voici un exemple de la trace proposée :
LOG: 1 parallel nodes planned (1 obtained all their workers, 0 obtained none), 2 workers planned (2 workers launched)
Savoir qu’il n’y a aucune requête parallélisée ou, au contraire, savoir qu’il y en a plein, peut aider à quantifier les ressources allouées à la machine (ici, le nombre de CPU).
Savoir qu’il y a eu moins de workers exécutés que planifiés peut démontrer un
problème de configuration (notamment sur les paramètres
max_worker_processes
, max_parallel_workers
et
max_parallel_workers_per_gather
).
À Dalibo, on tient à conseiller nos clients en nous basant sur des constatations et force est d’avouer que cette trace supplémentaire nous aiderait grandement.
Ces traces ont donc un intérêt et le patch a logiquement suscité un intérêt de la part de la communauté. Suite aux réactions, le patch a été amélioré. Il en est aujourd’hui à sa version 6 et est divisé en plusieurs parties :
-
V6_0001-Add-a-guc-for-parallel-worker-logging.patch
ajoute un paramètre de configuration (log_parallel_workers
) permettant de contrôler la trace sur la parallélisation avec trois options : désactivé, activé pour toutes les opérations, activé seulement quand des workers manquaient. -
V6_0002-Implements-logging-for-parallel-worker-usage-in-inde.patch
ajoute la trace sur les requêtesCREATE INDEX
(attention, seuls les index B-tree et BRIN peuvent profiter de la parallélisation à leur création). -
V6_0003-Setup-counters-for-parallel-vacuums.patch
ajoute les compteurs de parallélisation pour tracer la parallélisation des requêtesVACUUM
. -
V6_0004-Implements-logging-for-parallel-worker-usage-in-vacu.patch
ajoute les traces sur la parallélisation des requêtesVACUUM
. -
V6_0005-Implements-logging-for-parallel-worker-usage-in-quer.patch
ajoute les traces sur la parallélisation des requêtesSELECT
(les compteurs ont été ajoutés par un autre patch dont nous parlerons après).
La trace est devenue plus simple :
launched 3 parallel workers (planned: 4)
Le but de la division en plusieurs patchs est de mieux comprendre la structure du patch global, de faciliter sa relecture, puis de permettre au commiter d’intégrer uniquement les parties qui lui semblent intéressantes et finalisées, si le patch global nécessite encore des discussions. Cela donne ainsi plus de chance au développeur de voir au moins une partie de son patch intégrée.
Actuellement, ce patch n’a pas été intégré. Il fait partie du commit fest de
janvier, à l’état Needs review
.
Patch #2 : pg_stat_database
Cette vue nous intéresse pour cumuler par base le nombre de workers de
parallélisation planifiés et le nombre de ceux réellement exécutés. Le patch
initial proposait quatre nouvelles colonnes, deux pour les requêtes SELECT
et deux pour les requêtes DDL (actuellement, seules les commandes DDL CREATE
INDEX
et VACUUM
sont parallélisables).
Là aussi, une bonne discussion a eu lieu sur l’intérêt de ces différentes
colonnes. Autant la présence de colonnes pour les requêtes SELECT
ne
suscite pas trop d’objections, autant celle des colonnes pour les requêtes
DDL est fortement contestée.
L’argument principal contre ces colonnes est qu’un CREATE INDEX
et un
VACUUM
sont des opérations manuelles et que l’opérateur peut voir lui-même
quand il lance l’opération si cette opération est parallélisée. Pour moi, cet
argument a du sens. Pour les « petits malins » qui objecteront qu’un VACUUM
est automatisé via le processus autovacuum
, je répondrais qu’ils ont bien
raison, mais que ce VACUUM
automatisé n’utilise pas la clause PARALLEL
qui permettrait sa parallélisation. Pour le dire autrement, l’autovacuum
ne
peut pas exécuter un VACUUM
parallélisé actuellement.
Donc l’argument est difficilement contestable et, de ce fait, seule la moitié du patch a été appliquée dans ce commit. Et voici le résultat lorsqu’on interroge ces nouvelles colonnes :
SELECT datname, parallel_workers_to_launch, parallel_workers_launched
FROM pg_stat_database
WHERE datname IS NOT null;
datname | parallel_workers_to_launch | parallel_workers_launched
-----------+----------------------------+---------------------------
postgres | 50 | 45
template1 | 0 | 0
template0 | 0 | 0
(3 rows)
Patch #3 : pg_stat_statements
La vue pg_stat_statements
donne des informations sur les requêtes exécutées.
Connaître la durée d’exécution, le nombre d’exécutions, l’utilisation du cache
ou de JIT sur ces requêtes aide beaucoup à leur optimisation. Il nous a donc
semblé intéressant d’ajouter des informations sur la parallélisation par
requête.
Le premier patch était un peu naïf, proposant ainsi sept nouvelles colonnes. Beaucoup ont été contestées et au final, le patch, en sa version 3, a été divisé en deux parties, bien plus modestes :
-
v3-0001-Introduce-two-new-counters-in-EState.patch
ajoute les compteurs de parallélisation pour tracer la parallélisation des requêtesSELECT
(ces compteurs sont aussi utilisés par les nouvelles colonnes de la vuepg_stat_database
). -
v3-0002-Add-parallel-columns-to-pg_stat_statements.patch
ajoute les deux colonnes acceptées danspg_stat_statements
.
Ces deux parties ont été acceptées et intégrées (commit du patch v3-0001, et commit du patch v3-0002). Ce que je retire de la discussion sur ce patch, c’est qu’il faut proposer un nombre très limité de changements à la fois pour qu’il y ait une chance que ce soit accepté. Et de faire ça plusieurs fois si nécessaire, en avançant petit à petit, par itération.
Voici le résultat lorsqu’on interroge ces deux nouvelles colonnes :
SELECT query, parallel_workers_to_launch, parallel_workers_launched
FROM pg_stat_statements
WHERE query LIKE 'SELECT%t1%';
query | parallel_workers_to_launch | parallel_workers_launched
-------------------------------------+----------------------------+---------------------------
SELECT count(*) FROM t1 | 2 | 2
SELECT count(*) FROM t1 WHERE id>$1 | 4 | 4
SELECT * FROM t1 | 0 | 0
(3 rows)
Patch #4 : pg_stat_all_tables et pg_stat_all_indexes
Je ne vais pas m’éterniser sur ce patch. Il m’avait semblé intéressant de connaître les tables qui étaient parcourues en parallélisé, pour améliorer la configuration spécifique des tables en question avec un :
ALTER TABLE ... WITH (parallel_workers=X);
Le retour a été unanime. L’intérêt est très limité, voire nul. Je reconnais qu’il est limité, mais je réfute qu’il est nul. Ceci étant dit, je n’ai pas d’arguments supplémentaires pour défendre cette position, et j’ai donc préféré consacrer mon énergie à l’argumentation pour les autres patchs, notamment celui sur les traces.
Ce patch n’est officiellement pas rejeté, il serait certainement mieux que je le déclare abandonné.
Pour finir
Deux patchs acceptés sur quatre, et partiellement en plus. C’est une demi-victoire. Il n’empêche que nous aurons ainsi plus de métriques sur la parallélisation et que cela pourrait nous aider à améliorer sa configuration. Et rien n’empêche de revenir plus tard avec les bouts non acceptés et quelques arguments supplémentaires, venant de l’expérience rencontrée chez nos clients.
Tout le travail réalisé pour écrire un patch et réussir à le faire intégrer peut sembler lourd mais la qualité du code et sa stabilité sont à ce prix.
Cet article sera mis à jour quand les vidéos de la pgsession 17 seront disponibles pour y mettre l lien vers ma conférence.