PostgreSQL Avancé

Formation DBA2

Dalibo SCOP

24.09

29 août 2024

Sur ce document

Formation Formation DBA2
Titre PostgreSQL Avancé
Révision 24.09
ISBN N/A
PDF https://dali.bo/dba2_pdf
EPUB https://dali.bo/dba2_epub
HTML https://dali.bo/dba2_html
Slides https://dali.bo/dba2_slides

Licence Creative Commons CC-BY-NC-SA

Cette formation est sous licence CC-BY-NC-SA. Vous êtes libre de la redistribuer et/ou modifier aux conditions suivantes :

  • Paternité
  • Pas d’utilisation commerciale
  • Partage des conditions initiales à l’identique

Marques déposées

PostgreSQL® Postgres® et le logo Slonik sont des marques déposées par PostgreSQL Community Association of Canada.

Versions de PostgreSQL couvertes

Ce document ne couvre que les versions supportées de PostgreSQL au moment de sa rédaction, soit les versions 12 à 16.

Architecture & fichiers de PostgreSQL

PostgreSQL

Au menu

  • Rappels sur l’installation
  • Les processus
  • Les fichiers

Rappels sur l’installation

  • Plusieurs possibilités
    • paquets Linux précompilés
    • outils externes d’installation
    • code source
  • Chacun ses avantages et inconvénients
    • Dalibo recommande fortement les paquets précompilés

Paquets précompilés

  • Paquets Debian ou Red Hat suivant la distribution utilisée
  • Préférence forte pour ceux de la communauté
  • Installation du paquet
    • installation des binaires
    • création de l’utilisateur postgres
    • initialisation d’une instance (Debian seulement)
    • lancement du serveur (Debian seulement)
  • (Red Hat) Script de création de l’instance

Installons PostgreSQL

  • Prenons un moment pour
    • installer PostgreSQL
    • créer une instance
    • démarrer l’instance
  • Pas de configuration spécifique pour l’instant

Processus de PostgreSQL

Architecture de PostgreSQL

Introduction

  • PostgreSQL est :

    • multiprocessus (et non multithread)
    • à mémoire partagée
    • client-serveur

Processus d’arrière-plan

# ps f -e --format=pid,command | grep -E "postgres|postmaster"
  96122 /usr/pgsql-15/bin/postmaster -D /var/lib/pgsql/15/data/
  96123  \_ postgres: logger
  96125  \_ postgres: checkpointer
  96126  \_ postgres: background writer
  96127  \_ postgres: walwriter
  96128  \_ postgres: autovacuum launcher
  96131  \_ postgres: logical replication launcher

(sous Rocky Linux 8)

Processus d’arrière-plan (suite)

  • Les processus présents au démarrage :
    • Un processus père : postmaster
    • background writer
    • checkpointer
    • walwriter
    • autovacuum launcher
    • stats collector (avant v15)
    • logical replication launcher
  • et d’autres selon la configuration et le moment :
    • dont les background workers : parallélisation, extensions…

Processus par client (client backend)

  • Pour chaque client, nous avons un processus :
    • créé à la connexion
    • dédié au client…
    • …et qui dialogue avec lui
    • détruit à la déconnexion
  • Un processus gère une requête
    • peut être aidé par d’autres processus
  • Le nombre de processus est régi par les paramètres :
    • max_connections (défaut : 100) - connexions réservées
    • compromis nombre requêtes actives/nombre cœurs/complexité/mémoire

Gestion de la mémoire

Structure de la mémoire sous PostgreSQL

  • Zone de mémoire partagée :
    • shared buffers surtout
  • Zone de chaque processus
    • tris en mémoire (work_mem)

Fichiers

  • Une instance est composée de fichiers :
    • Répertoire de données
    • Fichiers de configuration
    • Fichier PID
    • Tablespaces
    • Statistiques
    • Fichiers de trace

Répertoire de données

postgres$ ls $PGDATA
base              pg_ident.conf  pg_stat      pg_xact
current_logfiles  pg_logical     pg_stat_tmp  postgresql.auto.conf
global            pg_multixact   pg_subtrans  postgresql.conf
log               pg_notify      pg_tblspc    postmaster.opts
pg_commit_ts      pg_replslot    pg_twophase  postmaster.pid
pg_dynshmem       pg_serial      PG_VERSION
pg_hba.conf       pg_snapshots   pg_wal
  • Une seule instance PostgreSQL doit y accéder !

Fichiers de configuration

  • postgresql.conf ( + fichiers inclus)
  • postgresql.auto.conf
  • pg_hba.conf ( + fichiers inclus (v16))
  • pg_ident.conf (idem)

Autres fichiers dans PGDATA

  • PG_VERSION : fichier contenant la version majeure de l’instance
  • postmaster.pid
    • nombreuses informations sur le processus père
    • fichier externe possible, paramètre external_pid_file
  • postmaster.opts

Fichiers de données

  • base/ : contient les fichiers de données
    • un sous-répertoire par base de données
    • pgsql_tmp : fichiers temporaires
  • global/ : contient les objets globaux à toute l’instance

Fichiers liés aux transactions

  • pg_wal/ : journaux de transactions
    • pg_xlog/ avant la v10
    • sous-répertoire archive_status
    • nom : timeline, journal, segment
    • ex : 00000002 00000142 000000FF
  • pg_xact/ : état des transactions
    • pg_clog/ avant la v10
  • mais aussi : pg_commit_ts/, pg_multixact/, pg_serial/ pg_snapshots/, pg_subtrans/, pg_twophase/
  • Ces fichiers sont vitaux !

Fichiers liés à la réplication

  • pg_logical/
  • pg_repslot/

Répertoire des tablespaces

  • pg_tblspc/ : tablespaces
    • si vraiment nécessaires
    • liens symboliques ou points de jonction
    • totalement optionnels

Fichiers des statistiques d’activité

Statistiques d’activité :

  • stats collector (≤v14) & extensions
  • pg_stat_tmp/ : temporaires
  • pg_stat/ : définitif

Autres répertoires

  • pg_dynshmem/
  • pg_notify/

Les fichiers de traces (journaux)

  • Fichiers texte traçant l’activité
  • Très paramétrables
  • Gestion des fichiers soit :
    • par PostgreSQL
    • délégués au système d’exploitation (syslog, eventlog)

Résumé

Architecture de PostgreSQL

Conclusion

  • PostgreSQL est complexe, avec de nombreux composants

  • Une bonne compréhension de cette architecture est la clé d’une bonne administration.

  • Pour aller (beaucoup) plus loin :

Questions

N’hésitez pas, c’est le moment !

Quiz

Installation de PostgreSQL depuis les paquets communautaires

Travaux pratiques

Processus

Fichiers

Travaux pratiques (solutions)

Configuration de PostgreSQL

PostgreSQL

Au menu

  • Les paramètres en lecture seule
  • Les différents fichiers de configuration
    • survol du contenu
  • Quelques paramétrages importants :
    • tablespaces
    • connexions
    • statistiques
    • optimiseur

Paramètres en lecture seule

  • Options de compilation ou lors d’initdb
  • Quasiment jamais modifiés
    • risque d’incompatabilité des fichiers, avec les outils
  • Tailles de bloc ou de fichier
    • block_size : 8 ko
    • wal_block_size : 8 ko
    • segment_size : 1 Go
    • wal_segment_size : 16 Mo (option --wal-segsize d’initdb en v11)

Fichiers de configuration

  • postgresql.conf
  • postgresql.auto.conf
  • pg_hba.conf
  • pg_ident.conf

postgresql.conf

Fichier principal de configuration :

  • Emplacement :
    • défaut/Red Hat & dérivés : répertoires des données (/var/lib/…)
    • Debian : /etc/postgresql/<version>/<nom>/postgresql.conf
  • Format clé = valeur
  • Sections, commentaires (redémarrage !)

