Registre des schémas et évolution des données
Pourquoi avoir besoin d'un registre de schémas
Le registre des schémas est une source centralisée de vérité pour les contrats de données (API, événements, flux, messages, stockage) qui fournit :- Évolution prévisible : règles de compatibilité et vérification automatique des « cassures ».
- Répétabilité et transparence : historique des versions, qui/quand/pourquoi a changé.
- Standardisation : noms uniques, formats d'erreur, champs de trace, étiquettes PII.
- Intégration avec CI/CD : verrouillage des modifications de rupture avant la production.
Le registre lie Protocol-first et l'interopérabilité contractuelle, rendant les changements rapides et sécurisés.
Formats et domaines d'application
JSON Schema : REST/HTTP charges utiles, documents, configurations.
Avro : pneus événements (Kafka/Pulsar), compact/evolution via ID de champs.
Protobuf : gRPC/RPC, efficace binaire, étiquettes strictes.
GraphQL SDL : schéma des types et directives, évolution via '@ deprecated'.
SQL DDL en tant qu'artefact : nous fixons les vues négociées (par exemple, les vitrines externes) - avec prudence.
Modes de compatibilité
BACKWARD : les nouveaux schémas lisent les anciennes données/messages. Convient au producteur qui étend payload additivement.
FORWARD : les anciens consommateurs lisent correctement les nouvelles données (nécessite un lecteur tolérant).
FULL : combine les deux (plus strict, plus pratique pour les marchés publics).
NONE : aucun contrôle - uniquement pour les bacs à sable.
- Événements : plus souvent BACKWARD (le producteur étend payload en option).
- API publiques : FULL ou BACKWARD + lecteur tolérant strict sur les clients.
- Prototypes internes : Temporairement NONE, mais pas sur trunk.
Sécurité (additif) vs. changements dangereux
Additif (OK) :- Ajoute un champ/type facultatif.
- Extension enum avec de nouvelles valeurs (avec tolérant reader).
- Ajoute une autre projection/événement ('.enriched').
- Assouplissement des contraintes ('minLength', 'maximum' ↑ mais pas ↓).
- Supprimer/renommer les champs ou modifier leur type/obligation.
- Modification de la sémantique des statuts/codecs/ordre dans les flux.
- Réutilisation des étiquettes protobuf.
- Change la clé de lot dans les événements.
Organisation du registre
Neuming et adressage
Groupes/espaces : 'payments', 'kyc', 'audit'.
Noms : 'payment. authorized. v1` (events), `payments. v1. CaptureRequest` (gRPC), `orders. v1. Order` (JSON Schema).
Majeur dans le nom, mineur - dans les métadonnées/version du schéma.
Métadonnées
'owner' (commande), 'domain', 'slas' (SLO/SLA), 'security. tier` (PII/PCI), `retention`, `compatibility_mode`, `sunset`, `changelog`.
Gestion du cycle de vie
Draft → Review → Approved → Released → Deprecated → Sunset.
Validateurs/linters automatiques, conception-révision manuelle (API Guild), release notes.
Intégration dans CI/CD
1. Pré-commit : linters locaux (Spectral/Buf/Avro tools).
2. PR-pipline : schema-diff → vérification de la compatibilité en mode ; on bloque le breaking.
3. Artifact publish : push schéma convenu dans le registre + génération SDK/modèles.
4. Runtime-guard (facultatif) : La passerelle/productrice valide payload contre le schéma actuel.
- `openapi-diff --fail-on-breaking`
- `buf breaking --against
` - `avro-compat --mode BACKWARD`
- génération de samples d'or et exécution de tests CDC.
Évolution des schémas : pratiques
Additive-first: новые поля — `optional/nullable` (JSON), `optional` (proto3), default в Avro.
Le modèle de la pyramide inverse : le noyau est stable, l'enrichissement est proche et facultatif.
Dual-emit/dual-write pour major : nous publions « v1 » et « v2 » en parallèle.
Sunset-plan : dates, utilisation, avertissements, adaptateurs.
Lecteur Tolérant : les clients ignorent les champs inconnus et gèrent correctement les nouveaux enum.
Exemples de schémas et de contrôles
JSON Schema (fragment, champ additif)
json
{
"$id": "orders.v1.Order",
"type": "object",
"required": ["id", "status"],
"properties": {
"id": { "type": "string", "format": "uuid" },
"status": { "type": "string", "enum": ["created", "paid", "shipped"] },
"risk_score": { "type": "number", "minimum": 0, "maximum": 1 }
},
"additionalProperties": true
}
Avro (par défaut pour la compatibilité)
json
{
"type": "record",
"name": "PaymentAuthorized",
"namespace": "payment.v1",
"fields": [
{ "name": "payment_id", "type": "string" },
{ "name": "amount", "type": "long" },
{ "name": "currency", "type": "string" },
{ "name": "risk_score", "type": ["null", "double"], "default": null }
]
}
Protobuf (n'utilisez pas trop de balises)
proto syntax = "proto3";
package payments.v1;
message CaptureRequest {
string payment_id = 1;
int64 amount = 2;
string currency = 3;
optional double risk_score = 4; // additive
}
// tag=4 зарезервирован под risk_score, его нельзя менять/удалять без v2
Registre des événements et répartition
Nommage des événements : 'domain. action. v{major}` (`payment. captured. v1`).
La clé de lot fait partie du contrat ('payment _ id', 'user _ id').
Core vs Enriched : '.v1' (noyau) et '.enriched. v1 '(détails).
Compatibilité dans le registre : modes au niveau du sujet/type ; CI refuse les modifications incompatibles.
Gestion des migrations
Expand → Migrate → Contract (REST/gRPC):1. ajouter des champs/tables ; 2) commencer à écrire/lire de nouveaux champs ; 3) supprimer l'ancien après sunset.
- Dual-emit (Events) : parallèle à 'v1 '/' v2', migration consumers/projections, puis retrait de 'v1'.
- Replay : recalculer les projections de la loge vers le nouveau schéma (uniquement avec la compatibilité et les migreurs).
- Adaptateurs : gateway/proxy traduisant 'v1↔v2' pour les clients complexes.
Sécurité et conformité
PII/PCI de l'étiquette dans le schéma : 'x-pii : true', 'x-sensibility : high'.
Politiques d'accès : qui peut publier/modifier des schémas (RBAC), signer des versions.
Cryptographie : signature des versions des schémas, journaux d'audit immuables (WORM).
Droit à l'oubli : spécifiez les champs nécessitant un chiffrement/un chiffrement ; guidance dans le registre.
Observation et audit
Dashboards : nombre de changements, types (mineur/majeur), proportion de RP rejetés, utilisation des versions.
Audit-trail : qui a modifié le schéma, liens vers PR/ADR, version associée.
Runtime-métriques : pourcentage de messages qui n'ont pas été validés ; incidents de compatibilité.
Outils (pile approximative)
OpenAPI/JSON Schema: Spectral, OpenAPI Diff, Schemathesis.
Protobuf/gRPC: Buf, buf-breaking, protoc linters.
Avro/Events: Confluent/Redpanda Schema Registry, Avro-tools, Karapace.
GraphQL: GraphQL Inspector, GraphQL Codegen.
Registres/catalogues : Artifact Registry, Git-based registry, Backstage Catalogue, custom UI.
Documentation : Redocly/Stoplight, Swagger-UI, GraphiQL.
Anti-modèles
Swagger-wash : le schéma ne reflète pas la réalité du service (ou vice versa).
Vérification de compatibilité désactivée : « urgent » → la faille se brise.
Réutilisation des étiquettes protobuf : corruption silencieuse des données.
Un seul mode de compatibilité « pour tout » : différents domaines nécessitent différents modes.
Les CDC bruts comme schémas publics : fuite du modèle OBD vers l'extérieur, impossibilité d'évolution.
Chèque de mise en œuvre
- Le format des artefacts et le mode de compatibilité par domaine ont été définis.
- Les linters et schema-diff sont configurés dans CI, PR est bloqué lors du breaking.
- Inclus dans le lecteur tolérant chez les clients ; 'additionalProperties = true' (le cas échéant).
- Les changements majeurs passent par RFC/ADR, il y a un plan sunset et dual-emit/dual-write.
- Les schémas sont marqués PII/PCI et les niveaux d'accès ; un audit est inclus.
- Dashboards sur l'utilisation des versions et les défauts de compatibilité.
- La génération de SDK/modèles à partir du registre fait partie de la pipline.
- Documentation et samples d'or mis à jour automatiquement.
FAQ
Est-il possible de stocker des schémas dans Git sans registre ?
Oui, mais le registre ajoute l'API de compatibilité, la recherche, les métadonnées, la politique centralisée et la validation « on-the-fly ». La meilleure option est Git comme storage + UI/stratégies en plus.
Comment choisir le mode de compatibilité ?
Regardez la direction du changement : si le producteur étend payload - BACKWARD. Pour l'API/SDK public - FULL. Pour les prototypes rapides - temporairement NONE (pas sur trunk).
Que faire en cas de besoin ?
Nous préparons v2 : dual-emit/dual-run, sunset-days, adaptateurs, télémétrie d'utilisation, hydes de migration.
Dois-je valider payload dans rantime ?
Pour les domaines critiques - oui : cela empêche les messages « poubelle » et accélère le diagnostic.
Total
Le registre des schémas transforme l'évolution des données de l'improvisation risquée en un processus contrôlé : règles d'interopérabilité uniques, vérifications automatiques, versions compréhensibles et historique transparent. Ajoutez à cela la discipline additive-first, tolérant reader, dual-emit et sunset - et vos contrats évolueront rapidement, sans cassures ni incidents nocturnes.