Contratti, indirizzamento e API per i microservizi

ID regione

REGION_ID è un codice abbreviato assegnato da Google in base alla regione selezionata quando crei l'app. Il codice non corrisponde a un paese o a una provincia, anche se alcuni ID regione possono sembrare simili ai codici di paesi e province di uso comune. Per le app create dopo febbraio 2020, REGION_ID.r è incluso negli URL di App Engine. Per le app esistenti create prima di questa data, l'ID regione è facoltativo nell'URL.

Scopri di più sugli ID regione.

In genere, i microservizi su App Engine si richiamano a vicenda utilizzando API RESTful basate su HTTP. È anche possibile invocare i microservizi in background utilizzando le code di attività e si applicano i principi di progettazione delle API descritti qui. È importante di seguire determinati pattern per garantire che l'applicazione basata su microservizi è stabile, sicuro e funziona bene.

Utilizzo di contratti solidi

Uno degli aspetti più importanti delle applicazioni basate su microservizi è di eseguire il deployment dei microservizi in maniera totalmente indipendente l'uno dall'altro. Per ottenere questa indipendenza, ciascun microservizio deve fornire un contratto ben definito e sottoposto al controllo delle versioni ai propri client, che sono altri microservizi. I singoli servizi non devono interrompere questi contratti sottoposti al controllo delle versioni finché non viene appurato che nessuna un altro microservizio si basa su un particolare contratto sottoposto al controllo delle versioni. Tieni presente che altri microservizi potrebbero dover eseguire il rollback a una versione precedente del codice che richiede un contratto precedente, per cui è importante tenerne conto nei criteri di deprecazione e disattivazione.

Probabilmente, l'aspetto organizzativo più complesso di un'applicazione stabile basata sui microservizi è la creazione di una cultura incentrata su contratti solidi e sottoposti al controllo delle versioni. I team di sviluppo devono comprendere la differenza tra una modifica che provoca un errore e una modifica non dannosa. Devono sapere quando è necessaria una nuova release principale. Devono capire come e quando un vecchio contratto può essere ritirato. I team devono utilizzare tecniche di comunicazione appropriate, tra cui comunicazioni relative al ritiro e al ritiro, per garantire la consapevolezza delle modifiche ai contratti dei microservizi. Per quanto possa sembrare scoraggiante, integrare queste pratiche in la cultura dello sviluppo produrrà grandi miglioramenti in termini di velocità e qualità nel tempo.

Gestione dei microservizi

I servizi e le versioni del codice possono essere indirizzati direttamente. Di conseguenza, puoi eseguire il deployment delle nuove versioni di codice affiancate a quelle esistenti e puoi testare il nuovo codice prima di impostarlo come versione di pubblicazione predefinita.

Ogni progetto App Engine ha un servizio predefinito e ogni servizio ha un codice predefinito. completamente gestita. Per accedere al servizio predefinito della versione predefinita di un progetto, utilizza il seguente URL:
https://PROJECT_ID.REGION_ID.r.appspot.com

Se esegui il deployment di un servizio denominato user-service, puoi accedere alla pubblicazione predefinita del servizio tramite il seguente URL:

https://user-service-dot-my-app.REGION_ID.r.appspot.com

Se esegui il deployment di una seconda versione di codice non predefinita denominata banana nel servizio user-service, puoi accedere direttamente a questa versione di codice utilizzando il seguente URL:

https://banana-dot-user-service-dot-my-app.REGION_ID.r.appspot.com

Tieni presente che se esegui il deployment di una seconda versione di codice non predefinita denominata cherry nel servizio default, puoi accedere a questa versione di codice utilizzando il seguente URL:

https://cherry-dot-my-app.REGION_ID.r.appspot.com

App Engine applica la regola che stabilisce che i nomi delle versioni del codice non è in conflitto con i nomi dei servizi.

L'indirizzamento diretto di versioni di codice specifiche deve essere utilizzato solo per i test di fumosità e per facilitare i test A/B, l'applicazione e il rollback. Il codice client deve invece indirizzare solo la versione predefinita in esecuzione del servizio predefinito o di un servizio specifico:


https://PROJECT_ID.REGION_ID.r.appspot.com

https://SERVICE_ID-dot-PROJECT_ID.REGION_ID.r.appspot.com

Questo stile di indirizzamento consente ai microservizi di eseguire il deployment di nuove versioni dei loro servizi, incluse correzioni di bug, senza richiedere alcuna modifica ai clienti.

Utilizzo delle versioni API

Ogni API di microservizio deve avere una versione principale dell'API nell'URL, ad esempio:

/user-service/v1/

Questa versione principale dell'API identifica chiaramente nei log la versione viene chiamato. Ma soprattutto, la versione principale dell'API produce diversi URL, in modo che le nuove versioni principali delle API possano essere pubblicate affiancate versioni principali dell'API precedente:

/user-service/v1/
/user-service/v2/