Surcharge des paramètres de postgresql.conf

  • Inclusion externe : include, include_if_exists
  • Surcharge dans cet ordre :
    • ALTER SYSTEM SET … ( renseigne postgresql.auto.conf )
    • paramètres de pg_ctl
    • ALTER DATABASE | ROLE … SET paramètre = …
    • SET / SET LOCAL
  • Consulter :
    • SHOW
    • pg_settings
    • pg_file_settings

Survol de postgresql.conf

  • Emplacement de fichiers
  • Connections & authentification
  • Ressources (hors journaux de transactions)
  • Journaux de transactions
  • Réplication
  • Optimisation de requête
  • Traces
  • Statistiques d’activité
  • Autovacuum
  • Paramétrage client par défaut
  • Verrous
  • Compatibilité

pg_hba.conf et pg_ident.conf

  • Authentification multiple :
    • utilisateur / base / source de connexion
  • Fichiers :
    • pg_hba.conf (Host Based Authentication)
    • pg_ident.conf : si mécanisme externe d’authentification
    • paramètres : hba_file et ident_file

Tablespaces

  • Espace de stockage physique d’objets
    • et non logique !
  • Simple répertoire (hors de PGDATA) + lien symbolique
  • Pour :
    • répartir I/O et volumétrie
    • quotas (par le FS, mais pas en natif)
    • tri sur disque séparé
  • Utilisation selon des droits

Tablespaces : mise en place

CREATE TABLESPACE chaud LOCATION '/SSD/tbl/chaud';

CREATE DATABASE nom TABLESPACE 'chaud';

ALTER DATABASE nom SET default_tablespace TO 'chaud';

GRANT CREATE ON TABLESPACE chaud TO un_utilisateur ;

CREATE TABLE une_table (…) TABLESPACE chaud ;

ALTER TABLE une_table SET TABLESPACE chaud ;  -- verrou !

ALTER INDEX une_table_i_idx SET TABLESPACE chaud ; -- pas automatique

Tablespaces : configuration

  • default_tablespace
  • temp_tablespaces
  • Droits à ouvrir :
GRANT CREATE ON TABLESPACE  ssd_tri  TO  dupont ;
  • Performances :
    • seq_page_cost, random_page_cost
    • effective_io_concurrency, maintenance_io_concurrency
ALTER TABLESPACE chaud SET ( random_page_cost = 1 );
ALTER TABLESPACE chaud SET ( effective_io_concurrency   = 500,
                             maintenance_io_concurrency = 500 ) ;

Gestion des connexions

  • L’accès à la base se fait par un protocole réseau clairement défini :

    • sockets TCP (IPV4 ou IPV6)
    • sockets Unix (Unix uniquement)
  • Les demandes de connexion sont gérées par le postmaster.

  • Paramètres : port, listen_adresses, unix_socket_directories, unix_socket_group et unix_socket_permissions

TCP

  • Paramètres de keepalive TCP
    • tcp_keepalives_idle
    • tcp_keepalives_interval
    • tcp_keepalives_count
  • Paramètre de vérification de connexion
    • client_connection_check_interval (v14)

SSL

  • Paramètres SSL
    • ssl, ssl_ciphers, ssl_renegotiation_limit

Statistiques sur l’activité

  • (Ne pas confondre avec statistiques sur les données !)
  • Statistiques consultable par des vues systèmes
  • Paramètres :
    • track_activities, track_activity_query_size
    • track_counts, track_io_timing et track_functions
    • update_process_title
    • stats_temp_directory (< v15)

Statistiques d’activité collectées

  • Accès logiques (INSERT, SELECT…) par table et index
  • Accès physiques (blocs) par table, index et séquence
  • Activité du Background Writer
  • Activité par base
  • Liste des sessions et informations sur leur activité

Vues système

  • Supervision / métrologie

  • Diagnostiquer

  • Vues système :

    • pg_stat_user_*
    • pg_statio_user_*
    • pg_stat_activity : requêtes
    • pg_stat_bgwriter
    • pg_locks

Statistiques sur les données

  • Statistiques sur les données : pg_stats
    • collectées par échantillonnage (default_statistics_target)
    • ANALYZE table
    • table par table (et pour certains index)
    • colonne par colonne
    • pour de meilleurs plans d’exécution
  • Affiner :
    • Échantillonnage
    ALTER TABLE matable ALTER COLUMN macolonne SET statistics 300 ;
    • Statistiques multicolonnes sur demande
    CREATE STATISTICS nom ON champ1, champ2… FROM nom_table ;

Optimiseur

  • SQL est un langage déclaratif :

    • décrit le résultat attendu (projection, sélection, jointure, etc.)…
    • …mais pas comment l’obtenir
    • c’est le rôle de l’optimiseur

Optimisation par les coûts

  • L’optimiseur évalue les coûts respectifs des différents plans
  • Il calcule tous les plans possibles tant que c’est possible
  • Le coût de planification exhaustif est exponentiel par rapport au nombre de jointures de la requête
  • Il peut falloir d’autres stratégies
  • Paramètres principaux :
    • seq_page_cost, random_page_cost, cpu_tuple_cost, cpu_index_tuple_cost, cpu_operator_cost
    • parallel_setup_cost, parallel_tuple_cost
    • effective_cache_size

Paramètres supplémentaires de l’optimiseur (1)

  • Partitionnement
    • constraint_exclusion
    • enable_partition_pruning
  • Réordonne les tables
    • from_collapse_limit & join_collapse_limit (défaut : 8)
  • Requêtes préparées
    • plan_cache_mode
  • Curseurs
    • cursor_tuple_fraction
  • Mutualiser les entrées-sorties
    • synchronize_seqscans

Paramètres supplémentaires de l’optimiseur (2)

  • GEQO :
    • un optimiseur génétique
    • état initial, puis mutations aléatoires
    • rapide, mais non optimal
    • paramètres : geqo & geqo_threshold (12 tables)

Débogage de l’optimiseur

  • Permet de valider qu’on est en face d’un problème d’optimiseur.
  • Les paramètres sont assez grossiers :
    • défavoriser très fortement un type d’opération
    • pour du diagnostic, pas pour de la production

Conclusion

  • Nombreuses fonctionnalités
    • donc nombreux paramètres

Questions

N’hésitez pas, c’est le moment !

Quiz

Travaux pratiques

Tablespace

Statistiques d’activités, tables et vues système

Statistiques sur les données

Travaux pratiques (solutions)

Mémoire et journalisation dans PostgreSQL

PostgreSQL

Au menu

La mémoire & PostgreSQL :

  • Mémoire partagée
  • Mémoire des processus
  • Les shared buffers & la gestion du cache
  • La journalisation

Rappel de l’architecture de PostgreSQL

Architecture de PostgreSQL

Mémoire partagée

  • L’implémentation dépend de l’OS
  • Quelles zones ?
  • Quelle taille ?

Zones de la mémoire partagée

  • shared_buffers
    • cache disque des fichiers de données
  • wal_buffers
    • cache disque des journaux de transactions
  • max_connections
    • 100… ou plus ?
  • track_activity_query_size
    • à monter
  • verrous
    • max_connections, max_locks_per_transaction
  • etc
  • Modification → redémarrage

Taille de la mémoire partagée

-- v15+
SHOW shared_memory_size ;
SHOW shared_memory_size_in_huge_pages ;

Mémoire par processus

  • work_mem
    • × hash_mem_multiplier (v 13)
  • maintenance_work_mem
    • autovacuum_work_mem
  • temp_buffers
  • Pas de limite stricte à la consommation mémoire d’une session !
    • ni à la consommation totale
  • Augmenter prudemment & superviser

Shared buffers

  • Shared buffers ou blocs de mémoire partagée
    • partage les blocs entre les processus
    • cache en lecture ET écriture
    • double emploi partiel avec le cache du système (voir effective_cache_size)
    • importants pour les performances !
  • Dimensionnement en première intention & avant tests :
    • shared_buffers = 25 % RAM généralement
    • si > 8 Go : Huge Pages, max_wal_size

