Compatibilitate înainte
Ce este compatibilitatea înainte
Compatibilitatea înainte este capacitatea unui sistem de a lucra corect cu clienți sau date mai noi decât cele pentru care a fost proiectat inițial. Mai simplu: serverul vechi nu se rupe atunci când vine vorba de un client nou; vechiul consumator nu cade atunci când întâlnește un nou mesaj.
Înainte diferă de compatibilitatea înapoi (atunci când noul sistem sprijină clienții vechi) în direcția responsabilității: proiectăm protocoale și clienți în așa fel încât să „supraviețuim” viitoarelor extensii fără o actualizare totală a întregului ecosistem.
Principii de bază
1. Cititor tolerant și scriitor tolerant
Reader ignoră câmpurile/anteturile necunoscute și permite noi valori ale enumului cu rezerva corectă.
Writer nu trimite nimic care serverul nu a declarat în mod explicit ca fiind acceptate (capabilități).
2. Negocierea capacităților
Schimbul explicit de capabilități (caracteristici/versiuni/tipuri media) la etapa strângerii de mână. Clientul își adaptează comportamentul la răspunsul serverului.
3. Degradarea implicită
Noile caracteristici sunt considerate opționale: dacă serverul/consumatorul nu le acceptă, scriptul se va încheia în continuare cu un minim util (MGC).
4. Miez stabil (MGC)
Contractul minim de garantie este neschimbat; inovațiile trăiesc ca extensii.
5. Contracte de eroare ca parte a protocolului
Codurile/motivele predictibile („caracteristică care nu este acceptată”, „tip media necunoscut”) permit clientului să se întoarcă automat la un mod acceptat.
6. Versiuni fără surprize
Linii majore separate; extensiile minore nu necesită o actualizare a serverului/consumatorului.
Unde contează
API-uri publice cu integrări de lungă durată (parteneri, SDK-uri în aplicații mobile).
Platforme de evenimente cu mulți consumatori independenți.
Clienții mobili care se actualizează mai lent decât backend-ul.
Edge/IoT, în cazul în care o parte a flotei de dispozitive este rareori clipit.
Modele de implementare după stil
REST/HTTP
Negociere:- "Acceptați "/tipuri de medii cu parametri (" aplicație/vnd. exemplu. comanda + json; v = 1; profil = risc ').
- 'Prefer: include =... "pentru blocuri opționale.
- Titlul 'X-Capabilities: risk_score,item_details_v2'.
- Trimite o cerere într-un format de bază, extensii - numai dacă serverul are capacitatea confirmată (prin OPȚIUNI/desc/punctul final principal).
- Când „415/406/501” este rulat automat înapoi la un format/metodă acceptată.
- Răspunsul serverului: parametrii necunoscuți - ignorați; câmpurile suplimentare sunt permise; format de eroare stabil ('type/code/detail/trace _ id').
gRPC/Protobuf
Servicii stabile: metode/domenii noi - aditivi; vechiul server ignoră în liniște câmpurile de cerere necunoscute.
Descoperire caracteristică: Metoda 'GetCapabilities ()' returnează liste de caracteristici/limite. Clientul nu apelează metoda v2 decât dacă serverul o declară.
Streaming: fixați ordinea setului minim de mesaje; marcați noi „cadre” cu extensii/tipuri pe care vechiul client le ignoră.
GraphQL
Forward-friendly: noi domenii/tipuri apar pe server - clienții vechi pur și simplu nu le solicită.
Presupunerile sunt interzise: clientul trebuie să păstreze schema (introspecție/codogen) și să nu trimită directive/variabile necunoscute.
Degradare: dacă serverul nu cunoaște directiva personalizată/caracteristică, clientul construiește o cerere fără ea.
Event-driven (Kafka/NATS/Pulsar, Avro/JSON/Proto)
Compatibilitatea ÎNAINTE a schemei în registru: consumatorii vechi pot citi mesajele scrise de noua schemă.
Câmpuri aditive cu defaults: noi producători nu rupe consumatori vechi.
Core vs Îmbogățit: nucleul rămâne același, informațiile noi sunt publicate în '.bogățit' sau ca câmpuri opționale.
Practici de proiectare
1. Contract minim de solicitare (MGC)
Operațiunea ar trebui să aibă un „gât îngust” pe care toate serverele îl vor susține timp de mulți ani.
2. Caracteristică steaguri la nivel de contract
Descrieți caracteristicile ca caracteristici numite: 'risk _ score', 'pricing _ v2', 'strong _ idempotency'. Clientul le include explicit.
3. Coduri de eroare explicite pentru „nu sunt acceptate”
HTTP: '501 Nu este implementat', '415 Tip media nesusţinut', детальные 'problemă + json'.
gRPC: 'UNIMPLEMENTED '/' FAILED _ PRECONDITION'.
Evenimente: traseu în DLQ with 'reason = unsupported _ feature'.
4. Nu vă bazați pe liste de comenzi/complete
Clientul trebuie să fie pregătit pentru noi valori ale enumului, fără câmpuri noi și proprietăți „suplimentare”.
5. Identificatori și formate stabile
Nu modificați formatul tastelor de ID/partiționare în cadrul liniei - acest lucru se rupe înainte pe partea cititorilor.
6. Documentație „ușor de citit”
Descriere gazdă: OpenAPI/AsyncAPI/Proto descriptors/GraphQL SDL. Clienții pot verifica suportul pentru caracteristica.
Testarea compatibilității înainte
Schema-diff în modul FORWARD/FULL: noua schemă validează vechiul consumator/server.
Client Contract Teste: Un nou client este executat împotriva unui server vechi cu caracteristici activate/dezactivate.
Cereri de aur: un set de cereri „noi” este rulat prin serverul „vechi”; degradarea preconizată fără erori critice.
Haos/latență: verificare timeout/retray - noul client trebuie să supraviețuiască corect celor mai rele SLA-uri ale vechiului server.
Canare: unii dintre noii clienți lucrează cu versiunea anterioară a serverului - colectăm telemetria erorilor/degradării.
Observabilitate și valori operaționale
Procentul de cereri/mesaje cu caracteristici neacceptate și rollback-urile lor automate.
Distribuția pe versiuni client (User-Agent/metadate/revendicări).
'Erori și rute neimplementate/501/415' în DLQ cu 'unsupported _ feature'.
Timp de degradare: p95/p99 pentru răspunsul MGC vs „extins”.
Moduri de compatibilitate în registrul schemei
FORWARD: noua intrare este compatibilă cu cititorul vechi (sunt necesare defaulturi, opționalitate).
FULL: и ÎNAINTE, и ÎNAPOI; convenabil pentru contracte de achiziții publice.
Recomandare: pentru evenimente - INAPOI pentru producator si FORWARD pentru consumator (prin intermediul unui cititor tolerant), pentru API-uri externe - FULL.
Exemple
REST (capacități + degradare)
1. Clientul face 'GET/meta/capabilities' → '{"risk _ score": false, "price_v2": true}'.
2. Pe 'POST/orders' trimite câmpuri de bază; 'risk _ score' nu solicită, deoarece serverul nu poate face acest lucru.
3. Dacă este trimis accidental 'Prefer: include = risk _ score', serverul răspunde cu 200 fără câmpul 'risk _ score' (sau 'Preference-Applied: none') - clientul nu se prăbușește.
gRPC (descoperire)
'GetCapabilities ()' returnat lista de metode/caracteristică. Clientul nu apelează 'CaptureV2' dacă nu este prezent - în loc să utilizeze 'Capture' și să convertească local intrarea într-o vizualizare acceptată.
Evenimente (FORWARD în registru)
Producătorul a adăugat câmpul „risk _ score” (nullable with default). Vechiul consumator îl ignoră; logica sa folosește doar câmpuri de nucleu stabile.
Antipatterns
Client dur: filtrează răspunsul prin câmpuri whitelist și cade pe o proprietate necunoscută.
Caracteristici implicite: Clientul începe să trimită un nou parametru fără a verifica capacitățile.
Schimbarea formatelor ID/cheie în cadrul liniei → servere vechi/consumatori nu mai înțeleg noi cereri/mesaje.
Ipoteze hardwired despre lista completă de enum (comutare fără implicit).
Logarea ca control al fluxului: analizarea șirurilor de erori în loc de coduri de contract.
Lista de verificare a implementării
- MGC definit; noile caracteristici sunt marcate ca fiind opționale.
- Negocierea capacității (punctul final/metadate/strângere de mână) este descrisă și implementată.
- Clienții ignoră câmpurile necunoscute și se ocupă corect de noul enum (rezervă).
- Error contractele captura „nu sunt acceptate” previzibil (HTTP/gRPC/Event).
- Registrul schemei este setat la FORWARD/FULL pentru artefactele corespunzătoare.
- Autotesturi: schema-diff (FORWARD), client vs. teste vechi contract de server, canar.
- Metrics: versiune client, eșec caracteristică, rata de degradare, p95 MGC.
- Documentație/SDKs publica o listă de caracteristici și exemple de degradare.
ÎNTREBĂRI FRECVENTE
Cum diferă înainte de înapoi în practică?
Înapoi: noul server nu rupe clienții vechi. Înainte: serverul vechi nu se rupe de clienții noi (sau de vechiul consumator din mesaje noi). În mod ideal, ajungi la plin.
Trebuie întotdeauna să intru în capacități?
Dacă vă așteptați la evoluția activă fără eliberări sincrone, da. E mai ieftin decât să ţii zeci de linii importante.
Ce zici de securitate?
Noile caracteristici ar trebui să necesite scopuri/revendicări separate. Dacă serverul nu le acceptă, clientul nu ar trebui să reducă securitatea, ci ar trebui să abandoneze funcția.
Este posibil să „ghiciți” suportul prin versiunea serverului?
Nedorite. Este mai bine să întrebați explicit (capabilități) sau să vă uitați la tipul/schema media.
Total
Interoperabilitatea înainte este disciplina oportunităților de negociere și degradarea în condiții de siguranță. Un nucleu stabil, negocierea capacităților, extensiile aditive și bug-urile previzibile permit clienților și datelor noi să se înțeleagă cu serverele și consumatorii vechi - fără comunicate în masă și migrații pe timp de noapte.