Réglage des paramètres de `postgresql.conf` pour des performances optimales en lecture et écriture
Débloquez des performances PostgreSQL optimales en maîtrisant les paramètres clés de `postgresql.conf`. Ce guide complet détaille `shared_buffers`, `work_mem` et `checkpoint_timeout`, en expliquant leur impact sur la vitesse des requêtes, le débit des transactions et l'efficacité globale de la base de données. Apprenez des stratégies pratiques de réglage, comprenez leur interaction avec le matériel et la charge de travail, et découvrez comment surveiller leur efficacité. Améliorez votre instance PostgreSQL avec des exemples de configuration concrets et des bonnes pratiques pour les opérations de lecture et d'écriture.
Réglage des paramètres de postgresql.conf pour des performances optimales en lecture et écriture
PostgreSQL fonctionne généralement de manière acceptable avec les valeurs par défaut fournies, mais « acceptable » peut se transformer en lectures lentes, écritures irrégulières ou latence aléatoire une fois que le trafic réel arrive. Le fichier postgresql.conf est l'endroit où vous définissez le budget de ressources de base : la quantité de mémoire que PostgreSQL peut utiliser pour le cache partagé, la quantité que chaque opération de requête peut utiliser avant de déborder sur le disque, l'agressivité avec laquelle les points de contrôle écrivent les pages modifiées, et les indices que le planificateur reçoit sur la machine sous-jacente.
L'erreur que je vois le plus souvent est de traiter le réglage de PostgreSQL comme une liste de nombres magiques. Quelqu'un copie shared_buffers = 25% de la RAM, pousse work_mem à une valeur élevée, double max_connections, et espère que la base de données deviendra plus rapide. Parfois ça marche. Parfois, elle commence à swaper pendant un travail de rapport ou atteint un mur pendant les points de contrôle.
La façon la plus sûre est de régler à partir des symptômes. Les lectures sont-elles lentes parce que le jeu de travail n'est pas en cache ? Les rapports débordent-ils les tris sur le disque ? Les écritures s'accumulent-elles pendant les points de contrôle ? Trop de connexions d'application se disputent-elles la mémoire ? Ce guide parcourt les paramètres qui comptent généralement en premier, avec des exemples que vous pouvez adapter plutôt que copier aveuglément.
Comprendre les paramètres mémoire essentiels
Une gestion efficace de la mémoire est primordiale pour les systèmes de bases de données hautes performances. PostgreSQL utilise diverses zones mémoire, dont deux des plus critiques sont shared_buffers pour la mise en cache des données fréquemment consultées et work_mem pour les opérations internes des requêtes.
shared_buffers
shared_buffers est sans doute l'un des paramètres mémoire les plus importants à régler. Il définit la quantité de mémoire dédiée que PostgreSQL utilise pour mettre en cache les blocs de données. Ces blocs incluent les données des tables, les données des index et les catalogues système. Lorsqu'une requête demande des données, PostgreSQL vérifie d'abord shared_buffers. Si les données s'y trouvent (un hit de cache), elles sont récupérées beaucoup plus rapidement que si elles devaient être lues depuis le disque.
Impact sur les performances
- Performances en lecture : Une valeur plus élevée de
shared_buffersaugmente la probabilité de hits de cache, réduisant considérablement les E/S disque pour les charges de travail à forte lecture. Cela se traduit par des réponses aux requêtes plus rapides. - Performances en écriture :
shared_bufferscontient également des pages « modifiées » (blocs de données qui ont été modifiés mais pas encore écrits sur le disque). Un tampon plus grand peut absorber plus d'écritures, permettant au système de les regrouper en moins d'écritures, mais plus volumineuses, sur le disque, améliorant ainsi le débit d'écriture. Cependant, s'il est trop grand, il peut entraîner des temps de point de contrôle plus longs et des pics d'E/S accrus pendant les points de contrôle.
Directives de réglage
- Point de départ : Une recommandation courante est de définir
shared_buffersà 25% de votre RAM physique totale. Par exemple, sur un serveur avec 16 Go de RAM,shared_buffersserait de 4 Go. - Systèmes avec grande RAM : Sur les serveurs avec 64 Go+ de RAM, allouer 25% peut être excessif. PostgreSQL s'appuie également sur le cache du système de fichiers du système d'exploitation. Au-delà d'un certain point, augmenter
shared_bufferspeut offrir des rendements décroissants car le cache du système d'exploitation peut gérer efficacement une grande partie du cache restant. Dans de tels cas, 15-20% peuvent être suffisants, laissant plus de RAM pour le cache du système d'exploitation ouwork_mem. - Surveillance : Gardez un œil sur le taux de hits de cache dans
pg_stat_database, mais ne considérez pas un pourcentage comme une preuve que tout va bien. Un taux de hits élevé peut cacher quelques requêtes très coûteuses, et un taux plus faible peut être normal pour des travaux par lots qui analysent de grandes tables une seule fois. Surveillez également le comportement des points de contrôle et la latence du disque.
Exemple de configuration
Pour définir shared_buffers à 4 Go dans postgresql.conf :
shared_buffers = 4GB
Astuce : Après avoir modifié
shared_buffers, vous devez redémarrer le service PostgreSQL pour que les modifications prennent effet.
Une vérification pratique après l'avoir modifié :
SELECT
datname,
blks_hit,
blks_read,
round(100.0 * blks_hit / nullif(blks_hit + blks_read, 0), 2) AS hit_pct
FROM pg_stat_database
WHERE datname NOT IN ('template0', 'template1');
Si vous avez augmenté shared_buffers et que l'application attend toujours les lectures disque, le problème peut être la forme de la requête, les index manquants, le gonflement des tables, ou un jeu de travail plus grand que la mémoire. Plus de cache ne remplace pas un meilleur plan d'exécution.
work_mem
work_mem spécifie la quantité maximale de mémoire à utiliser par une opération de requête (comme un tri ou une table de hachage) avant d'écrire des données temporaires sur le disque. Cette mémoire est allouée par session, par opération. Si une requête complexe implique plusieurs opérations de tri ou de hachage, elle pourrait potentiellement consommer work_mem plusieurs fois au sein d'une même session.
Impact sur les performances
- Requêtes complexes :
work_memimpacte significativement les requêtes impliquantORDER BY,GROUP BY,DISTINCT, les jointures de hachage et la matérialisation. Lorsqu'une opération de tri ou de hachage dépasse la limitework_mem, PostgreSQL déborde les données excédentaires vers des fichiers disque temporaires, entraînant une exécution beaucoup plus lente. - Concurrence : Étant donné que
work_memest alloué par opération et par session, une valeur globale élevée dework_memcombinée à de nombreuses requêtes complexes concurrentes peut rapidement épuiser la RAM disponible, entraînant du swapping et une dégradation sévère des performances.
Directives de réglage
- Évitez les valeurs globales excessives : Ne définissez pas aveuglément
work_memà une valeur très élevée globalement. Considérez plutôt la concurrence typique de votre application et l'empreinte mémoire de vos requêtes les plus gourmandes en ressources. - Surveillance des débordements disque : Utilisez
EXPLAIN ANALYZEsur les requêtes problématiques. Recherchez des lignes commeSort Method: external merge Disk: NkBouHashAggregate batches: N (disk)qui indiquent quework_memétait insuffisant et que les données ont été débordées sur le disque. - Réglage ciblé : Pour des rapports spécifiques de longue durée ou des travaux par lots, envisagez de définir
work_memau niveau de la session avant d'exécuter la requête, plutôt que globalement. Cela permet une utilisation mémoire plus élevée pour cette requête spécifique sans impacter les autres sessions concurrentes.
Exemple de configuration
Pour définir work_mem à 16 Mo globalement dans postgresql.conf :
work_mem = 16MB
Pour définir work_mem pour une session spécifique (par exemple, dans psql ou une connexion d'application) :
SET work_mem = '256MB';
SELECT * FROM large_table ORDER BY some_column;
Attention : Soyez prudent lorsque vous augmentez
work_mem. Si 100 requêtes concurrentes ont chacune besoin de 1 Go dework_mem, cela représente 100 Go de RAM ! Testez toujours les modifications dans un environnement de staging et surveillez l'utilisation mémoire de votre système.
Une façon plus réaliste d'utiliser work_mem est de garder la valeur globale modeste, puis de l'augmenter uniquement pour les sessions de reporting connues :
BEGIN;
SET LOCAL work_mem = '256MB';
SELECT customer_id, sum(total_amount)
FROM orders
WHERE created_at >= current_date - interval '90 days'
GROUP BY customer_id
ORDER BY sum(total_amount) DESC;
COMMIT;
Ce modèle est plus sûr que d'augmenter la valeur globale pour chaque requête web. Une application web avec de nombreuses requêtes courtes a besoin d'une utilisation mémoire prévisible. Un rapport nocturne peut se permettre un budget par requête plus important.
Gestion des performances d'écriture et de la durabilité avec les points de contrôle
Les points de contrôle sont un mécanisme essentiel dans PostgreSQL pour garantir la durabilité des données et gérer le journal des transactions (WAL - Write-Ahead Log). Ils synchronisent périodiquement les blocs de données modifiés de shared_buffers vers le disque, marquant le point jusqu'auquel toutes les modifications précédentes ont été écrites sur le stockage permanent.
checkpoint_timeout
checkpoint_timeout définit le temps maximum entre les points de contrôle WAL automatiques. Les points de contrôle se produisent également si la quantité de segments WAL générés depuis le dernier point de contrôle dépasse max_wal_size.
Impact sur les performances
- Points de contrôle fréquents (
checkpoint_timeoutcourt) : Conduit à des pics d'E/S plus fréquents lorsque les pages modifiées sont vidées sur le disque. Bien que cela réduise le temps de récupération après un crash (moins de WAL à rejouer), cela peut impacter négativement les performances de la charge de travail active en raison d'une activité d'écriture concentrée. - Points de contrôle peu fréquents (
checkpoint_timeoutlong) : Réduit la fréquence des pics d'E/S, conduisant à des performances plus fluides pendant le fonctionnement normal. Cependant, cela signifie que plus de données pourraient devoir être rejouées à partir du WAL en cas de crash, entraînant des temps de récupération de base de données plus longs. Cela nécessite également une valeurmax_wal_sizeplus grande pour stocker les segments WAL accumulés.
Directives de réglage
- Équilibre : L'objectif est de trouver un équilibre entre des performances continues fluides et un temps de récupération acceptable. De nombreux systèmes de production commencent autour de 5 à 15 minutes, puis s'ajustent en fonction du volume WAL et des objectifs de récupération.
- Interaction avec
max_wal_size: Ces deux paramètres fonctionnent ensemble. Sicheckpoint_timeoutest long mais quemax_wal_sizeest trop petit, les points de contrôle seront déclenchés parmax_wal_sizeplus fréquemment que parcheckpoint_timeout. Ajustezmax_wal_sizepour qu'il soit suffisamment grand pour permettre àcheckpoint_timeoutd'être le déclencheur principal. - Surveillance : Utilisez
pg_stat_bgwriterpour observer les compteurscheckpoints_timedetcheckpoints_req.checkpoints_timeddevrait être significativement plus élevé quecheckpoints_req(points de contrôle demandés en raison des limites de taille WAL) si votrecheckpoint_timeoutest le déclencheur principal.
Exemple de configuration
Pour définir checkpoint_timeout à 10 minutes dans postgresql.conf :
checkpoint_timeout = 10min
# Pensez également à ajuster max_wal_size en conséquence
max_wal_size = 4GB # Exemple, ajustez en fonction de la charge de travail
Bonne pratique : Visez à ce que les points de contrôle soient principalement déclenchés par
checkpoint_timeoutplutôt que parmax_wal_size. Cela fournit des modèles d'E/S plus prévisibles. Simax_wal_sizedéclenche fréquemment des points de contrôle, augmentez sa valeur.
Vérifiez le modèle avec :
SELECT
checkpoints_timed,
checkpoints_req,
checkpoint_write_time,
checkpoint_sync_time,
buffers_checkpoint
FROM pg_stat_bgwriter;
Si checkpoints_req augmente rapidement, PostgreSQL effectue des points de contrôle parce que le WAL a dépassé max_wal_size, pas parce que le minuteur a expiré. Cela se manifeste souvent par des rafales d'E/S en écriture. Augmenter max_wal_size peut lisser la charge de travail, mais peut également augmenter le temps de récupération après un crash car plus de WAL peut devoir être rejoué.
Paramètres du planificateur et du WAL qui méritent d'être vérifiés
Trois paramètres se situent souvent à côté des gros paramètres mémoire et de point de contrôle.
effective_cache_size n'est pas de la mémoire allouée par PostgreSQL. C'est une estimation du planificateur de la quantité de cache probablement disponible à travers les tampons partagés de PostgreSQL et le cache du système de fichiers du système d'exploitation. S'il est défini trop bas, le planificateur peut éviter les analyses d'index car il suppose que les lectures seront coûteuses. Sur un serveur de base de données dédié, un point de départ courant est une grande fraction de la RAM, mais la bonne valeur dépend de ce qui s'exécute d'autre sur l'hôte.
effective_cache_size = 12GB
maintenance_work_mem affecte les opérations de maintenance telles que CREATE INDEX, ALTER TABLE ADD FOREIGN KEY et VACUUM. Il n'est pas utilisé par les tris de requêtes normaux de la même manière que work_mem. Si les constructions d'index sont péniblement lentes pendant les fenêtres de maintenance, augmenter cette valeur pour la session peut aider :
SET maintenance_work_mem = '1GB';
CREATE INDEX CONCURRENTLY idx_orders_created_at ON orders (created_at);
wal_buffers contrôle la mémoire utilisée pour les enregistrements WAL avant qu'ils ne soient écrits. La valeur par défaut est généralement correcte car PostgreSQL peut la dimensionner automatiquement, mais les charges de travail à forte écriture avec de grandes transactions peuvent bénéficier de la vérification si les écritures WAL sont un goulot d'étranglement avant de le modifier. Ne le réglez pas simplement parce qu'il apparaît dans une liste de contrôle.
Points de départ différents pour différentes charges de travail
Pour une application web OLTP, la priorité est une latence stable sous concurrence. Gardez work_mem conservateur, utilisez un pooler de connexions au lieu d'autoriser des milliers de connexions directes, et surveillez les attentes de verrouillage et les mauvais plans avant de blâmer shared_buffers. Un problème typique ressemble à ceci : une version ajoute une requête de tableau de bord avec ORDER BY created_at DESC sur des millions de lignes, la requête déborde sur le disque, et soudainement chaque requête est plus lente parce que la base de données fait des E/S de fichiers temporaires. La solution peut être un index ou une requête plus étroite, pas un work_mem global plus grand.
Pour une base de données d'analyse ou de reporting, les grands tris et les agrégats de hachage sont normaux. Vous pouvez augmenter work_mem pour les rôles de reporting, augmenter maintenance_work_mem pour le travail d'index en masse, et accepter des requêtes plus longues. Le risque est la concurrence. Dix analystes exécutant des rapports gourmands en mémoire en même temps peuvent consommer bien plus de mémoire qu'un seul test de requête réussi ne le suggérait.
Pour un système à forte écriture, les points de contrôle et le WAL comptent davantage. Si l'application a des blocages d'écriture périodiques, vérifiez s'ils coïncident avec les points de contrôle. Regardez également la latence du stockage, la saturation du disque WAL, l'activité d'autovacuum, et si les transactions longues empêchent le nettoyage. Augmenter checkpoint_timeout seul ne résoudra pas un disque qui ne peut pas suivre le volume d'écriture moyen.
Un flux de travail de réglage simple
Commencez par enregistrer la configuration actuelle :
SELECT name, setting, unit, source
FROM pg_settings
WHERE name IN (
'shared_buffers',
'work_mem',
'maintenance_work_mem',
'effective_cache_size',
'checkpoint_timeout',
'max_wal_size',
'wal_buffers',
'max_connections'
)
ORDER BY name;
Ensuite, capturez les symptômes avant de changer quoi que ce soit. Sauvegardez un ou deux plans de requêtes lents avec EXPLAIN (ANALYZE, BUFFERS). Vérifiez la journalisation des fichiers temporaires si vous soupçonnez des débordements :
log_temp_files = 0
Ce paramètre journalise chaque fichier temporaire, alors utilisez-le avec précaution sur un système occupé ou définissez-le sur un seuil comme 64MB. Si vous voyez beaucoup de gros fichiers temporaires provenant de la même forme de requête, réglez la requête, ajoutez un index, ou augmentez work_mem pour cette charge de travail.
Changez une chose à la fois. Certains paramètres nécessitent un redémarrage, d'autres seulement un rechargement, et certains peuvent être définis par session. PostgreSQL vous indique lequel est lequel :
SELECT name, context
FROM pg_settings
WHERE name IN ('shared_buffers', 'work_mem', 'checkpoint_timeout', 'max_wal_size');
Le contexte postmaster signifie redémarrage. sighup signifie rechargement. user signifie que les modifications au niveau de la session sont possibles.
Conseils de réglage généraux et bonnes pratiques
- Réglage itératif : Commencez par de petites modifications incrémentales. Changez un paramètre à la fois, observez l'impact, puis ajustez davantage si nécessaire. Le réglage n'est pas une tâche ponctuelle mais un processus continu.
- Surveillez tout : Utilisez les vues de statistiques intégrées de PostgreSQL (
pg_stat_database,pg_stat_bgwriter,pg_stat_activity), les outils de surveillance au niveau du système d'exploitation (par exemple,iostat,vmstat,top), et des solutions de surveillance externes pour collecter des données sur le CPU, la mémoire, les E/S disque et les performances des requêtes. - Comprenez votre charge de travail : Votre application est-elle à forte lecture ou à forte écriture ? Effectue-t-elle des requêtes analytiques complexes ou des opérations transactionnelles simples ? Adaptez votre configuration aux caractéristiques spécifiques de votre charge de travail.
- Considérez d'autres paramètres : Bien que
shared_buffers,work_memetcheckpoint_timeoutsoient cruciaux, de nombreux autres paramètres peuvent impacter les performances. Par exemple,effective_cache_size(indices pour le planificateur de requêtes sur le cache OS disponible) etwal_buffers(mémoire pour les enregistrements WAL avant vidage) sont souvent réglés en parallèle de ceux-ci. - Utilisez
EXPLAIN ANALYZE: Cet outil inestimable vous aide à comprendre comment PostgreSQL exécute une requête, identifie les goulots d'étranglement, et peut révéler siwork_memest insuffisant.
Le meilleur travail de réglage PostgreSQL est ennuyeux dans le bon sens : mesurer, changer un paramètre, mesurer à nouveau, et garder une voie de retour. shared_buffers, work_mem et les paramètres de point de contrôle peuvent faire une réelle différence, mais ils fonctionnent avec les plans de requêtes, les index, l'autovacuum, les nombres de connexions et le stockage. Si ces éléments sont malsains, la configuration seule ne sauvera pas la base de données.