Notions essentielles de gestion du cache

  • Buffer pin
  • Buffer dirty/clean
  • Compteur d’utilisation
  • Clocksweep

Ring buffer

But : ne pas purger le cache à cause :

  • des grandes tables
  • de certaines opérations
    • Seq Scan (lecture)
    • VACUUM (écritures)
    • COPY, CREATE TABLE AS SELECT…

Contenu du cache

2 extensions en « contrib » :

  • pg_buffercache
  • pg_prewarm

Synchronisation en arrière-plan

Pour synchroniser les blocs « dirty » :

  • Checkpointer essentiellement :
    • lors des checkpoints (surtout périodiques)
    • synchronise toutes les pages dirty
  • Background writer :
    • de façon anticipée, selon l’activité
    • une portion des pages
  • Backends
    • en dernière extrémité

Journalisation

  • Garantir la durabilité des données
  • Base encore cohérente après :
    • arrêt brutal des processus
    • crash machine
  • Écriture des modifications dans un journal avant les fichiers de données
  • WAL : Write Ahead Logging

Journaux de transaction (rappels)

Essentiellement :

  • pg_wal/ : journaux de transactions
    • sous-répertoire archive_status
    • nom : timeline, journal, segment
    • ex : 00000002 00000142 000000FF
  • pg_xact/ : état des transactions
  • Ces fichiers sont vitaux !

Checkpoint

  • « Point de reprise »
  • À partir d’où rejouer les journaux ?
  • Données écrites au moins au niveau du checkpoint
    • il peut durer
  • Processus checkpointer

Déclenchement & comportement des checkpoints - 1

  • Déclenchement périodique (idéal)
    • checkpoint_timeout
  • ou : Quantité de journaux
    • max_wal_size (pas un plafond !)
  • ou : CHECKPOINT
  • À la fin :
    • sync
    • recyclage des journaux
  • Espacer les checkpoints peut réduire leur volumétrie

Déclenchement & comportement des checkpoints - 2

  • Dilution des écritures
    • checkpoint_completion_target × durée moy. entre 2 checkpoints
  • Surveillance :
    • checkpoint_warning
    • log_checkpoints
    • Gardez de la place ! sinon crash…

Paramètres du background writer

Nettoyage selon l’activité, en plus du checkpointer :

  • bgwriter_delay
  • bgwriter_lru_maxpages
  • bgwriter_lru_multiplier
  • bgwriter_flush_after

WAL buffers : journalisation en mémoire

  • Mutualiser les écritures entre transactions
  • Un processus d’arrière plan : walwriter
  • Paramètres notables :
    • wal_buffers
    • wal_writer_flush_after
  • Fiabilité :
    • fsync = on
    • full_page_writes = on
    • sinon corruption !

Compression des journaux

  • wal_compression
    • compression des enregistrements
    • moins de journaux
    • un peu de CPU

Limiter le coût de la journalisation

  • synchronous_commit
    • perte potentielle de données validées
  • commit_delay / commit_siblings
  • Par session

Au-delà de la journalisation

  • Sauvegarde PITR
  • Réplication physique
    • par log shipping
    • par streaming

L’archivage des journaux

  • Repartir à partir :
    • d’une vieille sauvegarde
    • les journaux archivés
  • Sauvegarde à chaud
  • Sauvegarde en continu
  • Paramètres
    • wal_level, archive_mode
    • archive_command ou archive_library

Réplication

  • Log shipping : fichier par fichier
  • Streaming : entrée par entrée (en flux continu)
  • Serveurs secondaires très proches de la production, en lecture

Conclusion

Mémoire et journalisation :

  • complexe
  • critique
  • mais fiable
  • et le socle de nombreuses fonctionnalités évoluées

Questions

N’hésitez pas, c’est le moment !

Quiz

Introduction à pgbench

Travaux pratiques

Mémoire partagée

Mémoire de tri

Cache disque de PostgreSQL

Journaux

Travaux pratiques (solutions)

Mécanique du moteur transactionnel & MVCC

PostgreSQL

Introduction

PostgreSQL utilise un modèle appelé MVCC (Multi-Version Concurrency Control).

  • Gestion concurrente des transactions
  • Excellente concurrence
  • Impacts sur l’architecture

Au menu

  • Présentation de MVCC
  • Niveaux d’isolation
  • Implémentation de MVCC de PostgreSQL
  • Les verrous
  • Le mécanisme TOAST

Présentation de MVCC

  • MultiVersion Concurrency Control
  • Contrôle de Concurrence Multi-Version
  • Plusieurs versions du même enregistrement
  • Granularité : l’enregistrement (pas le champ !)

Alternative à MVCC : un seul enregistrement en base

  • Verrouillage en lecture et exclusif en écriture
  • Nombre de verrous ?
  • Contention ?
  • Cohérence ?
  • Annulation ?

Implémentation de MVCC par undo

  • MVCC par undo :
    • une version de l’enregistrement dans la table
    • sauvegarde des anciennes versions
    • l’adresse physique d’un enregistrement ne change pas
    • la lecture cohérente est complexe
    • l’undo est complexe à dimensionner… et parfois insuffisant
    • l’annulation est lente
  • Exemple : Oracle

L’implémentation MVCC de PostgreSQL

  • Copy On Write (duplication à l’écriture)
  • Une version d’enregistrement n’est jamais modifiée
  • Toute modification entraîne une nouvelle version
  • Pas d’undo : pas de contention, ROLLBACK instantané

Niveaux d’isolation

  • Chaque transaction (et donc session) est isolée à un certain point :
    • elle ne voit pas les opérations des autres
    • elle s’exécute indépendamment des autres
  • Le niveau d’isolation au démarrage d’une transaction peut être spécifié :
    • BEGIN ISOLATION LEVEL xxx;

Niveau READ UNCOMMITTED

  • Non disponible sous PostgreSQL
    • si demandé, s’exécute en READ COMMITTED
  • Lecture de données modifiées par d’autres transactions non validées
  • Aussi appelé dirty reads
  • Dangereux
  • Pas de blocage entre les sessions

Niveau READ COMMITTED

  • Niveau d’isolation par défaut
  • La transaction ne lit que les données validées en base
  • Un ordre SQL s’exécute dans un instantané (les tables semblent figées sur la durée de l’ordre)
  • L’ordre suivant s’exécute dans un instantané différent

Niveau REPEATABLE READ

  • Instantané au début de la transaction
  • Ne voit donc plus les modifications des autres transactions
  • Voit toujours ses propres modifications
  • Peut entrer en conflit avec d’autres transactions si modification des mêmes enregistrements

Niveau SERIALIZABLE

  • Niveau d’isolation le plus élevé
  • Chaque transaction se croit seule sur la base
    • sinon annulation d’une transaction en cours
  • Avantages :
    • pas de « lectures fantômes »
    • évite des verrous, simplifie le développement
  • Inconvénients :
    • pouvoir rejouer les transactions annulées
    • toutes les transactions impliquées doivent être sérialisables

Structure d’un bloc

  • 1 bloc = 8 ko
  • ctid = (bloc, item dans le bloc)
Répartition des lignes au sein d’un bloc (schéma de la documentation officielle, licence PostgreSQL)

xmin & xmax

Table initiale :

xmin xmax Nom Solde
100 M. Durand 1500
100 Mme Martin 2200

xmin & xmax (suite)

BEGIN;
UPDATE soldes SET solde = solde - 200 WHERE nom = 'M. Durand';
xmin xmax Nom Solde
100 150 M. Durand 1500
100 Mme Martin 2200
150 M. Durand 1300

xmin & xmax (suite)

