Dans le même esprit que ce qui avait été fait pour MySQL dans cet épisode, nous allons balayer les possibilités qu’offre la solution Cloud SQL PostgreSQL du cloud de Moutain View.
Pour la revue du décor (briques de service, organisation territoriale des régions, tiers et stockage, etc…) se référer à l’article pré-cité. Ces notions s’appliquent aux 3 PaaS Cloud SQL que sont MySQL, PostgreSQL et le petit dernier SQL Server (la GA est sortie en février l’année dernière), donc on ne reviendra pas dessus. Dans cet article, nous allons surtout voir quelles peuvent être les différences notables d’utilisation de PostgreSQL entre une instance on-prem et une instance Cloud SQL.
Versions, limitations et extensions supportées:
Pour ce qui est des versions, Cloud SQL supporte PostgreSQL 13 depuis novembre 2020, et était le premier clouder majeur à adopter la dernière release PostgreSQL puisqu’Amazon n’a annoncé la disponibilité qu’en février de cette année, et Azure ne va pas au delà de la version 11 en Single Server encore aujourd’hui (toutefois 12 et 13 sont disponible en Flexible et Hyperscale).
47 extensions sont supportées parmi lesquelles les principales : Gin, GiST, hstore, intarray, pgaudit, pgcrypto, pgstattuple, l’incontournable pg_stat_statements et évidemment plpgsql. A noter que CREATE EXTENSION est la seule commande qui nécessite les privilèges SUPERUSER qui soit autorisée.
Pour avoir l’exhaustivité:
postgres=> select setting from pg_settings where name='cloudsql.supported_extensions' ; -[ RECORD 1 ]--------------------------------------------------------------------------------------- setting | address_standardizer:3.0.2, address_standardizer_data_us:3.0.2, bloom:1.0, btree_gin:1.3, btree_gist:1.5, citext:1.6, cube:1.4, dblink:1.2, dict_int:1.0, dict_xsyn:1.0, earthdistance:1.1, fuzzystrmatch:1.1, hll:2.14, hstore:1.7, intagg:1.1, intarray:1.3, ip4r:2.4, isn:1.2, lo:1.1, ltree:1.2, pageinspect:1.8, pg_buffercache:1.3, pg_freespacemap:1.2, pg_partman:4.4.0, pg_prewarm:1.2, pg_repack:1.4.6, pg_similarity:1.0, pg_stat_statements:1.8, pg_trgm:1.5, pg_visibility:1.2, pgaudit:1.5, pgcrypto:1.3, pgfincore:1.2, pglogical:2.3.3, pgrowlocks:1.2, pgstattuple:1.5, pgtap:1.1.0, plpgsql:1.0, plproxy:2.10.0, postgis:3.0.2, postgis_raster:3.0.2, postgis_sfcgal:3.0.2, postgis_tiger_geocoder:3.0.2, postgis_topology:3.0.2, postgres_fdw:1.0, prefix:1.2.0, sslinfo:1.2, tablefunc:1.0, tsm_system_rows:1.0, tsm_system_time:1.0, unaccent:1.1, uuid-ossp:1.1
Pour activer une extension, par exemple pg_stat_statements:
postgres=> CREATE EXTENSION pg_stat_statements ; CREATE EXTENSION postgres=> select * from pg_extension ; -[ RECORD 1 ]--+------------------- oid | 14026 extname | plpgsql extowner | 10 extnamespace | 11 extrelocatable | f extversion | 1.0 extconfig | extcondition | -[ RECORD 2 ]--+------------------- oid | 16444 extname | pg_stat_statements extowner | 16389 extnamespace | 2200 extrelocatable | t extversion | 1.8 extconfig | extcondition |
Et configurer le nombre max de requêtes retenues dans la vue:
C:\Program Files (x86)\Google\Cloud SDK>gcloud sql instances patch cloudpg13 \ --database-flags pg_stat_statements.max=10000 The following message will be used for the patch API method. {"name": "cloudpg13", "project": "paas-postgresql-mysql", "settings": {"databaseFlags": [{"name": "pg_stat_statements.max", "value": "10000"}]}} WARNING: This patch modifies database flag values, which may require your instance to be restarted. Check the list of supported flags - https://cloud.google.com/sql/docs/postgres/flags - to see if your instance will be restarted when this patch is submitted. Do you want to continue (Y/n)? Y Patching Cloud SQL instance...done. Updated [https://sqladmin.googleapis.com/sql/v1beta4/projects/paas-postgresql-mysql/instances/cloudpg13].
postgres=> select query, total_plan_time, total_plan_time, total_exec_time, calls, shared_blks_hit postgres-> from pg_stat_statements order by total_exec_time limit 10 ; -[ RECORD 1 ]---+------------------------------------------------------------------------------------ query | show max_connections total_plan_time | 0 total_plan_time | 0 total_exec_time | 0.008291 calls | 1 shared_blks_hit | 0 -[ RECORD 2 ]---+------------------------------------------------------------------------------------ query | show max_wal_size total_plan_time | 0 total_plan_time | 0 total_exec_time | 0.008558 calls | 1 shared_blks_hit | 0 (...)
Quant aux limitations, on peut retrouver notamment:
– L’indisponibilité de LLVM/JiT et de la réplication logique pour les versions 12 et 13 pour l’instant.
– Toute commande nécessitant un accès aux privilèges SUPERUSER : ALTER SYSTEM, COPY (hors stdin), opérations sur les backends, pg_switch_wal(), pg_reload_conf(), opérations externes sur les fichiers, etc… la liste exhaustive se trouve dans la doc PostgreSQL.
Surface de paramétrage:
Les paramètres de configuration de PostgreSQL sont configurables via les Database Flags. Comme ALTER SYSTEM est désactivé il faudra passer soit par la console, soit la ligne de commande gloud, ou une API REST. Il existe 134 Database Flags en version POSTGRESQL_13:
$ gcloud sql flags list \ --database-version=POSTGRES_13 \ --sort-by=NAME NAME TYPE DATABASE_VERSION ALLOWED_VALUES autovacuum BOOLEAN POSTGRES_9_6,POSTGRES_10,POSTGRES_11,POSTGRES_12,POSTGRES_13 autovacuum_analyze_scale_factor FLOAT POSTGRES_9_6,POSTGRES_10,POSTGRES_11,POSTGRES_12,POSTGRES_13 autovacuum_analyze_threshold INTEGER POSTGRES_9_6,POSTGRES_10,POSTGRES_11,POSTGRES_12,POSTGRES_13 autovacuum_freeze_max_age INTEGER POSTGRES_9_6,POSTGRES_10,POSTGRES_11,POSTGRES_12,POSTGRES_13 (...) vacuum_freeze_table_age INTEGER POSTGRES_9_6,POSTGRES_10,POSTGRES_11,POSTGRES_12,POSTGRES_13 vacuum_multixact_freeze_min_age INTEGER POSTGRES_9_6,POSTGRES_10,POSTGRES_11,POSTGRES_12,POSTGRES_13 vacuum_multixact_freeze_table_age INTEGER POSTGRES_9_6,POSTGRES_10,POSTGRES_11,POSTGRES_12,POSTGRES_13 work_mem INTEGER POSTGRES_9_6,POSTGRES_10,POSTGRES_11,POSTGRES_12,POSTGRES_13
Attention à l’amalgame: un select sur pg_settings remontera nettement plus de paramètres que de flags configurables, ils ne seront tout simplement pas modifiables sur GCP. Par exemple s’il est possible de modifier work_mem :
$ gcloud sql instances patch cloudpg13 \ --database-flags work_mem=128 The following message will be used for the patch API method. {"name": "cloudpg13", "project": "paas-postgresql-mysql", "settings": {"databaseFlags": [{"name": "work_mem", "value": "128"}]}} WARNING: This patch modifies database flag values, which may require your instance to be restarted. Check the list of supported flags - https://cloud.google.com/sql/docs/postgres/flags - to see if your instance will be restarted when this patch is submitted. Do you want to continue (Y/n)? Y Patching Cloud SQL instance...done. Updated [https://sqladmin.googleapis.com/sql/v1beta4/projects/paas-postgresql-mysql/instances/cloudpg13]. $ gcloud sql instances describe cloudpg13 (...) databaseFlags: - name: work_mem value: '128'
On ne peut en revanche pas toucher à d’autres paramètres comme shared_buffers …
postgres=> show shared_buffers; shared_buffers ---------------- 1229MB (1 row) postgres=> alter system set shared_buffers to '1400MB' ; ERROR: must be superuser to execute ALTER SYSTEM command
…ou max_connections qui sont directement associés au type de tiers disponible:
Connectivité:
Google recommande d’utilisation cloud SQL Proxy pour se connecter de manière sécurisée sur les PaaS Cloud SQL. Il s’agit d’un middleware exécuté du côté applicatif, qui s’interconnecte avec une autre couche middleware côté PaaS:
Il faudra récupérer le programme client en fonction du type de client (Linux, windows,etc…).
Cloud SQL Proxy se connecte au PaaS avec un compte de service déclaré dans la partie IAM de gestion des identités de GCP, et ce compte doit disposer au moins du privilège cloudsql.instances.connect, qui peut être obtenu via les rôles Cloud SQL Admin, Editor ou Client selon ce qui est requis pour l’application. Une clé au format JSON (-credential_file) est générée et doit être déposée sur la machine cliente depuis laquelle le programme Cloud SQL Proxy sera exécuté:
$ cloud_sql_proxy_x64 \ -credential_file=paas-postgresql-mysql-0a7b74d61a31.json \ -instances="paas-postgresql-mysql:europe-west1:cloudpg13=tcp:5432" 2021/06/05 15:39:12 using credential file for authentication; email=xxxxxxxxxxxx@paas-postgresql-mysql.iam.gserviceaccount.com 2021/06/05 15:39:13 Listening on 127.0.0.1:5432 for paas-postgresql-mysql:europe-west1:cloudpg13 2021/06/05 15:39:13 Ready for new connections 2021/06/05 15:39:24 New connection for "paas-postgresql-mysql:europe-west1:cloudpg13"
Une fois le proxy lancé (il est conseillé de l’intégrer dans un service type systemd, ou dans un container), on peut ensuite lancer la connexion via un psql classique ou un autre programme client, redirigé vers le proxy qui tourne en localhost:
$ psql "host=127.0.0.1 sslmode=disable dbname=postgres user=postgres" Password for user postgres: psql (13.3, server 13.2) postgres=> select version() ; version ------------------------------------------------------------------------------------------ PostgreSQL 13.2 on x86_64-pc-linux-gnu, compiled by Debian clang version 10.0.1 , 64-bit (1 row)
Ca peut paraître lourd, mais cela permet de centraliser les accès aux PaaS Cloud SQL d’un même Project avec un seul service Cloud SQL Proxy. Evidemment ce mode supporte l’utilisation de certificats SSL ce qui sera conseillé si les accès clients sont initiés depuis l’extérieur et sans VPN.
Sauvegarde et restauration:
Deux types de sauvegardes disponibles, automatiques et à la demande ou manuels.
Sauvegardes automatiques
Les backups automatiques sont activés au niveau du PaaS, soit à la création soit plus tard via une modification de paramètre instance. Ils sont exécutés lors de fenêtres de maintenance de 4 heures, et sont conservés soit sur une période soit en fonction d’un nombre de backups (7 par défaut, max 365):
A noter que leur localisation est également paramétrable, si on souhaite favoriser une région plutôt qu’une autre en fonction de contraintes légales. L’activation de la restauration en Point-In-Time active la sauvegarde des WALs en plus, avec une rétention en jours (7 par défaut). Les journaux antérieurs au dernier backup complet effectué sont automatiquement supprimés.
Sauvegardes à la demande
Il est aussi possible d’effectuer des backups à la demande avec gcloud (ou la console ou API REST):
$ gcloud sql backups create --instance=cloudpg13 --location=europe-west1 --description=MANUAL Backing up Cloud SQL instance...done. [https://sqladmin.googleapis.com/sql/v1beta4/projects/paas-postgresql-mysql/instances/cloudpg13] backed up. $ gcloud sql backups list --instance=cloudpg13 ID WINDOW_START_TIME ERROR STATUS INSTANCE 1623055883991 2021-06-07T08:51:23.991+00:00 - SUCCESSFUL cloudpg13 1623055751008 2021-06-07T08:49:11.008+00:00 - SUCCESSFUL cloudpg13 1622640837128 2021-06-02T13:33:57.128+00:00 - SUCCESSFUL cloudpg13 $ gcloud sql backups list --instance=cloudpg13 --filter="type=AUTOMATED" ID WINDOW_START_TIME ERROR STATUS INSTANCE 1622640837128 2021-06-02T13:33:57.128+00:00 - SUCCESSFUL cloudpg13 $ gcloud sql backups list --instance=cloudpg13 --filter="type=ON_DEMAND" ID WINDOW_START_TIME ERROR STATUS INSTANCE 1623055883991 2021-06-07T08:51:23.991+00:00 - SUCCESSFUL cloudpg13 1623055751008 2021-06-07T08:49:11.008+00:00 - SUCCESSFUL cloudpg13
Sinon, un DESCRIBE sur chaque BACKUP_ID permettra de faire la distinction :
$ gcloud sql backups describe 1623055883991 --instance=cloudpg13 backupKind: SNAPSHOT description: MANUAL endTime: '2021-06-07T08:52:04.569Z' enqueuedTime: '2021-06-07T08:51:23.991Z' id: '1623055883991' instance: cloudpg13 kind: sql#backupRun location: europe-west1 selfLink: https://sqladmin.googleapis.com/sql/v1beta4/projects/paas-postgresql-mysql/instances/cloudpg13/backupRuns/1623055883991 startTime: '2021-06-07T08:51:23.992Z' status: SUCCESSFUL type: ON_DEMAND windowStartTime: '2021-06-07T08:51:23.991Z' $ gcloud sql backups describe 1622640837128 --instance=cloudpg13 backupKind: SNAPSHOT endTime: '2021-06-02T13:35:18.283Z' enqueuedTime: '2021-06-02T13:33:57.128Z' id: '1622640837128' instance: cloudpg13 kind: sql#backupRun location: eu selfLink: https://sqladmin.googleapis.com/sql/v1beta4/projects/paas-postgresql-mysql/instances/cloudpg13/backupRuns/1622640837128 startTime: '2021-06-02T13:33:57.136Z' status: SUCCESSFUL type: AUTOMATED windowStartTime: '2021-06-02T13:33:57.128Z'
Exports de données
Mais qu’ils soient automatiques ou manuels, ils ne sont pas exportables, c’est à dire que l’on ne peut pas récupérer les fichiers résultants d’un backup. Et comme lorsque l’on supprime un PaaS, tous les backups sont supprimés, il faudra pouvoir exporter les données pour se donner une solution de retour arrière en cas de problème, soit via un client pg_dump classique :
$ pg_dump --host=127.0.0.1 --username=postgres --dbname=dvdrental > backup.dmp Password:
… soit via gcloud dans un bucket GS (qui ne sortira ni fonction, ni procédure stockée, ni trigger contrairement à pg_dump), le compte de service du PaaS devra disposer des privilèges storage.legacyBucketWriter et storage.legacyObjectReader sur le bucket en question:
# Creation du bucket $ gsutil mb -c NEARLINE -l europe-west1 -b on gs://cloudpg13backups Creating gs://cloudpg13backups/... $ gsutil ls gs://cloudpg13backups/ # Attribution des droits au compte de service $ gsutil iam ch serviceAccount:xxxxxxxxxxx-xxxxxxxx@gcp-sa-cloud-sql.iam.gserviceaccount.com:legacyBucketWriter,legacyObjectReader gs://cloudpg13backups # Export des données dans le bucket $ gcloud sql export sql cloudpg13 gs://cloudpg13backups/cloudpg13.dvdrental.dmp.gz --database=dvdrental Exporting Cloud SQL instance...done. Exported [https://sqladmin.googleapis.com/sql/v1beta4/projects/paas-postgresql-mysql/instances/cloudpg13] to [gs://cloudpg13backups/cloudpg13.dvdrental.dmp.gz]. $ gsutil ls gs://cloudpg13backups gs://cloudpg13backups/cloudpg13.dvdrental.dmp.gz # Et récupération en local ... $ gsutil cp gs://cloudpg13backups/cloudpg13.dvdrental.dmp.gz cloudpg13.dvdrental.dmp.gz Copying gs://cloudpg13backups/cloudpg13.dvdrental.dmp.gz... - [1 files][ 8.3 KiB/ 8.3 KiB] Operation completed over 1 objects/8.3 KiB.
Restauration:
On peut restaurer sur le PaaS courant ou créer un autre PaaS avec un backup. Pour la restauration d’un backup complet :
$ gcloud sql backups describe 1623083406184 --instance=cloudpg13 backupKind: SNAPSHOT description: 2021-06-07 18:31 endTime: '2021-06-07T16:30:46.801Z' enqueuedTime: '2021-06-07T16:30:06.184Z' id: '1623083406184' instance: cloudpg13 kind: sql#backupRun location: europe-west1 selfLink: https://sqladmin.googleapis.com/sql/v1beta4/projects/paas-postgresql-mysql/instances/cloudpg13/backupRuns/1623083406184 startTime: '2021-06-07T16:30:06.185Z' status: SUCCESSFUL type: ON_DEMAND windowStartTime: '2021-06-07T16:30:06.184Z' $ gcloud sql backups restore 1623083406184 --restore-instance=cloudpg13 --backup-instance=cloudpg13 All current data on the instance will be lost when the backup is restored. Do you want to continue (Y/n)? Y Restoring Cloud SQL instance...done. Restored [https://sqladmin.googleapis.com/sql/v1beta4/projects/paas-postgresql-mysql/instances/cloudpg13].
Par contre si on veut restaurer en Point-in-Time, il faudra restaurer sur une nouvelle instance que l’on va cloner:
$ gcloud sql instances clone cloudpg13 cloudpg13-202106071200 --point-in-time 2021-06-07T17:00:00.000Z Cloning Cloud SQL instance...\ Created [https://sqladmin.googleapis.com/sql/v1beta4/projects/paas-postgresql-mysql/instances/cloudpg13-202106071200]. NAME DATABASE_VERSION LOCATION TIER PRIMARY_ADDRESS PRIVATE_ADDRESS STATUS cloudpg13-202106071200 POSTGRES_13 europe-west1-b db-custom-1-3840 35.187.59.124 - RUNNABLE
L’ancienne instance reste accessible.
Quant aux exports, soit rejouer avec pg_restore ou psql selon le format de sortie (custom ou plain text respectivement), ou réimporter la sauvegarde avec gcloud:
Avec psql :
postgres=> create database dvdrental ; CREATE DATABASE postgres=> \c dvdrental psql (13.3, server 13.2) You are now connected to database "dvdrental" as user "postgres". dvdrental=> \i backup.dmp CREATE TABLE ALTER TABLE COPY 200 COPY 603 COPY 16 COPY 600 COPY 109 COPY 599 COPY 1000 (...)
Avec gcloud:
$ gcloud sql import sql cloudpg13 gs://cloudpg13backups/cloudpg13.dvdrental.dmp.gz \ --database=dvdrental --user=postgres Data from [gs://cloudpg13backups/cloudpg13.dvdrental.dmp.gz] will be imported to [cloudpg13]. Do you want to continue (Y/n)? Y Importing data into Cloud SQL instance...done. Imported data from [gs://cloudpg13backups/cloudpg13.dvdrental.dmp.gz] into [https://sqladmin.googleapis.com/sql/v1beta4/projects/paas-postgresql-mysql/instances/cloudpg13].
Note: Pour les imports et les exports customs de données dans des fichiers plats ou CSV, noter que la commande COPY nécessite le privilège SUPERUSER donc elle n’est pas utilisable dans un script. Elle fonctionnera seulement si les données sont fournies sur l’entrée standard (stdin). Pour contourner ce problème sous le prompt psql, il est possible d’utiliser la méta-commande \copy :
dvdrental=> COPY public.actor (actor_id, first_name, last_name, last_update) FROM '3057.dat'; ERROR: must be superuser or a member of the pg_read_server_files role to COPY from a file HINT: Anyone can COPY to stdout or from stdin. psql's \copy command also works for anyone. dvdrental=> \copy public.actor (actor_id, first_name, last_name, last_update) FROM '3057.dat'; COPY 200
Mise à jour et maintenance:
Comme les autres services managés chez les concurrents, il existe une fenêtre de maintenance imposée en quelque sorte qui permet de faire passer les mises à jour. Durant cette période l’accès au PaaS est coupé, le doc indique une coupure de 60 secondes en moyenne, mais la vraie difficulté est de pouvoir prévoir cette coupure, d’autant que les instances réplicas ne peuvent être sollicités sur cette période car ils sont coupés eux-aussi.
Comme sur RDS, il est possible de planifier les fenêtres de maintenance sur des périodes attendues pour éviter qu’elles n’arrivent de manière aléatoire.
$ gcloud sql instances patch cloudpg13 \ --maintenance-window-day=SUN \ --maintenance-window-hour=04
Il est également possible de planifier une période durant laquelle la maintenance ne peut pas s’appliquer avec un maximum de 90 jours, par exemple pour couvrir une période d’activité de vente particulièrement importante pour votre chiffre d’affaires (ventes privées, soldes, période de fêtes, etc…). La période d’exclusion peut être récurrente tous les ans si on n’indique pas l’année dans les paramètres mais seulement une date au format mm-dd:
$ gcloud sql instances patch cloudpg13 \ --deny-maintenance-period-start-date 06-01 \ --deny-maintenance-period-end-date 06-30 \ --deny-maintenance-period-time 00:00:00
On peut enfin s’abonner à des notifications pour être prévenu d’une coupure prochaine, via email, dans les préférences de l’utilisateur :
Supervision :
- Journaux d’erreur:
L’accès aux journaux de PostgreSQL peut se faire soit via la console soit via gcloud loggging :
$ gcloud logging read resource.type="cloudsql_database" --project=paas-postgresql-mysql --limit=1 --format=json [ { "insertId": "s=4a2d092448f2442196dbf937d53aa2f3;i=11b17e;b=8d370594a8c64ab6bf7936578969b58d;m=2f32331f4e;t=5c50feb23e9aa;x=56218d300d4ea42d-0-0@a1", "logName": "projects/paas-postgresql-mysql/logs/cloudsql.googleapis.com%2Fpostgres.log", "receiveTimestamp": "2021-06-18T20:10:45.252620488Z", "resource": { "labels": { "database_id": "paas-postgresql-mysql:cloudpg13", "project_id": "paas-postgresql-mysql", "region": "europe" }, "type": "cloudsql_database" }, "severity": "INFO", "textPayload": "2021-06-18 20:10:43.733 UTC [52719]: [2-1] db=,user= LOG: automatic analyze of table \"cloudsqladmin.public.heartbeat\" system usage: CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s", "timestamp": "2021-06-18T20:10:43.733930Z" } ]
Avec un outil comme jq, il devient possible de récupérer précisément des informations contenues dans le blob JSON. Une autre solution peut consister à exporter les logs sur un autre stockage (Cloud Storage, BigTable ou Elastic Cloud par exemple) via des sinks.
- Compteurs de performance de base:
La console permet d’accéder à 8 compteurs de base:
- Monitoring:
La brique Cloud Monitoring permet d’aller un peu plus loin et se créer des dashboards plus complets avec davantage de métriques:
Ainsi que se créer des alertes avec notification.
- Optimisation SQL:
Query Insights donne une première vision des requêtes en exécution si l’instance est activée avec la trace Insight :
$ gcloud sql instances create ... --insights-config-query-insights-enabled
Elle est non payante si on y accède via la console, et avec une semaine de rétention. Elle présente les requêtes avec leur temps d’exécution, le nombre de calls et le nombre moyen de lignes retournées. Deux choses à noter cependant:
– Elle est capable de normaliser les requêtes et de générer un queryid (query_hash pour gcloud) comme peut le faire pg_stat_statements:
dvdrental=> select count(1) from inventory where film_id = 995 ; count ------- 6 (1 row) dvdrental=> select count(1) from inventory where film_id = 1000 ; count ------- 8 (1 row)
– La deuxième il peut afficher un plan type avec le détail des opérateurs:
L’autre bonne nouvelle c’est que pg_stat_statements est également disponible et que les actions SUPERUSER-only sont autorisées (modifier les paramètres GUC de PGSS ou appeler pg_stat_statements_reset()). On peut donc se construire un outil ou porter un existant sur des PaaS GCP sans trop de problèmes à priori.
MCO hors backups : vacuums, gestion des partitions, etc…
Pour planifier des tâches hors backups type vacuum full, etc… on pourra utiliser la brique Cloud Scheduler qui permet via des Cloud Functions serverless et des jobs de lancer des tâches planifiées.
Haute disponibilité:
On ne rentrera pas dans les détails, là encore ça pourra faire l’objet d’un post dédié, mais globalement lorsque l’on déploie un PaaS PostgreSQL, il est possible d’activer une haute disponibilité au niveau régional. Une instance standby sera créé dans une autre zone de la même région, et la synchronisation sera assurée au niveau blocs disques.
Cloud SQL étant une ressource régionale, il n’est pas possible de crééer une standby dans une autre région, donc pour se prémunir d’une indisponibilité de toute une région, la solution est de créer un read-replica dans une autre région, mais qui sera répliqué de manière asynchrone:
(source : https://cloud.google.com/architecture/intro-to-cloud-sql-disaster-recovery)
Dans le cas d’une indisponibilité de zone, l’utilisation de cloud_sql_proxy permettra une bascule transparente vers la standby. Toutefois en cas de perte de la région, la bascule vers le read réplica devra se faire manuellement via une procédure, qui consistera globalement à :
1) Détacher le read-replica de son primaire en échec.
2) Faire un promote sur le réplica pour qu’il devienne primaire
3) S’assurer qu’aucune application ne peut plus de connecter à l’ancien primaire ou standby dans la région initiale, car il n’y a aucun garde-fou contre le split-brain
4) Faire pointer les applications sur le nouveau primaire dans la deuxième région.
5) Potentiellement ré-implémenter une standby régionale dans la deuxième région, et un read réplica dans une troisième région pour se prémunir d’une nouvelle perte de la région 2.
Evidemment tout cela pourra être automatisé via gcloud ou Terraform mais personnellement je ne suis pas un grand fan des solutions qui basculent toutes seules, même on-premise. Il vaut mieux avoir une procédure robuste, que chaque étape soit scriptée mais garder la main sur l’enchaînement me paraît plus rassurant.
Migration on-prem vers Cloud SQL:
Contrairement à Cloud SQL pour MySQL, Cloud SQL pour PostgreSQL ne supporte pas la réplication depuis une source externe, donc l’option de migrer un cluster PostgreSQL on-prem via la réplicaiton est exclu. Il reste la solution d’importer directement un pg_dump dans une instance PaaS mais cela supposera une indisponibilité plus grande et qui sera fonction du volume à manipuler.
Attention à la valeur de temp_file_limit lors de la recréation des indexes. La valeur par défaut pour mon PaaS en 13 est à environ 2Gb alors qu’on-prem il n’y a pas de limitation.
Autre solution, utiliser le Cloud Migration Service mais dont l’étendue des fonctionnalités dépasse largement le scope de cet article.
Bilan :
Lorsque j’avais évalué la première génération de PaaS PostgreSQL sur GCP en 2018, j’avais trouvé pas mal de lacunes, presque rien pour monitorer, une faible surface de configuration.
Le moins qu’on puisse dire c’est que depuis des efforts ont été faits pour réduire la fracture entre les capacités on-prem et les capacités d’un PaaS équivalent: extensions, interfaces, versions, paramètres GUC, tout y passe. Le seul couac qui reste encore c’est de franchir la première marche (la migration vers le PaaS) surtout si l’on a une grande quantité de données à migrer. Il faudra tester l’assistant de migration, peut être dans un prochain épisode !
A+ ~David
Continuez votre lecture sur le blog :
- AWS RDS : les extensions PostgreSQL (Emmanuel RAMI) [AWSPostgreSQL]
- PaaS PostgreSQL AWS vs Azure (Capdata team) [AWSAzureNon classéPostgreSQL]
- Comparatif MySQL dans le PaaS, épisode 1 : Google Cloud SQL (David Baffaleuf) [GCPMySQL]
- Azure et PostgreSQL en PaaS (Capdata team) [AzurePostgreSQL]
- Nouveautés pg_stat_statements avec PostgreSQL 15 (David Baffaleuf) [PostgreSQL]