Abwärtskompatibilität
Was ist Abwärtskompatibilität
Abwärtskompatibilität (backward compatibility) - die Eigenschaft des Systems, alte Kunden/Verbraucher zu akzeptieren und korrekt zu behandeln, wenn das System aktualisiert wird. Einfacher: Sie veröffentlichen eine neue Version des Service/Events und bereits bestehende Integrationen funktionieren unverändert weiter.
Der Schlüssel: Vereinbarungen nicht brechen. Jede Evolution ist durch das Hinzufügen, nicht die Überarbeitung eines bereits veröffentlichten.
Grundlagen
1. Additive-first
Neue Felder/Methoden/Ereignisse werden optional hinzugefügt. Nichts Existierendes wird entfernt oder verändert die Bedeutung.
2. Mindestgarantievertrag (MGC)
Definieren Sie den Kern - eine Reihe von Feldern/Operationen, ohne die das Szenario seine Bedeutung verliert. Der Kern ist stabil. Alles andere sind Erweiterungen.
3. Tolerant reader
Die Clients ignorieren unbekannte Felder und verarbeiten neue Enum-Werte (Fallback) korrekt.
4. Versionsrichtlinie
Brechende Änderungen - nur über die Hauptleitung ('/v2', 'payments. v2`, `event. v2`). Minor ist additiv.
5. Beobachtbarkeit ist Teil des Vertrages
In Logs/Traces und Metriken sind die Client-Version, das Format und die Capability-Flags sichtbar. Damit kann die Migration gesteuert werden.
Sichere vs gefährliche Änderungen
Normalerweise sicher (BC-OK)
Optionale Felder hinzufügen (JSON/Avro/Protobuf „optional “/„ nullbar“).
Hinzufügen neuer Endpunkte/Methoden/Ereignisse.
enum um zusätzliche Werte erweitern (bei tolerantem Reader).
Abschwächung der Validierung (Erhöhung der Maxima, Hinzufügen alternativer Formate).
Hinzufügen von Titeln/Metadaten, die keinen Einfluss auf die Bedeutung haben.
Gefährlich (Breaking)
Löschen/Umbenennen von Feldern, Ändern des Typs oder der Verbindlichkeit vorhandener Felder.
Änderung der Semantik von Fehlerstatus/Codes.
Neuverwendung von Protobuf-Tags für andere Felder.
Ändern Sie den Partitionierungsschlüssel des Ereignisses (bricht die Reihenfolge für die Einheit).
Verschärfung von SLAs/Timeouts, wodurch alte Kunden zu fallen beginnen.
Interaktionsstile
REST/HTTP + JSON
Additivität: Die neuen Felder sind 'optional', der Server benötigt sie nicht von den alten Clients.
Versionen: major - unterwegs ('/v2') oder Mediatyp; minor - durch Erweiterungen und'? include = '/'? fields ='.
Fehler: einheitliches Format; Ändern Sie die Codes/Semantik nicht ohne Major.
ETag/If-Match: für sichere Upgrades ohne Rennen.
Idempotenz: 'Idempotency-Key' für POST - alte Kunden „verdoppeln“ den Effekt nicht beim Retracement.
gRPC / Protobuf
Die Tags sind unverändert. Gelöschte Tags können nicht erneut verwendet werden.
Die neuen Felder sind 'optional '/' wiederholt'; Die Standardwerte werden vom alten Code korrekt verarbeitet.
Streaming: Ändern Sie nicht die Reihenfolge/Verbindlichkeit der Nachrichten innerhalb von minor.
Fehler - ein stabiler Satz von Status; Neue Semantik → neue Methode/Dienst („.v2“).
Event-driven (Kafka/NATS/Pulsar) + Avro/JSON/Proto
Benennung: 'Domäne. action. v{major}`.
Core vs Enriched: Der Kern ist stabil; Anreicherung - einzelne Typen/Themen („.enriched“).
Schema-Kompatibilitätsmodus: häufiger BACKWARD; CI blockiert inkompatible Änderungen.
Partitionierung: Schlüssel (z.B. 'payment _ id') - Teil des Vertrages; ändern Sie es - brechen.
GraphQL
Hinzufügen von Feldern/Typen - OK; Löschen/Umbenennen - über'@ deprecated 'und das Migrationsfenster.
Erhöhen Sie nicht „nullbar → nicht-nullbar“ ohne Major.
Kontrolle complexity/depth - Limits ändern = Vertrag ändern.
Muster zur Erhaltung von BC
Umgekehrtes Pyramidenmodell: Kern stabilisieren, optional erweitern.
Capability negotiation: Der Client meldet die unterstützten Fähigkeiten ('X-Capabilities '/handshake), der Server passt sich an.
Dual-Run/Dual-Emit: Halten Sie für die Dauer der Migration gleichzeitig 'v1' und 'v2'.
Adapter: Proxy/Gateway übersetzen 'v1↔v2' Anfragen für „schwere“ Clients.
Expand-and-contract (für DB): Zuerst Neues hinzufügen, mit dem Schreiben/Lesen beginnen, erst dann das Alte löschen.
Governance und Prozess
1. Vertragsverzeichnis (Scheme Registry): eine einzige Quelle der Wahrheit mit Kompatibilitätsrichtlinien.
2. Linters und Diff-Checks in CI/CD: OpenAPI-diff, Buf-breaking, Avro/JSON Schema Kompatibilitätsprüfung.
3. CDC/Consumer-Driven Contracts: Der Anbieter wird auf reale Verbraucherverträge geprüft.
4. Goldene Beispiele: Referenzanfragen/-antworten/-ereignisse für den Regress.
5. Change Management: RFC/ADR auf Breaking, Sunset Pläne, Kommunikation.
Deprecate und Entfernung alter Versionen
Markieren Sie veraltet ('@ deprecated', Beschreibungen, Überschriften 'Deprecation', 'Sunset').
Migrationsfenster: Vorab angekündigtes Datum, Prüfstand, Codebeispiele.
Telemetrie-Nutzung: Wer ist noch auf 'v1'? Metriken/Protokolle nach Version segmentieren.
Dual-Run auf null Verkehr, dann - Entfernung.
Beobachtbarkeit und Betriebskennzahlen
Prozentsatz der Anfragen/Nachrichten nach Version.
Anteil der Fehler/Timeouts bei Altkunden nach Release.
Anteil inkompatibler Payload (Validierung durch Schema auf Gateway/Stream-Filter).
Die Verzögerung der Verbrauchermigration (wie viele hören noch „v1“).
Testen der Abwärtskompatibilität
Schema-diff: fail при remove/rename/type-change.
Vertragstests: Alte SDKs/Kunden rennen gegen die neue Implementierung.
E2E-Kanarienvogel: Teil des alten Verkehrs zur neuen Version, Vergleich p95/p99, Codes, Retrays.
Replikate von Ereignissen: Projektionen werden von der neuen Logik aus dem alten Protokoll ohne Diskrepanzen gesammelt.
Fault-Injection: Verzögerungen/Teilantworten - alte Kunden fallen nicht.
Beispiele
REST (additiv)
Es gab:json
{ "id": "p1", "status": "authorized" }
Es wurde:
json
{ "id": "p1", "status": "authorized", "risk_score": 0. 12 }
Alte Kunden, die' risk _ score' ignorieren, arbeiten weiter.
Protobuf (Tags)
proto message Payment {
string id = 1;
string status = 2;
optional double risk_score = 3 ;//new field, safe
}
//Tags 1 and 2 cannot be changed/deleted without v2
Ereignisse (Kernel + Anreicherung)
`payment. authorized. v1 'ist der Kern (Minimum an Fakten).
`payment. enriched. v1'- Teile; Kernverbraucher sind nicht auf Anreicherungen angewiesen.
Anti-Pattern
Swagger-wash: Das Schema wurde aktualisiert, aber der Dienst verhält sich wie zuvor (oder umgekehrt).
Versteckte Brüche: Veränderte Bedeutung des Feldes/Status ohne Version.
Überverwendung von Protobuf-Tags: „stille“ Datenkorruption.
Harte Kunden: fallen auf ungewohnte Felder/enum; kein toleranter Leser.
Mega-Endpoint: ein All-in-One - jede Änderung wird zu einem potenziellen Bruch.
Checkliste vor der Veröffentlichung
- Die Änderungen sind additiv; Kernel (MGC) nicht berührt.
- Linters/Diff Checks bestanden; Es gibt keine Breaking-Flags.
- Client-SDKs wurden aktualisiert (oder sind für die additive Erweiterung nicht erforderlich).
- Toleranter Reader bei Kunden aktiviert; enum-fallback geprüft.
- Metriken/Logs enthalten Versions- und Capability-Flags.
- Es gibt '/v2', Dual-Run und einen Sunset-Plan für einen möglichen Abbruch.
- Dokumentation/Beispiele aktualisiert, es gibt Golden-Sets.
FAQ
Backward vs forward - was ist der Unterschied?
Backward - Neue Server arbeiten mit alten Clients. Vorwärts - neue Clients arbeiten korrekt mit alten Servern (aufgrund eines toleranten Readers und ordentlicher Standardwerte). Der komplette Kreis ist voll kompatibel.
Muss ich bei großen Änderungen immer '/v2 'machen?
Ja, wenn Invarianten/Typen/Schlüssel/Semantik brechen. Ansonsten - halten Sie die Linie und entwickeln Sie sich additiv.
Was ist mit enum?
Fügen Sie neue Werte hinzu, ohne die Bedeutung der alten zu ändern. Kunden müssen bei unbekanntem Wert einen Fallback haben.
Was tun, wenn man schon „kaputt“ ist?
Rollback, Hot-Fix Adapter, Release' v2 'mit Dual-Run, Kommunikation und Migrationshyde.
Summe
Abwärtskompatibilität ist die Disziplin der Evolution: Stabilisieren Sie den Kern, erweitern Sie additiv, implementieren Sie einen toleranten Reader, automatisieren Sie Inspektionen und führen Sie eine bewusste Deprecate durch. Auf diese Weise können Sie die Plattform schnell entwickeln, ohne dass Kunden unter den Trümmern „unauffälliger“ Änderungen bleiben.