UPDATE soldes SET solde = solde + 200 WHERE nom = 'Mme Martin';
xmin xmax Nom Solde
100 150 M. Durand 1500
100 150 Mme Martin 2200
150 M. Durand 1300
150 Mme Martin 2400

xmin & xmax (suite)

xmin xmax Nom Solde
100 150 M. Durand 1500
100 150 Mme Martin 2200
150 M. Durand 1300
150 Mme Martin 2400
  • Comment est effectuée la suppression d’un enregistrement ?
  • Comment est effectuée l’annulation de la transaction 150 ?

CLOG

  • La CLOG (Commit Log) enregistre l’état des transactions.
  • Chaque transaction occupe 2 bits de CLOG
  • COMMIT ou ROLLBACK très rapide

Avantages du MVCC PostgreSQL

  • Avantages :
    • avantages classiques de MVCC (concurrence d’accès)
    • implémentation simple et performante
    • peu de sources de contention
    • verrouillage simple d’enregistrement
    • ROLLBACK instantané
    • données conservées aussi longtemps que nécessaire

Inconvénients du MVCC PostgreSQL

  • Nettoyage des enregistrements
    • VACUUM
    • automatisation : autovacuum
  • Tables plus volumineuses
  • Pas de visibilité dans les index
  • Colonnes supprimées impliquent reconstruction

Le wraparound (1)

  • Wraparound : bouclage du compteur de xmin/xmax
  • 32 bits ~ 4 milliards

Le wraparound (2)

Après 4 milliards de transactions :

Le wraparound (3)

Concrètement ?

  • VACUUM FREEZE
    • géré par l’autovacuum
    • au pire, d’office
    • potentiellement beaucoup d’écritures

Optimisations de MVCC

MVCC a été affiné au fil des versions :

  • Mise à jour HOT (Heap-Only Tuples)
    • si place dans le bloc
    • si aucune colonne indexée modifiée
  • Free Space Map
  • Visibility Map

Verrouillage et MVCC

La gestion des verrous est liée à l’implémentation de MVCC

  • Verrouillage d’objets en mémoire
  • Verrouillage d’objets sur disque
  • Paramètres

Le gestionnaire de verrous

PostgreSQL possède un gestionnaire de verrous

  • Verrous d’objet
  • Niveaux de verrouillage
  • Empilement des verrous
  • Deadlock
  • Vue pg_locks

Verrous sur enregistrement

  • Le gestionnaire de verrous possèdes des verrous sur enregistrements
    • transitoires
    • le temps de poser le xmax
  • Utilisation de verrous sur disque
    • pas de risque de pénurie
  • Les verrous entre transaction se font sur leurs ID

La vue pg_locks

  • pg_locks :
    • visualisation des verrous en place
    • tous types de verrous sur objets
  • Complexe à interpréter :
    • verrous sur enregistrements pas directement visibles

Verrous - Paramètres

  • Nombre :
    • max_locks_per_transaction (+ paramètres pour la sérialisation)
  • Durée :
    • lock_timeout (éviter l’empilement des verrous)
    • deadlock_timeout (défaut 1 s)
  • Trace :
    • log_lock_waits

Mécanisme TOAST

TOAST : The Oversized-Attribute Storage Technique

Que faire si une ligne dépasse d’un bloc ?

Principe du TOAST

  • Table de débordement pg_toast_XXX
    • masquée, transparente
  • Jusqu’à 1 Go par champ (déconseillé)
    • texte, JSON, binaire…
    • compression optionnelle
  • Politiques par champ
    • PLAIN/MAIN/EXTERNAL ou EXTENDED

TOAST et compression

  • pglz (zlib) : défauts
  • lz4 à préférer
    • généralement plus rapide
    • compression équivalente (à vérifier)
  • Mise en place :
default_toast_compression = lz4

ou :

ALTER TABLE t1 ALTER COLUMN c2 SET COMPRESSION lz4 ;

Conclusion

  • PostgreSQL dispose d’une implémentation MVCC complète, permettant :
    • que les lecteurs ne bloquent pas les écrivains
    • que les écrivains ne bloquent pas les lecteurs
    • que les verrous en mémoire soient d’un nombre limité
  • Cela impose par contre une mécanique un peu complexe, dont les parties visibles sont la commande VACUUM et le processus d’arrière-plan autovacuum.

Questions

N’hésitez pas, c’est le moment !

Quiz

Travaux pratiques

Niveaux d’isolation READ COMMITTED et REPEATABLE READ

Niveau d’isolation SERIALIZABLE (Optionnel)

Effets de MVCC

Verrous

Travaux pratiques (solutions)

VACUUM et autovacuum

PostgreSQL

Au menu

  • Principe & fonctionnement du VACUUM
  • Options : VACUUM seul, ANALYZE, FULL, FREEZE
    • ne pas les confondre !
  • Suivi
  • Autovacuum
  • Paramétrages

VACUUM et autovacuum

  • VACUUM : nettoie d’abord les lignes mortes
  • Mais aussi d’autres opérations de maintenance
  • Lancement
    • manuel
    • par le démon autovacuum (seuils)

Fonctionnement de VACUUM

Phase 1/3 : recherche des enregistrements morts

Fonctionnement de VACUUM (suite)

Phase 2/3 : nettoyage des index

Fonctionnement de VACUUM (suite)

Phase 3/3 : suppression des enregistrements morts

NB : L’espace est rarement rendu à l’OS !

Les options de VACUUM

  • Quelle tâche ?
  • Comment améliorer les performances ?
  • Quelles options en cas d’urgence ?
  • Autres options

Tâches d’un VACUUM

Ne pas confondre :

  • VACUUM seul
    • nettoyage des lignes mortes, visibility map, hint bits
  • ANALYZE
    • statistiques sur les données
  • VACUUM (ANALYZE)
    • nettoyage & statistiques
  • VACUUM (FREEZE)
    • gel des lignes
    • parfois gênant ou long
  • VACUUM FULL
    • bloquant !
    • jamais lancé par l’autovacuum

Options de performance de VACUUM

  • Index :
    • PARALLEL (v13+)
  • Taille du buffer ring (v16+)
    • BUFFER_USAGE_LIMIT
    • vacuum_buffer_usage_limit (256 ko)
  • SKIP_DATABASE_STATS, ONLY_DATABASE_STATS (v16+)
  • Éviter les verrous
    • SKIP_LOCKED
    • SET lock_timeout = '1s'

Options pour un VACUUM en urgence

  • INDEX_CLEANUP off
  • PROCESS_TOAST off (v14+)
  • TRUNCATE off

Autres options de VACUUM

  • VERBOSE

  • Ponctuellement :

    • DISABLE_PAGE_SKIPPING

Suivi du VACUUM

  • pg_stat_activity ou top
  • La table est-elle suffisamment nettoyée ?
  • Vue pg_stat_user_tables
    • last_vacuum / last_autovacuum
    • last_analyze / last_autoanalyze
  • log_autovacuum_min_duration

Progression du VACUUM

  • Pour VACUUM simple / VACUUM FREEZE

    • vue pg_stat_progress_vacuum
    • blocs parcourus / nettoyés
    • nombre de passes dans l’index
  • Partie ANALYZE

    • pg_stat_progress_analyze (v13)
  • Manuel ou via autovacuum

  • Pour VACUUM FULL

    • vue pg_stat_progress_cluster (v12)

Autovacuum

  • Processus autovacuum
  • But : ne plus s’occuper de VACUUM
  • Suit l’activité
  • Seuil dépassé => worker dédié
  • Gère : VACUUM, ANALYZE, FREEZE
    • mais pas FULL

Paramétrage du déclenchement de l’autovacuum

  • autovacuum (on !)
  • autovacuum_naptime (1 min)
  • autovacuum_max_workers (3)
    • plusieurs workers simultanés sur une base
    • un seul par table

Déclenchement de l’autovacuum

Seuil de déclenchement =