Non è necessario includere nell'URL la versione secondaria dell'API perché l'API secondaria per definizione non introdurranno modifiche che provocano un errore. Infatti, l'inclusione della versione secondaria dell'API nell'URL provocherebbe una proliferazione di e creano incertezza sulla capacità di un cliente di passare a un nuovo minorenne Versione API.

Tieni presente che questo articolo presuppone un ambiente di integrazione e distribuzione continua in cui il ramo principale viene sempre eseguito in App Engine. In questo articolo sono presenti due concetti distinti di versione:

  • Versione del codice, che è mappato direttamente a una versione del servizio App Engine e rappresenta un un particolare tag commit del ramo principale.

  • versione API, che è mappato direttamente all'URL di un'API e rappresenta la forma gli argomenti della richiesta, la forma del documento di risposta, e il comportamento dell'API.

Questo articolo presuppone anche che il deployment di un singolo codice implementerà sia i vecchi e le nuove versioni di un'API in una versione di codice comune. Ad esempio, di cui è stato eseguito il deployment nel ramo principale potrebbe implementare sia /user-service/v1/ /user-service/v2/. Quando implementi nuove versioni minori e patch, questo approccio ti consente di suddividere il traffico tra due versioni di codice indipendentemente dalle versioni dell'API effettivamente implementate dal codice.

La tua organizzazione può scegliere di sviluppare /user-service/v1/ e /user-service/v2/ su rami di codice diversi, ovvero nessun deployment di codice implementerà entrambi contemporaneamente. Questo modello è possibile anche su App Engine, ma per suddividere il traffico devi spostare la versione principale dell'API nel nome del servizio stesso. Ad esempio, i tuoi clienti potrebbero utilizzare i seguenti URL:

http://user-service-v1.my-app.REGION_ID.r.appspot.com/user-service/v1/
http://user-service-v2.my-app.REGION_IDappspot.com/user-service/v2/

La versione principale dell'API viene inserita nel nome del servizio stesso, ad esempio user-service-v1 e user-service-v2. (le parti /v1/, /v2/ del sono ridondanti in questo modello potrebbe essere rimosso, anche se possono comunque essere utili nell'analisi dei log.) Questo modello richiede un po' più di lavoro perché probabilmente richiede agli script di deployment per eseguire il deployment di nuovi servizi modifiche principali alla versione API. Inoltre, tieni presente il numero massimo di servizi consentiti per applicazione App Engine.

Modifiche che provocano e non interrompono

È importante capire la differenza tra una modifica che provoca un errore e una un cambiamento costante. Le modifiche che comportano una rottura sono spesso di tipo sottrattivo, ovvero rimuovono parte del documento di richiesta o risposta. La modifica della forma del documento o del nome delle chiavi può comportare una modifica che comporta l'interruzione del servizio. Nuovi gli argomenti richiesti interrompono sempre le modifiche. Possono verificarsi anche modifiche che provocano un errore se cambia il comportamento del microservizio.

Le modifiche non invasive tendono ad essere additive. Un nuovo argomento facoltativo della richiesta o una nuova sezione aggiuntiva nel documento di risposta sono modifiche non invasive. Al fine di ottenere cambiamenti costanti, la scelta la serializzazione on-the-wire è essenziale. Molte serializzazioni sono compatibili con le modifiche non invasive: JSON, Protocol Buffers o Thrift. Una volta deserializzata, queste serializzazioni ignorano silenziosamente informazioni aggiuntive e inaspettate. Nelle lingue dinamiche, le informazioni aggiuntive vengono visualizzate semplicemente nell'oggetto deserializzato.

Prendi in considerazione la seguente definizione JSON per il servizio /user-service/v1/:

{
  "userId": "UID-123",
  "firstName": "Jake",
  "lastName": "Cole",
  "username": "jcole@example.com"
}

La seguente modifica che provoca un errore richiede il ripristino delle versioni del servizio /user-service/v2/:

{
  "userId": "UID-123",
  "name": "Jake Cole",  # combined fields
  "email": "jcole@example.com"  # key change
}

Tuttavia, la seguente modifica non invasiva non richiede una nuova versione:

{
  "userId": "UID-123",
  "firstName": "Jake",
  "lastName": "Cole",
  "username": "jcole@example.com",
  "company": "Acme Corp."  # new key
}

Eseguire il deployment di nuove versioni minori dell'API non incompatibili

Durante il deployment di una nuova versione secondaria dell'API, App Engine consente il nuovo codice una versione affiancata alla vecchia versione del codice. In App Engine, sebbene sia possibile gestire direttamente qualsiasi versione di cui è stato eseguito il deployment, solo una versione è la versione di pubblicazione predefinita, ricorda che esiste una versione di pubblicazione predefinita per ogni servizio. In questo esempio, abbiamo la vecchia versione del codice, denominata apple, che è la versione di pubblicazione predefinita, e implementiamo la nuova versione del codice come versione affiancata, denominata banana. Tieni presente che gli URL dei microservizi per entrambi sono gli stessi /user-service/v1/ poiché stiamo eseguendo il deployment di una modifica minore non invasiva dell'API.

