Ce projet a pour but de mettre à disposition
- des utilisateurs internes (développeurs, PO, support, métiers)
- des utilisateurs externes (partenaires, membres d'une organisation dans PixOrga) les possibilités suivantes:
- exécuter des rapports dans Metabase
- exécuter des requêtes SQL
Les contraintes majeures sont:
- disposer des données les plus récentes
- ne pas impacter la performance de la BDD
- ne donner accès qu'aux utilisateurs autorisés.
La solution est la suivante:
- importer chaque nuit les données de production complète dans une BDD dite "interne"
- importer chaque nuit une partie des données de production dans une BDD dite "externe"
- dans Metabase, ne donner accès aux externes que sur cette BDD "externe"
- suite à l'import, créer des objets supplémentaires pour assurer un temps d'exécution des rapport acceptables (index, vues matérialisées,..)
Pour importer les données, récupérer le backup créé automatiquement par Scalingo. Afin de garder un seul repository partagé par les applications, utiliser les variables d'environnement.
Ce projet est prévu pour être déployé sur une application Scalingo associée à une base de donnée PostgreSQL.
Pour satisfaire les contraintes de déploiement Scalingo, le Procfile
déclare un conteneur de type web
qui démarre un serveur Web "vide".
Une fois l'application créée et déployée une première fois, il faut:
- mettre à 0 le nombre de conteneurs de type
web
- mettre à 1 le nombre de conteneurs de type
background
.
Variables d'environnement :
-
SCALINGO_APP
: cette variable est utilisée automatiquement par l'outil CLI de Scalingo, et doit contenir le nom de l'application portant la base de données source (pix-api-production
typiquement). -
SCALINGO_API_TOKEN
: cette variable est utilisée automatiquement par l'outil CLI de Scalingo pour l'authentification, et doit être renseignée avec un token d'utilisateur Scalingo étant collaborateur de l'application désignée parSCALINGO_APP
. -
SCHEDULE
: une chaîne au formatcron
(interprétée par https://www.npmjs.com/package/node-cron) qui spécifie la fréquence à laquelle l'opération de réplication doit être exécutée. Exemple :10 5 * * *
correspond à une exécution quotidienne à 5h10 UTC. -
DATABASE_URL
: URL d'accès à la base cible qui sera écrasée et alimentée depuis le backup à chaque exécution. Cette variable est en principe automatiquement alimentée par Scalingo lors de l'ajout d'une base PostgreSQL. -
MAX_RETRY_COUNT
: cette variable est utilisée pour indiquer le nombre maximum de tentative de rejeux -
RESTORE_FK_CONSTRAINTS
: restaurer ou non les contraintes de clés étrangères. Si non renseignée, les contraintes de clés étrangères ne sont pas restaurées. Si "true", les contraintes de clés étrangères sont restaurées. -
RESTORE_ANSWERS_AND_KES
: restaurer ou non les tablesanswers
etknowledge-elements
. Si non renseignée, ces tables ne sont pas restaurées. Si "true", ces tables sont restaurées.
Une opération de réplication peut être lancée immédiatement (hors tâche planifiée) en exécutant le script run.js
dans un conteneur individuel Scalingo :
Sur la BDD destinée aux internes $ scalingo run --region osc-secnum-fr1 -a pix-datawarehouse-production --size M --detached node run.js
Sur la BDD destinée aux externes $ scalingo run --region osc-secnum-fr1 -a pix-datawarehouse-ex-production --size M --detached node run.js
Certaines étapes de la procédure de réplication sont spécifiques à l'environnement Scalingo et pas pertinentes à exécuter en local lors du développement sur le script. Un exemple d'exécution d'une partie des étapes, en supposant un backup déjà téléchargé et un serveur PostgreSQL disponible en local:
$ DATABASE_URL=postgres://postgres@localhost/pix_restore node -e "steps=require('./steps'); steps.dropCurrentObjects(); steps.restoreBackup({compressedBackup:'backup.tar.gz'})"
Application Scalingo hors osc-secnum-fr1 pour éviter les considérations de sécurité des données
Vérifier les données présentes dans la BDD à exporter $ scalingo -a pix-api-review-pr1973 pgsql-console
Lancer un backup (ou ne rien faire, le dernier est utilisé par défaut)
Lancer l'import du backup $ scalingo run --region osc-fr1 --app pix-db-replication --size S --detached node run.js
Vérifier le résultat
$ scalingo -a pix-db-replication pgsql-console
SELECT id, email FROM "users" LIMIT 5;
Déroulement :
- une BDD est créé en local sur l'URL $TEST_POSTGRES_URL (défaut:
postgres://postgres@localhost
), instancepix_replication_test
- la table
test_table
est créée et chargée avec 100 000 enregistrements (1 colonne, PK) - un export est effectué par
pg_dump --c
dans un dossier temporaire - la restauration à tester est appelée depuis steps.js/restoreBackup
- les assertions SQL sont effectuées par un
runSql
, un wrapper autour depsql
Note: le dump Scalingo est créé avec des options pg_dump
différentes
Se connecter à la BDD de test
psql postgres://postgres@localhost/pix_replication_test
Les tests d'intégration sortent en erreur sur CircleCI avec le message suivant
Error: spawn psql ENOENT
L'analyse de ce qui prend du temps est complexe sur les logs brutes s'il y a:
- plusieurs jobs de restauration (variable d'environnement
PG_RESTORE_JOBS
); - beaucoup de tables.
Pour faciliter l'analyse, utilisez le script d'analyse de log.
Etapes:
- récupérer les logs
scalingo --region osc-secnum-fr1 --app <NOM_APPLICATION> logs --lines 100000 > logs.txt
- déterminer la date d'exécutionau format YYYY-MM-DDDD, ex: 2020-10-13
- exécuter
node utils/parse-replication-logs.js ./logs.txt <DATE_EXECUTION>
Exemples de résultat sur pix-datawarehouse-production
le 22/10/2020
$ node utils/parse-replication-logs.js ./logs.txt 2020-10-22 1 ↵
Durée de récupération du backup: 1h 27min 42s
Durée de réplication: 8h 51min 17s
Durée de l'enrichissement: 1h 39min 42s
Durée totale: 11h 58min 41s
FK CONSTRAINT total duration : 7h 57min 25s
FK CONSTRAINT schooling-registrations students_organizationid_foreign : 2h 11min 4s
FK CONSTRAINT competence-evaluations competence_evaluations_assessmentid_foreign : 2h 10min 41s
FK CONSTRAINT knowledge-elements knowledge_elements_answerid_foreign : 0h 58min 52s
CONSTRAINT total duration : 2h 49min 60s
CONSTRAINT answers answers_pkey : 1h 26min 32s
CONSTRAINT knowledge-elements knowledge-elements_pkey : 1h 13min 36s
CONSTRAINT knowledge-element-snapshots knowledge-element-snapshots_pkey : 0h 2min 59s
INDEX total duration : 10h 21min 34s
INDEX knowledge-elements_assessmentId_idx : 4h 16min 55s
INDEX knowledge_elements_userid_index : 3h 49min 46s
INDEX answers_assessmentid_index : 2h 7min 20s
SEQUENCE total duration : 0h 0min 28s
SEQUENCE SET assessments_id_seq : 0h 0min 4s
SEQUENCE SET user-orga-settings_id_seq : 0h 0min 3s
SEQUENCE SET assessment-results_id_seq : 0h 0min 3s
TABLE DATA total duration : 4h 8min 7s
TABLE DATA knowledge-element-snapshots : 1h 51min 60s
TABLE DATA knowledge-elements : 1h 11min 25s
TABLE DATA answers : 0h 46min 55s
S'il y a eu
- plusieurs exécutions le même jour
- une exécution incomplète (pas de message
Start restore
ouRestore done
)
Alors vous obtiendrez le message suivant TypeError: Cannot read property '0' of null