threshold + scale factor × nb lignes de la table

Déclenchement de l’autovacuum (suite)

  • Pour VACUUM
    • autovacuum_vacuum_scale_factor (20 %)
    • autovacuum_vacuum_threshold (50)
    • (v13) autovacuum_vacuum_insert_threshold (1000)
    • (v13) autovacuum_vacuum_insert_scale_factor (20 %)
  • Pour ANALYZE
    • autovacuum_analyze_scale_factor (10 %)
    • autovacuum_analyze_threshold (50)
  • Adapter pour une grosse table :
   ALTER TABLE table_name SET (autovacuum_vacuum_scale_factor = 0.1);

Paramétrage de VACUUM & autovacuum

  • VACUUM vs autovacuum
  • Mémoire
  • Gestion des coûts
  • Gel des lignes

VACUUM vs autovacuum

VACUUM manuel autovacuum
Urgent Arrière-plan
Pas de limite Peu agressif
Paramètres Les mêmes + paramètres de surcharge

Mémoire

  • Quantité de mémoire allouable
    • maintenance_work_mem / autovacuum_work_mem
    • monté souvent à ½ à 1 Go
  • Impact
    • VACUUM
    • construction d’index

Bridage du VACUUM et de l’autovacuum

  • Pauses régulières après une certaine activité
  • Par bloc traité
    • vacuum_cost_page_hit/_miss/_dirty (1/ 10 ou 2 /20)
    • jusque total de : vacuum_cost_limit (200)
    • pause : vacuum_cost_delay (en manuel : 0 ms !)
  • Surcharge pour l’autovacuum
    • autovacuum_vacuum_cost_limit (identique)
    • autovacuum_vacuum_cost_delay (2 ms)
    • => débit en écriture max : ~40 Mo/s
  • Pour accélérer : augmenter la limite

Paramétrage du FREEZE (1)

Le but est de geler les numéros de transaction assez vite :

Paramétrage du FREEZE (2)

Quand le VACUUM gèle-t-il les lignes ?

  • « Âge » d’une table : age ( pgclass.relfrozenxid )
    • Les blocs nettoyés/gelés sont notés dans la visibility map
  • vacuum_freeze_min_age (50 Mtrx)
    • âge des lignes rencontrées à geler
  • vacuum_freeze_table_age (150 Mtrx)
    • agressif (toute la table)
  • Au plus tard, par l’autovacuum sur toute la table :
    • autovacuum_freeze_max_age (200 Mtrx)
  • Attention après un import massif/migration logique !
    • VACUUM FREEZE préventif en période de maintenance

Autres problèmes courants

L’autovacuum dure trop longtemps

  • Fréquence de passage ?
  • Débit ?
  • Nombre de workers ?
  • Taille vraiment trop grosse ?
Nombre de workers avant et après la réduction d’autovacuum_vacuum_cost_delay

Arrêter un VACUUM ?

  • Lancement manuel ou script
    • risque avec certains verrous
  • Autovacuum
    • interrompre s’il gêne
  • Exception : to prevent wraparound lent et bloquant
    • pg_cancel_backend + VACUUM FREEZE manuel

Ce qui peut bloquer le VACUUM FREEZE

  • Causes :
    • sessions idle in transaction sur une longue durée
    • slot de réplication en retard/oublié
    • transactions préparées oubliées
    • erreur à l’exécution du VACUUM
  • Conséquences :
    • processus autovacuum répétés
    • arrêt des transactions
    • mode single…
  • Supervision :
    • check_pg_activity : xmin, max_freeze_age
    • surveillez les traces !

Résumé des conseils sur l’autovacuum

“Vacuuming is like exercising.
If it hurts, you’re not doing it enough!”

(Robert Haas, PGConf.EU 2023, Prague, 13 décembre 2023)

Résumé des conseils sur l’autovacuum (1/2)

  • Laisser l’autovacuum faire son travail
  • Augmenter le débit autorisé
  • Surveiller last_(auto)analyze / last_(auto)vacuum
  • Nombre de workers
  • Grosses tables, par ex :
ALTER TABLE table_name SET (autovacuum_analyze_scale_factor = 0.01) ;
ALTER TABLE table_name SET (autovacuum_vacuum_threshold = 1000000) ;
  • Mais ne pas hésiter à planifier un vacuumdb quotidien

Résumé des conseils sur l’autovacuum (2/2)

  • Mode manuel
    • batchs / tables temporaires / tables à insertions seules (<v13)
    • si pressé !
  • Danger du FREEZE brutal après migration logique ou gros import
    • prévenir
  • VACUUM FULL : dernière extrémité

Conclusion

  • VACUUM fait de plus en plus de choses au fil des versions
  • Convient généralement
  • Paramétrage apparemment complexe
    • en fait relativement simple avec un peu d’habitude

Questions

N’hésitez pas, c’est le moment !

Quiz

Travaux pratiques

Traiter la fragmentation

Détecter la fragmentation

Gestion de l’autovacuum

Travaux pratiques (solutions)

Partitionnement déclaratif (introduction)

  • Le partitionnement déclaratif apparaît avec PostgreSQL 10

  • Préférer PostgreSQL 13 ou plus récent

  • Ne plus utiliser l’ancien partitionnement par héritage.

Principe & intérêts du partitionnement

  • Faciliter la maintenance de gros volumes
    • VACUUM (FULL), réindexation, déplacements, sauvegarde logique…
  • Performances
    • parcours complet sur de plus petites tables
    • statistiques par partition plus précises
    • purge par partitions entières
    • pg_dump parallélisable
    • tablespaces différents (données froides/chaudes)
  • Attention à la maintenance sur le code

Partitionnement déclaratif

  • Table partitionnée
    • structure uniquement
    • index/contraintes répercutés sur les partitions
  • Partitions :
    • 1 partition = 1 table classique, utilisable directement
    • clé de partitionnement (inclue dans PK/UK)
    • partition par défaut
    • sous-partitions possibles
    • FDW comme partitions possible
    • attacher/détacher une partition

Partitionnement par liste

Partitionnement par liste

Partitionnement par liste : implémentation

CREATE TABLE t1(c1 integer, c2 text) PARTITION BY LIST (c1) ;

CREATE TABLE t1_a PARTITION OF t1 FOR VALUES IN (1, 2, 3) ;
CREATE TABLE t1_b PARTITION OF t1 FOR VALUES IN (4, 5) ;

Partitionnement par intervalle

Partitionnement par intervalle

Partitionnement par intervalle : implémentation

CREATE TABLE logs ( d timestamptz, contenu text) PARTITION BY RANGE (d) ;

CREATE TABLE logs_201901 PARTITION OF logs
                        FOR VALUES FROM ('2019-01-01') TO ('2019-02-01');
CREATE TABLE logs_201902 PARTITION OF logs
                        FOR VALUES FROM ('2019-02-01') TO ('2019-03-01');

CREATE TABLE logs_201912 PARTITION OF logs
                        FOR VALUES FROM ('2019-12-01') TO ('2020-01-01');

CREATE TABLE logs_autres PARTITION OF logs
                        DEFAULT ;               -- pour ne rien perdre

Partitionnement par hachage

Partitionnement par hachage

Partitionnement par hachage : implémentation

  • Hachage des valeurs
  • Répartition homogène
  • Indiquer un modulo et un reste
CREATE TABLE t3(c1 integer, c2 text) PARTITION BY HASH (c1);

CREATE TABLE t3_a PARTITION OF t3 FOR VALUES WITH (modulus 3,remainder 0);
CREATE TABLE t3_b PARTITION OF t3 FOR VALUES WITH (modulus 3,remainder 1);
CREATE TABLE t3_c PARTITION OF t3 FOR VALUES WITH (modulus 3,remainder 2);

