Restauration et conservation
- Leçon 16
- 60 min
- Module 5 : Fichiers, vecteurs et cycle de vie
Leçon 16 sur 16 · Bases de données et stockage pour les applications d'IARestauration et conservation
1. Choisir le stockage selon la charge de travail
2. Concevoir un schéma relationnel
3. Accéder aux données depuis une API
4. Améliorer la performance des requêtes
5. Fichiers, vecteurs et cycle de vie
Ce que vous saurez faire
Prouvez que vous pouvez restaurer une sauvegarde avant d’en avoir besoin. Supprimez ensuite les données d’un client de la base, des fichiers et des vecteurs. Trouvez ce qu’une suppression inachevée laisse derrière elle.
Avant de commencerCe qu’il faut savoir et avoir sous la main
Ce que vous devez savoir
- Les transactions : tout ou rien, dans Transactions.
- Les clés étrangères et leurs règles de suppression, dans Contraintes d’intégrité.
- Les fichiers dans le stockage objet, avec une ligne par fichier, dans Modèles de stockage objet; les versions des vecteurs et la somme de contrôle du texte, dans Stockage des vecteurs.
Ce qu’il vous faut sur votre ordinateur
- Le projet après Stockage des vecteurs, avec PostgreSQL et Azurite en marche.
python -m pytestaffiche101 passed, 1 deselected(101 tests réussis, 1 exclu). pg_dumpetpg_restoreversion 18, fournis par l’installateur PostgreSQL ou le paquet Homebrewlibpq. Sans eux,scripts/backup.pyles exécute dans le conteneur Docker; le cours n’a pas testé cette méthode.
Cette leçon ajoute la migration 012_erasure.sql, quatre scripts (backup, restore_drill, erase_customer, scan) et un fichier de tests. Ensuite, votre projet correspond à l’instantané end-of-m05, la version finale du projet du cours.
La clé de rechange dans le tiroir
Section intitulée « La clé de rechange dans le tiroir »Bien des familles gardent une clé de maison de rechange dans un tiroir. Personne ne l’a essayée depuis le changement des serrures. Le jour où quelqu’un en a besoin, elle ne tourne pas.
Les écoles font des exercices d’évacuation pour la même raison. Un plan que personne n’a essayé n’est qu’un espoir. L’exercice révèle la porte bloquée alors qu’il n’y a pas de feu.
Le problème : « nous avons des sauvegardes chaque nuit »
Section intitulée « Le problème : « nous avons des sauvegardes chaque nuit » »Tomás ne s’inquiète pas de la restauration. « Nous avons des sauvegardes chaque nuit, tout va bien. » Personne n’en a jamais restauré une.
Le cours a fait ce que personne chez Larkfield n’avait fait : restaurer des sauvegardes et vérifier les données récupérées. Trois sauvegardes ont échoué, chacune pour une vraie raison. Chacune avait pourtant produit un fichier qui semblait correct :
- Une sauvegarde dont la description a été écrite juste après l’exportation, pendant que l’API continuait d’écrire. La restauration contenait 331 messages; la description en annonçait 333.
- Une bonne sauvegarde, restaurée après que l’équipe avait effacé un client. La base de données est revenue, mais 33 des 43 fichiers étaient présents. Et le client effacé était revenu aussi.
- Une bonne sauvegarde, restaurée sur un serveur PostgreSQL sans l’extension pgvector :
extension "vector" is not available(l’extension « vector » n’est pas disponible), eterrors ignored on restore: 8(8 erreurs ignorées lors de la restauration). La table des vecteurs n’est jamais revenue.
Le premier et le troisième cas sont construits, et le cours le précise chaque fois. Ils ne sont pas rares en pratique. Une équipe restaure souvent sur un nouveau serveur ou fait l’exportation pendant que le service fonctionne.
L’idée : une sauvegarde et un exercice de restauration qui la vérifie
Section intitulée « L’idée : une sauvegarde et un exercice de restauration qui la vérifie »Une sauvegarde est une copie des données, conservée à part, qui permet de recréer la base de données. Un exercice de restauration est une restauration d’essai. Vous restaurez la sauvegarde dans une nouvelle base vide et vérifiez que les données récupérées sont complètes. C’est seulement alors que la sauvegarde est vérifiée.
Pour vérifier que les données sont « complètes », l’exercice doit savoir ce que la sauvegarde devrait contenir. Ainsi, scripts/backup.py écrit deux fichiers : l’exportation (pg_dump -Fc, le format compressé de PostgreSQL) et un manifeste. Le manifeste liste les migrations appliquées et, pour chaque table, le nombre de lignes et une somme de contrôle du contenu. Voici une partie d’un vrai manifeste, pour le petit jeu de données :
"sha256": "1deab8057b8d60a693bad2b983380dde6b60428f0dc3761d12f982e82b6abc6a","tables": { "customers": { "rows": 40, "md5": "ddfcc042800ed374de0bca8c04f75b95" }, "tickets": { "rows": 200, "md5": "0dc72e50a0a7a9e2e7673167b1ac5ffc" }, "messages": { "rows": 331, "md5": "e37cb3f89c8ac805536997ad420990a3" },Le nombre de lignes seul peut cacher un changement. Dans le premier échec, tickets avait 200 lignes des deux côtés, mais le message_count d’un billet différait. La somme de contrôle l’a détecté. L’exercice effectue ensuite sept vérifications :
Description textuelle du diagramme
backup.py produit l’exportation avec pg_dump et le manifeste à partir d’un seul instantané de la base. L’exportation du petit jeu de données fait 0,4 Mo. restore_drill.py restaure l’exportation dans une nouvelle base vide et effectue sept vérifications. Premièrement : l’exportation correspond à son manifeste. Deuxièmement : pg_restore a terminé. Troisièmement : les mêmes migrations sont appliquées. Quatrièmement : chaque table contient les mêmes lignes et le même contenu. Cinquièmement : chaque contrainte est valide. Sixièmement : la recherche de billets semblables fonctionne. Septièmement : chaque fichier enregistré se trouve dans le stockage objet, car les fichiers ne sont pas dans l’exportation. Trois échecs réels : un manifeste créé après l’exportation, pendant l’arrivée de messages, échoue à la quatrième vérification. Il y a 331 messages, alors que le manifeste en annonçait 333. Une restauration après un effacement échoue à la septième vérification : 33 fichiers sur 43 trouvés. Un serveur sans pgvector échoue à la deuxième vérification : l’extension vector n’est pas disponible.
L’exercice ne touche jamais à votre base. Il restaure les données dans tickets_restore_drill, puis supprime cette copie, sauf si vous demandez de la garder. Pour le grand jeu de données, l’exportation faisait 53,9 Mo et a pris de 4,5 à 4,7 secondes. pg_restore a pris de 4,6 à 7,9 secondes. Cet exercice a réussi 6 vérifications sur 6. La vérification 7 a été omise, car le grand jeu de données n’a pas de fichiers.
Un seul instantané pour l’exportation et le manifeste
Section intitulée « Un seul instantané pour l’exportation et le manifeste »Le premier échec explique une ligne de backup.py. L’essai construit a écrit l’exportation, puis deux messages sont arrivés, puis le manifeste a été écrit : deux moments, deux images. La restauration correspondait à l’exportation, et le manifeste décrivait une base plus récente.
La solution consiste à décrire le même moment que celui copié par l’exportation. backup.py ouvre une transaction, demande son instantané à PostgreSQL avec pg_export_snapshot(), puis le transmet à pg_dump --snapshot. Il lit ensuite le manifeste dans cette même transaction. Les écritures qui arrivent entre-temps ne figurent dans aucun des deux fichiers, et l’API continue de fonctionner.
Chiffrement : qui d’autre peut lire une sauvegarde
Section intitulée « Chiffrement : qui d’autre peut lire une sauvegarde »Une exportation contient le nom et le courriel de chaque client. Elle est compressée, pas chiffrée, et tout pg_restore peut la lire :
pg_restore --data-only --table customers --file - backups/tickets-20261010-050211.dump | grep -m2 "Olga\|COPY"COPY public.customers (customer_id, name, email, segment, region, joined_on, created_at) FROM stdin;C-0001 Olga Olsen olga.olsen@example.com home north 2024-10-18 2024-10-18 09:42:49+00Protégez donc les données à deux endroits. En transit, entre l’API et une base hébergée, utilisez TLS (sslmode=require ou verify-full dans la chaîne de connexion). Au repos, les services infonuagiques chiffrent leurs disques et leur stockage de blocs binaires par défaut, selon leur documentation. Une exportation que vous copiez ailleurs relève de votre responsabilité. Chiffrez-la, limitez l’accès à quelques personnes et supprimez-la selon le plan de conservation. Sur votre ordinateur, .gitignore exclut déjà backups/ de Git.
Supprimer un client partout
Section intitulée « Supprimer un client partout »Grace pose la question qu’elle avait posée dans le premier module : « Si un client demande de supprimer ses données, pouvons-nous le faire? » Les données d’un client sont maintenant dans trois types d’endroits : lignes dans PostgreSQL, fichiers dans le stockage objet et vecteurs issus de son texte.
PostgreSQL peut supprimer les lignes dans une seule transaction. Les clés étrangères de Contraintes d’intégrité aident : les messages et les vecteurs sont supprimés avec leur billet (CASCADE). Mais le stockage objet ne fait pas partie de la transaction. Le programme doit donc supprimer les fichiers, et l’ordre compte :
- Les fichiers d’abord, puis les lignes. Si le programme plante entre les deux, les lignes pointent vers des fichiers disparus. La page du billet ne fonctionne plus.
- Les lignes d’abord, puis les fichiers. S’il plante entre les deux, les fichiers restent sans ligne qui les référence. Personne ne les retrouvera, et les photos du client restent.
Le projet supprime d’abord les lignes, en conservant une trace du travail restant. Dans la transaction qui supprime les lignes, il écrit les clés des fichiers dans une table, file_deletions. C’est une boîte d’envoi (outbox) : une liste d’actions à effectuer hors de la base, écrite dans la même transaction que le changement. Après le commit (validation), une deuxième étape supprime chaque fichier et marque sa clé comme traitée. Si cette étape s’arrête, la liste reste disponible, et l’étape peut recommencer. Supprimer un fichier déjà disparu ne pose pas problème, car le but est qu’il n’existe plus. La deuxième étape peut donc être répétée sans risque, comme dans Effets de bord et nouvelles tentatives.
Description textuelle du diagramme
L’étape 1 forme une seule transaction dans PostgreSQL. Elle supprime le client C-0028 et ses 19 billets. Les 33 messages et les 19 vecteurs sont supprimés avec leurs billets, grâce à CASCADE. Les 10 lignes de pièces jointes sont supprimées, et leurs clés d’objet sont écrites dans la table de boîte d’envoi file_deletions. Les 31 exécutions d’IA perdent leur texte et leur billet, mais gardent leur coût. La table erasures reçoit une ligne contenant seulement des nombres. Tout est validé, ou rien ne l’est. L’étape 2 suit le commit. Elle supprime chacun des 10 fichiers du stockage objet, par exemple tickets/T-30018/2646ce7c…/photo-1.png, et marque chaque clé comme traitée. Si le programme plante entre les étapes, les lignes ont disparu et les fichiers restent. L’analyse indique alors 10 suppressions en attente, et scan –fix les termine. L’analyse cherche aussi les fichiers orphelins, les fichiers manquants, les anciens téléversements en attente et les vecteurs périmés. Une sauvegarde contient seulement la partie PostgreSQL. Une restauration antérieure à l’effacement ramène les lignes du client sans ses fichiers, et l’exercice trouve 33 fichiers sur 43.
Trois détails de la migration 012 et de scripts/erase_customer.py :
- Les exécutions d’IA gardent leur coût. Les totaux mensuels de Priya doivent rester justes. Les exécutions perdent leur billet et leur texte de sortie, qui peut contenir les mots du client. La migration 012 assouplit un
CHECK: une exécution réussie peut n’avoir aucune sortie si elle n’a aucun billet. - La table
erasuresgarde des nombres, pas des données. Elle note que le client C-0028 a été effacé, quand, et combien de lignes de chaque type. C’est la preuve pour Grace. - Un index accélère l’opération. Pour chaque billet supprimé, PostgreSQL vérifie qu’aucune ligne de pièce jointe ne pointe encore vers lui. Sans index sur
attachments (ticket_id), chaque vérification lit toute la table. Sur le grand jeu de données, effacer le client d’affaires C-3835 (4 322 billets) a pris 7,7 secondes. Avec l’index ajouté par 012, cela a pris 0,39 seconde.
Une suppression arrêtée à mi-chemin et l’analyse
Section intitulée « Une suppression arrêtée à mi-chemin et l’analyse »Que laisse un plantage entre les deux étapes? Le cours a volontairement arrêté le programme à cet endroit avec --crash-after-database (un échec construit) :
Database: deleted 19 tickets, 33 messages, 10 attachment rows, 19 vectors; removed the text of 31 AI runs (their cost stays). 10 files are waiting in file_deletions.Stopped on purpose before the files were deleted (--crash-after-database).Les dix photos et reçus sont encore dans le stockage. Sans vérification, personne ne le remarquerait. Deux termes désignent ce qui peut mal tourner entre deux systèmes de stockage :
- Un fichier orphelin se trouve dans le stockage objet, sans ligne de pièce jointe ni suppression en attente qui le référence. Personne ne peut le trouver depuis la base, et personne ne le supprimera.
- Un vecteur périmé est un vecteur dont le texte du billet a changé après sa création. Son
source_sha256ne correspond plus à la somme de contrôle du texte. Les recherches trouvent alors le billet d’après ses anciens mots.
scripts/scan.py compare les systèmes de stockage et compte chaque problème. Pour tous les montrer, le cours a ajouté deux autres défauts construits : un fichier sans ligne correspondante et un billet modifié manuellement. Il a ensuite lancé l’analyse :
orphan files 1 tickets/T-30005/7c1f0e7a-0000-4000-8000-000000000000/photo-1.pngmissing files 0waiting deletions 10 tickets/T-30018/2646ce7c-9180-4b82-84b6-eb99d6bd4b6e/photo-1.png, tickets/T-30021/380da7d7-c283-4bc6-9524-e6a2fc48780e/receipt-LK-413252.pdf, tickets/T-30021/da92666b-f5fd-472d-bbec-f739c3916847/receipt-LK-413252.pdf ...waiting deletions already gone 0old pending uploads 0embedding version e5-small-v1stale vectors 1 T-30010vectors of other versions 0tickets without current vector 0Chaque ligne représente une comparaison, formulée comme une question :
| Ligne | La question | Comment l’analyse y répond |
|---|---|---|
| orphan files (fichiers orphelins) | Un fichier du stockage est-il absent des lignes et des suppressions en attente? | clés du stockage moins attachments.object_key moins clés en attente |
| missing files (fichiers manquants) | Une ligne enregistrée pointe-t-elle vers un fichier absent? | lignes stored (enregistrées) moins clés du stockage |
| waiting deletions (suppressions en attente) | Une suppression s’est-elle arrêtée à mi-chemin? | lignes de file_deletions non traitées dont le fichier existe encore |
| old pending uploads (anciens téléversements en attente) | Un téléversement commencé il y a plus d’un jour est-il resté inachevé? | attachments avec status = 'pending' et un ancien created_at |
| stale vectors (vecteurs périmés) | Le texte d’un billet a-t-il changé après la création de son vecteur? | source_sha256 comparé au SHA-256 du texte actuel |
scan --fix termine seulement les suppressions en attente. Elles sont sans risque : la base a déjà décidé de supprimer ces fichiers. Le fichier orphelin et le vecteur périmé attendent une intervention humaine. Le fichier orphelin pourrait encore servir à quelqu’un. Pour le vecteur périmé, python -m scripts.embed le recrée avec le modèle.
Conservation : les sauvegardes gardent ce que vous avez effacé
Section intitulée « Conservation : les sauvegardes gardent ce que vous avez effacé »Le deuxième échec de l’exercice s’explique maintenant. La sauvegarde avait été faite avant l’effacement. La restauration a ramené C-0028, Noah Park, avec 19 billets. La trace de l’effacement avait disparu, car elle était plus récente que la sauvegarde. Les fichiers n’ont pas été restaurés, car ils n’avaient jamais été dans la sauvegarde :
FAIL attachment files are in the object storage: 33 of 43 found; missing e.g. tickets/T-30018/2646ce7c-9180-4b82-84b6-eb99d6bd4b6e/photo-1.pngRestore drill: 6 of 7 checks passed.Ici, l’échec est une bonne nouvelle : les fichiers d’un client effacé doivent avoir disparu. Mais les lignes devraient avoir disparu aussi. Un plan de conservation répond à ce problème avec trois règles :
- Gardez chaque sauvegarde pendant une durée fixe, puis supprimez-la, par exemple 30 jours. Les données d’un client effacé disparaissent alors de la dernière sauvegarde dans les 30 jours. Dites-le au client.
- Gardez la liste des effacements hors des sauvegardes, par exemple dans un fichier à côté d’elles. Après toute restauration, effacez de nouveau chaque client dont l’effacement dans la liste est plus récent que la sauvegarde.
- Sauvegardez les fichiers séparément, avec leur propre durée de conservation : gestion des versions d’objets ou copie dans un deuxième conteneur. Une règle de cycle de vie de Modèles de stockage objet peut supprimer les anciennes copies.
Exercice guidé : sauvegarder, restaurer, effacer, analyser
Section intitulée « Exercice guidé : sauvegarder, restaurer, effacer, analyser »-
Copiez les fichiers de cette leçon depuis l’instantané. Sur macOS ou Linux :
Fenêtre de terminal S=../nextia-learning-labs/C20/snapshots/end-of-m05cp $S/migrations/012_erasure.sql migrations/cp $S/scripts/{backup,restore_drill,erase_customer,scan}.py scripts/cp $S/tests/test_recovery.py tests/Sur Windows, avec
$Scomme avant :Copy-Item "$S\migrations\012_erasure.sql" migrations\, puisforeach ($f in "backup","restore_drill","erase_customer","scan") { Copy-Item "$S\scripts\$f.py" scripts\ }, puisCopy-Item "$S\tests\test_recovery.py" tests\. -
Appliquez la migration 012 et lancez les tests :
Fenêtre de terminal python -m ticket_api.migratepython -m pytestLa migration affiche
applied 012_erasure(012_erasure appliquée) etDatabase is up to date (12 migrations).(base de données à jour, 12 migrations). Les tests affichent108 passed, 1 deselected(108 réussis, 1 exclu). Votre projet correspond maintenant àend-of-m05. -
Voyez ce que l’effacement du client C-0003 supprimerait, sans rien supprimer :
Fenêtre de terminal python -m scripts.erase_customer C-0003 --dry-runC-0003 has: tickets 18, messages 27, files 2, vectors 36, ai_runs 2736 vecteurs pour 18 billets de soutien : chaque billet a un vecteur e5 et un vecteur MiniLM. Ils viennent de l’étape facultative de la dernière leçon. Sans cette étape, vous voyez
vectors 18(18 vecteurs). -
Rechargez le petit jeu de données pour obtenir les mêmes nombres que la leçon, puis lancez l’analyse :
Fenêtre de terminal python -m scripts.load --resetpython -m scripts.scanLe chargement se termine par
43 files uploaded to the object storage.(43 fichiers téléversés dans le stockage objet). Chaque décompte de l’analyse est0, et la version du plongement (embedding) este5-small-v1. -
Faites une sauvegarde :
Fenêtre de terminal python -m scripts.backupBackup: backups/tickets-20261010-050211.dump (0.4 MB, 0.1 s)Manifest: backups/tickets-20261010-050211.json: 12 migrations, customers 40, tickets 200, messages 331, attachments 43, documents 36, ai_runs 294, ticket_embeddings 200Not in the backup: the files in object storage. A backup is not proven until a restore works: python -m scripts.restore_drill backups/tickets-20261010-050211.dumpVotre nom de fichier contient votre propre date et heure. Utilisez-le dans les prochaines étapes.
-
Vérifiez la sauvegarde :
Fenêtre de terminal python -m scripts.restore_drill backups/tickets-20261010-050211.dumpPASS dump matches its manifestPASS pg_restore finished: 0.1 sPASS same migrations: 12 of 12PASS same rows and contents in every table: all 7 tablesPASS every constraint is validPASS similar-ticket search works: 5 resultsPASS attachment files are in the object storage: 43 of 43 foundRestore drill: 7 of 7 checks passed. -
Effacez C-0028, le client qui a le plus de fichiers, et arrêtez volontairement après l’étape de la base de données :
Fenêtre de terminal python -m scripts.erase_customer C-0028 --dry-runpython -m scripts.erase_customer C-0028 --crash-after-databaseLa simulation affiche
C-0028 has: tickets 19, messages 33, files 10, vectors 19, ai_runs 31(C-0028 a 19 billets, 33 messages, 10 fichiers, 19 vecteurs et 31 exécutions d’IA). La deuxième commande affiche les deux lignes montrées plus haut et termine parStopped on purpose(arrêt volontaire). -
Lancez l’analyse. Elle trouve
waiting deletions 10(10 suppressions en attente) et termine avec le code de sortie 1. Une tâche planifiée signalerait donc le problème. -
Ajoutez deux erreurs artificielles : un fichier qu’aucune ligne ne référence et une modification manuelle d’un billet. La première commande place 100 octets dans le stockage :
Fenêtre de terminal python -c "from ticket_api.config import load_env, load_settings; from ticket_api.files import make_store; load_env(); make_store(load_settings()).put('tickets/T-30005/7c1f0e7a-0000-4000-8000-000000000000/photo-1.png', b'x' * 100, 'image/png')"Ensuite, dans
psql:UPDATE tickets SET body = body || ' Update: it arrived today.' WHERE ticket_id = 'T-30010';. Relancez l’analyse. Elle affiche le résultat montré plus haut : 1 fichier orphelin, 10 suppressions en attente et 1 vecteur périmé,T-30010. -
Laissez l’analyse terminer les opérations sûres, puis vérifiez de nouveau :
Fenêtre de terminal python -m scripts.scan --fixpython -m scripts.scanLa première commande termine par
fixed finished 10 waiting deletions (10 files deleted)(corrigé : 10 suppressions en attente terminées, 10 fichiers supprimés). La deuxième affichewaiting deletions 0. Le fichier orphelin et le vecteur périmé restent là pour qu’une personne décide quoi faire. -
Restaurez encore la sauvegarde de l’étape 5, maintenant que l’effacement a eu lieu :
Fenêtre de terminal python -m scripts.restore_drill backups/tickets-20261010-050211.dump --keepSix vérifications réussissent, et la vérification 7 échoue avec
33 of 43 found(33 sur 43 trouvés). Danspsql, connectez-vous à la copie conservée avec\c tickets_restore_drill. LancezSELECT customer_id, name FROM customers WHERE customer_id = 'C-0028';: Noah Park est de retour. Revenez avec\c tickets, puis supprimez la copie :DROP DATABASE tickets_restore_drill;. -
Nettoyez avec
python -m scripts.load --reset. L’analyse ne trouve plus de problèmes.
Erreur courante
La restauration s'exécute, mais les vecteurs ne reviennent pas
Symptôme : une restauration sur un nouveau serveur affiche des erreurs et continue. L’exercice de restauration, ou votre propre vérification, ne trouve aucune table ticket_embeddings, et la recherche de billets semblables échoue. Le cours a reproduit ce problème avec une image PostgreSQL 18.6 standard, sans pgvector (un cas artificiel) :
pg_restore: error: could not execute query: ERROR: extension "vector" is not availablepg_restore: error: could not execute query: ERROR: extension "vector" does not existpg_restore: error: could not execute query: ERROR: type "public.vector" does not existpg_restore: error: could not execute query: ERROR: relation "public.ticket_embeddings" does not existpg_restore: warning: errors ignored on restore: 8Cause : une exportation contient CREATE EXTENSION vector, mais pas le programme de l’extension. Le serveur cible doit avoir pgvector installé. pg_restore saute les instructions qui échouent et restaure le reste. La restauration semble donc presque correcte.
Diagnostic : lisez la première erreur, pas la dernière ligne. extension "vector" is not available (l’extension « vector » n’est pas disponible) indique l’élément manquant. La vérification 2 de l’exercice échoue. La vérification 6, la recherche de billets semblables, échoue aussi.
Correction : restaurez sur un serveur avec la même version majeure et les mêmes extensions. Ici, utilisez l’image pgvector/pgvector:0.8.7-pg18-trixie. Inscrivez la version et les extensions du serveur dans le plan de restauration. Faites l’exercice sur le type de serveur que vous utiliseriez pour restaurer.
Exercice du module : un plan de restauration et de suppression
Section intitulée « Exercice du module : un plan de restauration et de suppression »Rédigez un plan de restauration et de suppression d’une page pour votre propre ticket-api. Il contient des clients, des billets, des messages, des exécutions d’IA et des documents dans PostgreSQL. Ses fichiers joints sont dans le stockage objet. Ses vecteurs de billets sont dans pgvector, avec une version de plongement. Répondez à ces questions :
- Que sauvegardez-vous, à quelle fréquence et pour combien de temps? Nommez les données qui n’ont pas besoin d’une sauvegarde distincte et expliquez pourquoi.
- Comment vérifiez-vous une sauvegarde? Nommez les vérifications et le type de serveur pour l’exercice.
- Un client demande à Larkfield de supprimer ses données. Listez tous les endroits où ses données ou leurs copies se trouvent, et l’ordre des étapes.
- Que peut laisser une panne en cours d’opération, et comment le trouvez-vous?
- Que devient un effacement lorsque vous restaurez une sauvegarde plus ancienne que cet effacement?
Pour un deuxième exercice, rédigez le même plan pour l’assistant documentaire de l’exercice du premier module.
Afficher un exemple de réponse
1. Sauvegardes. PostgreSQL : un python -m scripts.backup chaque nuit, avec l’exportation et le manifeste d’un même instantané. Conservez chaque sauvegarde pendant 30 jours, chiffrée, dans un autre compte ou une autre région. Les fichiers joints : gestion des versions d’objets ou copie nocturne dans un deuxième conteneur, également conservée pendant 30 jours. Les vecteurs de billets et l’index HNSW sont des copies du texte des billets. Ils sont déjà dans l’exportation. python -m scripts.embed les recrée à partir du texte avec la version enregistrée.
2. Vérification. Un python -m scripts.restore_drill chaque semaine sur un serveur avec PostgreSQL 18 et pgvector 0.8, l’image pgvector/pgvector:0.8.7-pg18-trixie. Ses sept vérifications : l’exportation correspond à son manifeste, pg_restore ne produit aucune erreur et les migrations sont les mêmes. Les lignes et les sommes de contrôle de chaque table correspondent, les contraintes sont valides et la recherche de billets semblables fonctionne. Chaque fichier stocké se trouve dans le stockage objet. Un exercice qui échoue déclenche une alerte à une personne.
3. Effacement. python -m scripts.erase_customer <id>. Une transaction supprime le client, ses billets, ses messages, ses lignes de pièces jointes et ses vecteurs de toutes les versions. Elle retire le texte de ses exécutions d’IA et conserve le coût. Elle écrit les clés des fichiers dans file_deletions et une ligne avec les décomptes dans erasures. Après le commit (validation de la transaction), le script supprime les fichiers et marque chaque clé comme traitée. Les anciennes sauvegardes contiennent encore les données jusqu’à leur expiration. Le plan indique donc au client : suppression partout dans les 30 jours.
4. Échec partiel. Une panne après le commit laisse des fichiers dont les lignes ont disparu. python -m scripts.scan les affiche comme suppressions en attente, et scan --fix les termine. Un fichier qu’aucune ligne ni suppression en attente ne référence est orphelin. Une personne doit le vérifier. Un billet modifié après la création de son vecteur apparaît comme un vecteur périmé; scripts.embed le recrée. Lancez l’analyse chaque nuit et déclenchez une alerte pour le code de sortie 1.
5. Restauration. Les lignes du client effacé reviennent, sans ses fichiers : l’exercice en a trouvé 33 sur 43. Conservez donc une copie de la liste des effacements en dehors des sauvegardes. Après chaque restauration, relancez erase_customer pour chaque effacement plus récent que la sauvegarde, puis lancez l’analyse.
Vérification du module
Section intitulée « Vérification du module »Vous avez terminé le module 5 quand vous pouvez montrer ces résultats dans votre propre projet :
python -m pytestaffiche108 passed, 1 deselected, etpython -m pytest -m azuriteaffiche1 passed(1 réussi).- Un téléversement par URL signée termine avec
stored(stocké). Un téléversement trop volumineux termine avecrejected(rejeté) et le code 413. python -m scripts.backup, puispython -m scripts.restore_drill backups/<file>.dumpaffichentRestore drill: 7 of 7 checks passed.(exercice de restauration : 7 vérifications sur 7 réussies).- Vérification de fin : expliquez comment détecter les fichiers orphelins et les vecteurs périmés après un échec partiel. Définissez chacun et dites ce que l’analyse compare pour le trouver. Dites ce que
scan --fixfait et ne fait pas. Utilisez comme exemple l’effacement de C-0028 interrompu par une panne.
Réinitialisation. Si votre projet ne fonctionne plus, renommez-le et copiez l’instantané end-of-m05. Conservez votre .env. Dans ~/projects :
mv ticket-api ticket-api-oldcp -R nextia-learning-labs/C20/snapshots/end-of-m05 ticket-apicp ticket-api-old/.env ticket-api/Sur Windows, dans PowerShell, dans ~/projects : Rename-Item ticket-api ticket-api-old, puis Copy-Item -Recurse nextia-learning-labs\C20\snapshots\end-of-m05 ticket-api, puis Copy-Item ticket-api-old\.env ticket-api\. Recréez l’environnement virtuel, lancez docker compose up -d db azurite, puis lancez python -m scripts.load --reset.
Vérification des connaissances
Section intitulée « Vérification des connaissances »Vérifiez votre compréhension
Vérification de fin : après un échec partiel, comment le projet détecte-t-il les fichiers orphelins et les vecteurs périmés? Définissez chacun, dites ce que l'analyse compare et ce que scan --fix en fait.
Afficher la réponse
Un fichier orphelin est un fichier du stockage objet qu’aucune ligne de pièce jointe ni suppression en attente ne référence. L’analyse liste les clés du stockage sous tickets/. Elle retire chaque attachments.object_key et chaque clé de file_deletions qui n’est pas marquée comme traitée. Ce qui reste est orphelin, comme le fichier artificiel tickets/T-30005/7c1f0e7a-…/photo-1.png. Un vecteur périmé est un vecteur créé à partir d’une ancienne version du texte d’un billet. L’analyse compare le source_sha256 de chaque vecteur avec le SHA-256 du sujet et du corps actuels du billet. T-30010 était différent après la modification manuelle. Après l’effacement de C-0028 interrompu par une panne, l’analyse affichait aussi 10 suppressions en attente. scan --fix termine seulement celles-ci, car la base de données a déjà décidé de les supprimer. Il laisse le fichier orphelin à vérifier par une personne et le vecteur périmé à recréer par scripts.embed.
Votre réponse contient-elle les points principaux de la nôtre ?
Connectez-vous et inscrivez-vous au cours pour enregistrer vos réponses. Chaque vérification compte pour le certificat.
Vérifiez votre compréhension
Pourquoi erase_customer supprime-t-il les lignes avant les fichiers, et qu'est-ce qui permet de relancer la deuxième étape sans risque?
Afficher la réponse
Les fichiers et les lignes ne peuvent pas faire partie d’une seule transaction. Si les fichiers étaient supprimés d’abord et que le programme plantait, des lignes pointeraient vers des fichiers disparus. Supprimer les lignes d’abord signifie qu’une panne peut seulement laisser des fichiers derrière. La même transaction écrit leurs clés dans file_deletions, la boîte d’envoi (outbox), pour ne rien oublier. La deuxième étape supprime chaque fichier listé et le marque comme traité. Supprimer un fichier déjà disparu compte comme une réussite. Exécuter l’étape deux fois donne donc le même résultat.
Votre réponse contient-elle les points principaux de la nôtre ?
Connectez-vous et inscrivez-vous au cours pour enregistrer vos réponses. Chaque vérification compte pour le certificat.
Vérifiez votre compréhension
Tomás dit : « On a des sauvegardes chaque nuit, tout va bien. » Donnez-lui trois raisons tirées de cette leçon pour expliquer pourquoi une sauvegarde jamais restaurée ne suffit pas.
Afficher la réponse
Premièrement, la sauvegarde peut différer de ce que vous pensez. Un manifeste écrit juste après l’exportation décrivait 333 messages, mais la restauration en contenait 331. Deuxièmement, la restauration nécessite le bon serveur. Sans pgvector, pg_restore a sauté les vecteurs et signalé errors ignored on restore: 8 (8 erreurs ignorées pendant la restauration). Troisièmement, la sauvegarde contient seulement la base de données. Les fichiers n’y étaient pas (33 sur 43 après un effacement), et un client effacé est revenu avec ses lignes. Seul un exercice de restauration avec des vérifications révèle ces problèmes avant un incident.
Votre réponse contient-elle les points principaux de la nôtre ?
Connectez-vous et inscrivez-vous au cours pour enregistrer vos réponses. Chaque vérification compte pour le certificat.
Récapitulatif
- Une sauvegarde est une exportation et un manifeste provenant d’un même instantané. Un exercice de restauration la restaure dans une base de données vide et lance sept vérifications : 7 sur 7 pour le petit jeu de données.
- Trois échecs réels : un manifeste d’un autre moment (331 contre 333 messages) et un serveur sans pgvector (8 erreurs). Puis une restauration après un effacement : 33 fichiers sur 43, et le client de retour.
- Une exportation est compressée, pas chiffrée. Protégez les sauvegardes et les connexions. Conservez les sauvegardes seulement pour la durée prévue au plan.
- Un effacement supprime les lignes dans une transaction et écrit les clés des fichiers dans une boîte d’envoi, puis supprime les fichiers. Un index a réduit la durée du gros effacement à 0,39 seconde au lieu de 7,7 secondes.
- L’analyse trouve les fichiers orphelins, les fichiers manquants, les suppressions en attente, les anciens téléversements en attente et les vecteurs périmés.
--fixtermine seulement les suppressions en attente. - Votre projet correspond à
end-of-m05, la fin du projet du cours :108 passed, 1 deselected.
Vous avez terminé le module 5 et le projet du cours. Les études de cas du module 6 appliquent les mêmes méthodes à de vraies données ouvertes.
Leçon suivante : Concevoir et optimiser le stockage d'un jeu de données public ouvert