App Engine fornisce meccanismi per eseguire automaticamente la migrazione del traffico da apple a banana contrassegnando la nuova versione del codice banana come pubblicazione predefinita completamente gestita. Quando viene impostata la nuova versione di pubblicazione predefinita, nessuna nuova richiesta verrà indirizzata a apple e tutte le nuove richieste verranno indirizzate a banana. In questo modo, puoi eseguire il passaggio a una nuova versione di codice che implementa una nuova versione dell'API secondaria o di patch senza alcun impatto sui microservizi client.

In caso di errore, il rollback viene eseguito invertendo la procedura precedente: reimposta la versione di pubblicazione predefinita su quella precedente, apple nel nostro esempio. Tutte le nuove richieste torneranno alla versione precedente del codice e non a nuove verranno indirizzate a banana. Tieni presente che le richieste in corso possono essere completate.

App Engine offre anche la possibilità di indirizzare solo una determinata percentuale di traffico alla nuova versione del codice. Questa procedura è spesso chiamata procedura di rilascio canary e il meccanismo è chiamato suddivisione del traffico in App Engine. Puoi indirizzare l'1%, il 10%, il 50% o qualsiasi percentuale di traffico che preferisci alle nuove versioni del codice e puoi modificare questo importo nel tempo. Ad esempio, puoi implementare la nuova versione del codice nell'arco di 15 minuti, aumentando lentamente il traffico e controllando la presenza di eventuali problemi che potrebbero indicare la necessità di un rollback. Lo stesso meccanismo ti consente di eseguire test A/B su due versioni di codice: imposta la suddivisione del traffico al 50% e confronta le caratteristiche di rendimento e di tasso di errore delle due versioni di codice per confermare i miglioramenti previsti.

L'immagine seguente mostra le impostazioni di suddivisione del traffico nella console Google Cloud:

Impostazioni di suddivisione del traffico nella console Google Cloud

Deployment di nuove versioni principali delle API

Quando esegui il deployment di versioni principali dell'API che non sono compatibili con le versioni precedenti, la procedura di applicazione e di rollback è la stessa delle versioni secondarie dell'API compatibili con le versioni precedenti. Tuttavia, solitamente non esegui suddivisioni del traffico o test A/B perché la versione dell'API che causa interruzioni è un URL appena rilasciato, ad esempio/user-service/v2/. Ovviamente, se hai modificato la struttura della vecchia versione principale dell'API, puoi continuare a utilizzare suddivisione del traffico per testare che la vecchia versione principale dell'API continua a funzionino come previsto.

Quando esegui il deployment di una nuova versione principale dell'API, è importante ricordare che potrebbero essere ancora in esecuzione anche le vecchie versioni principali dell'API. Ad esempio, /user-service/v1/ potrebbe essere ancora pubblicato quando viene rilasciato /user-service/v2/. Questo fatto è un elemento essenziale delle release di codice indipendenti. Potresti disattivare le vecchie versioni principali dell'API solo dopo aver verificato che nessun altro microservizio le richieda, inclusi altri microservizi che potrebbero dover eseguire il rollback a una versione precedente del codice.

Come esempio concreto, immagina di avere un microservizio chiamato web-app, che dipende da un altro microservizio, denominato user-service. Immagina user-service deve modificare alcune implementazioni sottostanti che impossibile supportare la vecchia versione principale dell'API web-app sta attualmente utilizzando, ad esempio la compressione di firstName e lastName in un unico campo denominato name. Vale a dire che user-service deve disattivare una versione principale precedente dell'API.

Per apportare questa modifica, è necessario eseguire tre implementazioni distinte:

  • Innanzitutto, user-service deve eseguire il deployment di /user-service/v2/ continuando a supportare /user-service/v1/. Questo deployment può richiedere la scritta per supportare la compatibilità con le versioni precedenti, una conseguenza comune di applicazioni basate su microservizi

  • Successivamente, web-app deve eseguire il deployment del codice aggiornato che modifica la sua dipendenza da Da /user-service/v1/ a /user-service/v2/

  • Infine, dopo che il team di user-service avrà verificato che web-app non richiede più /user-service/v1/ e web-app non eseguire il rollback, il team può eseguire il deployment di codice che rimuove /user-service/v1/ ed eventuali codici temporanei necessari per supportarlo.

Sebbene questa attività possa sembrare onerosa, è un processo essenziale nella basate su microservizi ed è esattamente il processo che consente indipendenti cicli di rilascio per lo sviluppo. Precisiamo che questo processo appare molto dipendente, ma è importante sottolineare che ogni passaggio precedente può avvenire su le tempistiche, il rollback e il rollback avvengono nell'ambito di una microservizio. È fisso solo l'ordine dei passaggi, che possono essere avvengono nell'arco di molte ore, giorni o persino settimane.

Passaggi successivi