Performances & partitionnement

  • Insertions via la table principale
    • quasi aucun impact
  • Lecture depuis la table principale
    • attention à la clé
  • Purge
    • simple DROP ou DETACH
  • Trop de partitions
    • attention au temps de planification

Attacher/détacher une partition

ALTER TABLE logs ATTACH PARTITION logs_archives
FOR VALUES FROM (MINVALUE) TO ('2019-01-01') ;
  • Vérification du respect de la contrainte
    • parcours complet de la table: lent + verrou !
ALTER TABLE logs DETACH PARTITION logs_archives ;
  • Rapide… mais verrou

Supprimer une partition

DROP TABLE logs_2018 ;

Limitations principales du partitionnement déclaratif

  • Temps de planification ! Max ~ 100 partitions
  • Création non automatique
  • Pas d’héritage multiple, schéma fixe
  • Partitions distantes sans propagation d’index
  • Limitations avant PostgreSQL 13/14

Conclusion

  • Préférer une version récente de PostgreSQL
  • Pour plus de détails sur le partitionnement

Quiz

Sauvegarde physique à chaud et PITR

PostgreSQL

Introduction

  • Sauvegarde traditionnelle
    • sauvegarde pg_dump à chaud
    • sauvegarde des fichiers à froid
  • Insuffisant pour les grosses bases
    • long à sauvegarder
    • encore plus long à restaurer
  • Perte de données potentiellement importante
    • car impossible de réaliser fréquemment une sauvegarde
  • Une solution : la sauvegarde PITR

Au menu

  • Mettre en place la sauvegarde PITR
    • sauvegarde : manuelle, ou avec pg_basebackup
    • archivage : manuel, ou avec pg_receivewal
  • Restaurer une sauvegarde PITR
  • Des outils

PITR

  • Point In Time Recovery
  • À chaud
  • En continu
  • Cohérente

Principes

  • Les journaux de transactions contiennent toutes les modifications
  • Il faut les archiver
    • …et avoir une image des fichiers à un instant t
  • La restauration se fait en restaurant cette image
    • …et en rejouant les journaux
    • dans l’ordre
    • entièrement
    • ou partiellement (ie jusqu’à un certain moment)

Avantages

  • Sauvegarde à chaud
  • Rejeu d’un grand nombre de journaux
  • Moins de perte de données

Inconvénients

  • Sauvegarde de l’instance complète
  • Nécessite un grand espace de stockage (données + journaux)
  • Risque d’accumulation des journaux
    • dans pg_wal en cas d’échec d’archivage… avec arrêt si il est plein !
    • dans le dépôt d’archivage si échec des sauvegardes
  • Restauration de l’instance complète
  • Impossible de changer d’architecture (même OS conseillé)
  • Plus complexe

Copie physique à chaud ponctuelle avec pg_basebackup

  • Réalise les différentes étapes d’une sauvegarde
    • via 1 ou 2 connexions de réplication + slots de réplication
    • base backup + journaux nécessaires
  • Copie intégrale,
    • image de la base à la fin du backup
  • Pas de copie incrémentale
  • Configuration : streaming (rôle, droits, slots)
$ pg_basebackup --format=tar --wal-method=stream \
 --checkpoint=fast --progress -h 127.0.0.1 -U sauve \
 -D /var/lib/postgresql/backups/

Sauvegarde PITR

2 étapes :

  • Archivage des journaux de transactions
    • archivage interne
    • ou outil pg_receivewal
  • Sauvegarde des fichiers
    • pg_basebackup
    • ou manuellement (outils de copie classiques)

Méthodes d’archivage

  • Deux méthodes :
    • processus interne archiver
    • outil pg_receivewal (flux de réplication)

Choix du répertoire d’archivage

  • À faire quelle que soit la méthode d’archivage
  • Attention aux droits d’écriture dans le répertoire
    • la commande configurée pour la copie doit pouvoir écrire dedans
    • et potentiellement y lire

Processus archiver : configuration

  • configuration (postgresql.conf)
    • wal_level = replica
    • archive_mode = on (ou always)
    • archive_command = '… une commande …'
    • ou : archive_library = '… une bibliothèque …' (v15+)
    • archive_timeout = '… min'
  • Ne pas oublier de forcer l’écriture de l’archive sur disque
  • Code retour de l’archivage entre 0 (ok) et 125

Processus archiver : lancement

  • Redémarrage de PostgreSQL
    • si modification de wal_level et/ou archive_mode
  • ou rechargement de la configuration

Processus archiver : supervision

  • Vue pg_stat_archiver
  • pg_wal/archive_status/
  • Taille de pg_wal
    • si saturation : Arrêt !
  • Traces

pg_receivewal

  • Archivage via le protocole de réplication
  • Enregistre en local les journaux de transactions
  • Permet de faire de l’archivage PITR
    • toujours au plus près du primaire
  • Slots de réplication obligatoires

pg_receivewal - configuration serveur

  • postgresql.conf :
# configuration  par défaut
max_wal_senders = 10
max_replication_slots = 10
  • pg_hba.conf :
host  replication  repli_user  192.168.0.0/24  scram-sha-256
  • Utilisateur de réplication :
CREATE ROLE repli_user LOGIN REPLICATION PASSWORD 'supersecret'

pg_receivewal - redémarrage du serveur

  • Redémarrage de PostgreSQL
  • Slot de réplication
SELECT pg_create_physical_replication_slot('archivage');

pg_receivewal - lancement de l’outil

  • Exemple de lancement
pg_receivewal -D /data/archives -S archivage
  • Journaux créés en temps réel dans le répertoire de stockage
  • Mise en place d’un script de démarrage
  • S’il n’arrive pas à joindre le serveur primaire
    • Au démarrage de l’outil : pg_receivewal s’arrête
    • En cours d’exécution : pg_receivewal tente de se reconnecter
  • Nombreuses options

Avantages et inconvénients

  • Méthode archiver
    • simple à mettre en place
    • perte au maximum d’un journal de transactions
  • Méthode pg_receivewal
    • mise en place plus complexe
    • perte minimale voire nulle

Sauvegarde PITR manuelle

  • 3 étapes :
    • fonction de démarrage
    • copie des fichiers par outil externe
    • fonction d’arrêt
  • Exclusive : simple… & obsolète ! (< v15)
  • Concurrente : plus complexe à scripter
  • Aucun impact pour les utilisateurs ; pas de verrou
  • Préférer des outils dédiés qu’un script maison

Sauvegarde manuelle - 1/3 : pg_backup_start

SELECT pg_backup_start (

  • un_label : texte
  • fast : forcer un checkpoint ?

)

Sauvegarde manuelle - 2/3 : copie des fichiers

  • Cas courant : snapshot
    • cohérence ? redondance ?
  • Sauvegarde des fichiers à chaud
    • répertoire principal des données
    • tablespaces
  • Copie forcément incohérente (la restauration des journaux corrigera)
  • rsync et autres outils
  • Ignorer :
    • postmaster.pid, log, pg_wal, pg_replslot et quelques autres
  • Ne pas oublier : configuration !

Sauvegarde manuelle - 3/3 : pg_backup_stop

Ne pas oublier !!

SELECT * FROM pg_backup_stop (

  • true : attente de l’archivage

)

Sauvegarde de base à chaud : pg_basebackup

Outil de sauvegarde pouvant aussi servir au sauvegarde basique

  • Backup de base ici sans les journaux :
$ pg_basebackup --format=tar --wal-method=none \
 --checkpoint=fast --progress -h 127.0.0.1 -U sauve \
 -D /var/lib/postgresql/backups/

Fréquence de la sauvegarde de base

  • Dépend des besoins
  • De tous les jours à tous les mois
  • Plus elles sont espacées, plus la restauration est longue
    • et plus le risque d’un journal corrompu ou absent est important

Suivi de la sauvegarde de base

  • Vue pg_stat_progress_basebackup
    • à partir de la v13

Restaurer une sauvegarde PITR

  • Une procédure relativement simple
  • Mais qui doit être effectuée rigoureusement

Restaurer une sauvegarde PITR (1/5)

  • S’il s’agit du même serveur
    • arrêter PostgreSQL
    • supprimer le répertoire des données
    • supprimer les tablespaces

Restaurer une sauvegarde PITR (2/5)

  • Restaurer les fichiers de la sauvegarde
  • Supprimer les fichiers compris dans le répertoire pg_wal restauré
    • ou mieux, ne pas les avoir inclus dans la sauvegarde initialement
  • Restaurer le dernier journal de transactions connu (si disponible)

Restaurer une sauvegarde PITR (3/5)

  • Indiquer qu’on est en restauration

  • Commande de restauration

    • restore_command = '… une commande …'
    • dans postgresql.[auto.]conf

Restaurer une sauvegarde PITR (4/5)

  • Jusqu’où restaurer :
    • recovery_target_name, recovery_target_time
    • recovery_target_xid, recovery_target_lsn
    • recovery_target_inclusive
  • Le backup de base doit être antérieur !
  • Suivi de timeline :
    • recovery_target_timeline : latest ?
  • Et on fait quoi ?
    • recovery_target_action : pause
    • pg_wal_replay_resume pour ouvrir immédiatement
    • ou modifier & redémarrer

Restaurer une sauvegarde PITR (5/5)

  • Démarrer PostgreSQL
  • Rejeu des journaux
  • Vérifier que le point de cohérence est atteint !

Restauration PITR : durée

  • Durée dépendante du nombre de journaux
    • rejeu séquentiel des WAL
  • Accéléré en version 15 (prefetch)

Restauration PITR : différentes timelines

  • Fin de recovery => changement de timeline :
    • l’historique des données prend une autre voie
    • le nom des WAL change
    • fichiers .history
  • Permet plusieurs restaurations PITR à partir du même basebackup
  • Choix :recovery_target_timeline
    • défaut : latest

Restauration PITR : illustration des timelines

Les timelines

Après la restauration

  • Bien vérifier que l’archivage a repris
    • et que les archives des journaux sont complètes
  • Ne pas hésiter à reprendre une sauvegarde complète
  • Bien vérifier que les secondaires ont suivi

Pour aller plus loin

  • Limiter la volumétrie des journaux sauvegardés
  • Quels sont les outils PITR ?

Réduire le nombre de journaux sauvegardés

Volumétrie archivée en fonction de checkpoint_timeout

  • Monter
    • checkpoint_timeout
    • max_wal_size

Compresser les journaux de transactions

  • wal_compression
    • moins de journaux
    • un peu plus de CPU
    • à activer
  • Outils de compression standards : gzip, bzip2, lzma
    • attention à ne pas ralentir l’archivage

Outils de sauvegarde PITR dédiés

  • Se faciliter la vie avec différents outils
    • pgBackRest
    • barman
    • pitrery (< v15, déprécié)
  • Fournissent :
    • un outil pour les backups, les purges…
    • une commande pour l’archivage

pgBackRest

  • Gère la sauvegarde et la restauration
    • pull ou push, multidépôts
    • mono- ou multiserveur
  • Indépendant des commandes système
    • protocole dédié
  • Sauvegardes complètes, différentielles ou incrémentales
  • Multithread, sauvegarde depuis un secondaire, archivage asynchrone…
  • Projet mature

barman

  • Gère la sauvegarde et la restauration
    • mode pull
    • multiserveurs
  • Une seule commande (barman)
  • Et de nombreuses actions
    • list-server, backup, list-backup, recover
  • Spécificité : gestion de pg_receivewal

pitrery

  • Projet en fin de vie, non compatible v15+
  • Gère la sauvegarde et la restauration
    • mode push
    • mono-serveur
  • Multi-commandes
    • archive_wal
    • pitrery
    • restore_wal

Conclusion

  • Une sauvegarde
    • fiable
    • éprouvée
    • rapide
    • continue
  • Mais
    • plus complexe à mettre en place que pg_dump
    • qui restaure toute l’instance

Questions

N’hésitez pas, c’est le moment !

Quiz

Travaux pratiques

pg_basebackup : sauvegarde ponctuelle & restauration

pg_basebackup : sauvegarde ponctuelle & restauration des journaux suivants

Travaux pratiques (solutions)

PostgreSQL : Gestion d’un sinistre

PostgreSQL

Introduction

  • Une bonne politique de sauvegardes est cruciale
    • mais elle n’empêche pas les incidents
  • Il faut être prêt à y faire face

Au menu

  • Anticiper les désastres
  • Réagir aux désastres
  • Rechercher l’origine du problème
  • Outils utiles
  • Cas type de désastres

Anticiper les désastres

  • Un désastre peut toujours survenir
  • Il faut savoir le détecter le plus tôt possible
    • et s’être préparé à y répondre

Documentation

  • Documentation complète et à jour
    • emplacement et fréquence des sauvegardes
    • emplacement des traces
    • procédures et scripts d’exploitation
  • Sauvegarder et versionner la documentation

Procédures et scripts

  • Procédures détaillées de restauration / PRA
    • préparer des scripts / utiliser des outils
    • minimiser le nombre d’actions manuelles
  • Tester les procédures régulièrement
    • bases de test, développement…
    • s’assurer que chacun les maîtrise
  • Sauvegarder et versionner les scripts

Supervision et historisation

  • Tout doit être supervisé
    • réseau, matériel, système, logiciels…
    • les niveaux d’alerte doivent être significatifs
  • Les métriques importantes doivent être historisées
    • cela permet de retrouver le moment où le problème est apparu
    • quand cela a un sens, faire des graphes

Automatisation

  • Des outils existent
    • PAF (Pacemaker), patroni, repmgr…
  • Automatiser une bascule est complexe
    • cela peut mener à davantage d’incidents
    • voire à des désastres (split brain)

Réagir aux désastres

  • Savoir identifier un problème majeur
  • Bons réflexes
  • Mauvais réflexes

Symptômes d’un désastre

  • Crash de l’instance
  • Résultats de requêtes erronnés
  • Messages d’erreurs dans les traces
  • Dégradation importante des temps d’exécution
  • Processus manquants
    • ou en court d’exécution depuis trop longtemps

Bons réflexes 1

  • Garder la tête froide
  • Répartir les tâches clairement
  • Minimiser les canaux de communication
  • Garder des notes de chaque action entreprise

Bons réflexes 2

  • Se prémunir contre une aggravation du problème
    • couper les accès applicatifs
  • Si une corruption est suspectée
    • arrêter immédiatement l’instance
    • faire une sauvegarde immédiate des fichiers
    • travailler sur une copie

Bons réflexes 3

  • Déterminer le moment de démarrage du désastre
  • Adopter une vision générale plutôt que focalisée sur un détail
  • Remettre en cause chaque élément de l’architecture
    • aussi stable (et/ou coûteux/complexe) soit-il
  • Éliminer en priorité les causes possibles côté hardware, système
  • Isoler le comportement précis du problème
    • identifier les requêtes / tables / index impliqués

Bons réflexes 4

  • En cas de défaillance matérielle
    • s’assurer de corriger sur du hardware sain et non affecté !
    • baies partagées…

Bons réflexes 5

  • Communiquer, ne pas rester isolé
  • Demander de l’aide si le problème est trop complexe
    • autres équipes
    • support
    • forums
    • listes

Bons réflexes 6

  • Dérouler les procédures comme prévu
  • En cas de situation non prévue, s’arrêter pour faire le point
    • ne pas hésiter à remettre en cause l’analyse
    • ou la procédure elle-même

Bons réflexes 7

  • En cas de bug avéré
    • tenter de le cerner et de le reproduire au mieux
    • le signaler à la communauté de préférence (configuration, comment reproduire)

Bons réflexes 8

  • Après correction
  • Tester complètement l’intégrité des données
    • pour détecter tous les problèmes
  • Validation avec export logique complet
pg_dumpall > /dev/null
  • Ou physique
pg_basebackup
  • Reconstruction dans une autre instance (vérification de cohérence)
pg_dumpall | psql -h autre serveur

Mauvais réflexes 1

  • Paniquer
  • Prendre une décision hâtive
    • exemple, supprimer des fichiers du répertoire pg_wal
  • Lancer une commande sans la comprendre, par exemple :
    • pg_resetwal
    • l’extension pg_surgery
    • DANGER, dernier espoir

Mauvais réflexes 2

  • Arrêter le diagnostic quand les symptômes disparaissent
  • Ne pas pousser l’analyse jusqu’au bout

Mauvais réflexes 3

  • Ne pas documenter
    • le résultat de l’investigation
    • les actions effectuées

Rechercher l’origine du problème

  • Quelques pistes de recherche pour cerner le problème
  • Liste non exhaustive

Prérequis

  • Avant de commencer à creuser
    • référencer les symptômes
    • identifier au mieux l’instant de démarrage du problème

Recherche d’historique

  • Ces symptômes ont-ils déjà été rencontrés dans le passé ?
  • Ces symptômes ont-ils déjà été rencontrés par d’autres ?
  • Attention à ne pas prendre les informations trouvées pour argent comptant !

Matériel

  • Vérifier le système disque (SAN, carte RAID, disques)
  • Un fsync est-il bien honoré de l’OS au disque ? (batteries !)
  • Rechercher toute erreur matérielle
  • Firmwares pas à jour
    • ou récemment mis à jour
  • Matériel récemment changé

Virtualisation

  • Mutualisation excessive
  • Configuration du stockage virtualisé
  • Rechercher les erreurs aussi niveau superviseur
  • Mises à jour non appliquées
    • ou appliquées récemment
  • Modifications de configuration récentes

Système d’exploitation 1

  • Erreurs dans les traces
  • Mises à jour système non appliquées
  • Modifications de configuration récentes

Système d’exploitation 2

  • Opération d’IO impossible
    • FS plein ?
    • FS monté en lecture seule ?
  • Tester l’écriture sur PGDATA
  • Tester la lecture sur PGDATA

Système d’exploitation 3

  • Consommation excessive des ressources
    • OOM killer (overcommit !)
  • Après un crash, vérifier les processus actifs
    • ne pas tenter de redémarrer si des processus persistent
  • Outils : sar, atop

PostgreSQL

  • Relever les erreurs dans les traces
    • ou messages inhabituels
  • Vérifier les mises à jour mineures

Paramétrage de PostgreSQL : écriture des fichiers

  • La désactivation de certains paramètres est dangereuse
    • fsync
    • full_page_write

Paramétrage de PostgreSQL : les sommes de contrôle

  • Activez les checksums !
    • initdb --data-checksums
    • pg_checksums --enable (à posteriori, v12)
  • Détecte les corruptions silencieuses
  • Impact faible sur les performances
  • Vérification lors de pg_basebackup (v11)

Erreur de manipulation

  • Traces système, traces PostgreSQL
  • Revue des dernières manipulations effectuées
  • Historique des commandes
  • Danger : kill -9, rm -rf, rsync, find … -exec

Outils

  • Quelques outils peuvent aider
    • à diagnostiquer la nature du problème
    • à valider la correction apportée
    • à appliquer un contournement
  • ATTENTION
    • certains de ces outils peuvent corrompre les données !

Outils - pg_controldata

  • Fournit des informations de contrôle sur l’instance
  • Ne nécessite pas que l’instance soit démarrée

Outils - export/import de données

  • pg_dump
  • pg_dumpall
  • COPY
  • psql / pg_restore
    • --section=pre-data / data / post-data

Outils - pageinspect

  • Extension
  • Vision du contenu d’un bloc
  • Sans le dictionnaire, donc sans décodage des données
  • Affichage brut
  • Utilisé surtout en debug, ou dans les cas de corruption
  • Fonctions de décodage pour les tables, les index (B-tree, hash, GIN, GiST), FSM
  • Nécessite de connaître le code de PostgreSQL

Outils - pg_resetwal

  • Efface les WAL courants
  • Permet à l’instance de démarrer en cas de corruption d’un WAL
    • comme si elle était dans un état cohérent
    • …ce qui n’est pas le cas
  • Cet outil est dangereux et mène à des corruptions !!!
  • Pour récupérer ce qu’on peut, et réimporter ailleurs

Outils - Extension pg_surgery

  • Extension apparue en v14
  • Collection de fonctions permettant de modifier le statut des tuples d’une relation
  • Extrêmement dangereuse

Outils - Vérification d’intégrité

  • À froid : pg_checksums (à froid, v11)
  • Lors d’une sauvegarde : pg_basebackup (v11)
  • amcheck : pure vérification
    • v10 : 2 fonctions pour l’intégrité des index
    • v11 : vérification de la cohérence avec la table (probabiliste)
    • v14 : ajout d’un outil pg_amcheck

Cas type de désastres

  • Les cas suivants sont assez rares
  • Ils nécessitent généralement une restauration
  • Certaines manipulations à haut risque sont possibles
    • mais complètement déconseillées !

Avertissement

  • Privilégier une solution fiable (restauration, bascule)
  • Les actions listées ici sont parfois destructrices
  • La plupart peuvent (et vont) provoquer des incohérences
  • Travailler sur une copie

Corruption de blocs dans des index

  • Messages d’erreur lors des accès par l’index ; requêtes incohérentes
  • Données différentes entre un indexscan et un seqscan
  • Supprimer et recréer l’index : REINDEX

Corruption de blocs dans des tables 1

ERROR: invalid page header in block 32570 of relation base/16390/2663
ERROR: could not read block 32570 of relation base/16390/2663:
       read only 0 of 8192 bytes
  • Cas plus problématique
  • Restauration probablement nécessaire

Corruption de blocs dans des tables 2

SET zero_damaged_pages = true ;
VACUUM FULL tablecorrompue ;
  • Des données vont certainement être perdues !

Corruption de blocs dans des tables 3

  • Si la corruption est importante, l’accès au bloc peut faire crasher l’instance
  • Il est tout de même possible de réinitialiser le bloc
    • identifier le fichier à l’aide de pg_relation_filepath()
    • trouver le bloc avec ctid / pageinspect
    • réinitialiser le bloc avec dd
    • il faut vraiment ne pas avoir d’autre choix

Corruption des WAL 1

  • Situés dans le répertoire pg_wal
  • Les WAL sont nécessaires au recovery
  • Démarrage impossible s’ils sont corrompus ou manquants
  • Si les fichiers WAL ont été archivés, les récupérer
  • Sinon, la restauration est la seule solution viable

Corruption des WAL 2

  • pg_resetwal permet de forcer le démarrage
  • ATTENTION !!!
    • cela va provoquer des pertes de données
    • des corruptions de données sont également probables
    • ce n’est pas une action corrective !

Corruption du fichier de contrôle

  • Fichier global/pg_control
  • Contient les informations liées au dernier checkpoint
  • Sans lui, l’instance ne peut pas démarrer
  • Recréation avec pg_resetwal… parfois
  • Restauration nécessaire

Corruption du CLOG

  • Fichiers dans pg_xact
  • Statut des différentes transactions
  • Son altération risque de causer des incohérences

Corruption du catalogue système

  • Le catalogue contient la définition du schéma
  • Sans lui, les données sont inaccessibles
  • Situation très délicate…

Conclusion

  • Les désastres peuvent arriver
  • Il faut s’y être préparé
  • Faites des sauvegardes !
    • et testez-les

Quiz

Travaux pratiques

Corruption d’un bloc de données

Corruption d’un bloc de données et incohérences

Travaux pratiques (solutions)