12 apr 2025·8 min di lettura

Blue-green vs canary: cambiamenti più sicuri per API e database

Blue-green vs canary spiegati per cambi di API e database, con passi pratici per ridurre il rischio di downtime durante migrazioni di schema e aggiornamenti mobili lenti.

Blue-green vs canary: cambiamenti più sicuri per API e database

Perché i deploy diventano rischiosi con cambi di schema e aggiornamenti mobili lenti

Un deploy può sembrare perfetto nei test e fallire appena arriva traffico reale. La ragione solita è che non cambia solo il codice: cambiano anche il contratto API e lo schema del database, e raramente procedono alla stessa velocità.

Le cose si rompono quando le parti del sistema non sono d'accordo su cosa significhi "corretto". Un backend nuovo si aspetta una colonna che non esiste ancora. Un backend più vecchio scrive dati in un formato che il codice nuovo non capisce più. Anche piccoli cambi come rinominare un campo, restringere la validazione o cambiare un valore enum possono causare errori in produzione.

Le app mobile alzano la posta perché le versioni vecchie restano in circolazione. Alcuni utenti aggiornano in pochi minuti, altri in settimane. Questo significa che il tuo backend deve servire più generazioni di client contemporaneamente. Se rilasci una modifica API che funziona solo con l'app più recente, puoi rompere checkout, onboarding o sincronizzazioni in background per una fetta di utenti senza accorgertene subito.

"Rischio di downtime" non è solo il sito che cade. Nei sistemi reali si manifesta spesso come guasti parziali:

  • un picco di errori 4xx/5xx su endpoint specifici mentre tutto il resto sembra a posto
  • accessi che falliscono perché token, ruoli o record utente non corrispondono più alle aspettative
  • problemi di dati silenziosi (default sbagliati, testo troncato, relazioni mancanti) che emergono giorni dopo
  • job in background bloccati che costruiscono una coda che impiega ore a svuotarsi

Per questo i team confrontano blue-green vs canary: stai cercando di ridurre il blast radius quando i cambiamenti non sono perfettamente compatibili.

Blue-green e canary in parole semplici

Quando si confrontano blue-green vs canary si risponde quasi sempre a una domanda: vuoi uno switch grande e controllato, o un test piccolo e prudente?

Blue-green: due versioni complete e uno switch del traffico

Blue-green significa eseguire due ambienti completi contemporaneamente. "Blue" è la versione corrente che serve gli utenti. "Green" è la nuova versione, deployata e testata in parallelo. Quando sei pronto, giri il traffico da blue a green.

Questo approccio è ottimo per la prevedibilità. Puoi validare la nuova versione con impostazioni simili alla produzione prima che serva utenti reali, poi fare un cutover pulito.

Il rollback è anche semplice: se qualcosa va storto dopo lo switch, rimandi il traffico a blue. È vicino a uno switch istantaneo, ma cache, job in background e cambi di dati possono comunque complicare il recupero.

Canary: invii prima una piccola percentuale di traffico

Canary significa che la nuova versione va in produzione solo per una fetta ridotta di utenti o richieste all'inizio. Se sembra sana, aumenti gradualmente quella percentuale fino a servire tutti.

Canary è ideale quando temi comportamenti sconosciuti con traffico reale. Puoi intercettare problemi prima che la maggior parte degli utenti li noti.

Il rollback avviene riducendo la percentuale del canary a zero (o fermando il routing verso la nuova versione). È solitamente veloce, ma non sempre pulito, perché alcuni utenti potrebbero aver già creato dati o stato che entrambe le versioni devono gestire.

Un modo semplice per ricordare i compromessi:

  • Blue-green favorisce cutover puliti e switchback rapidi.
  • Canary favorisce l'apprendimento dal traffico reale con blast radius limitato.
  • Nessuno dei due risolve automaticamente il rischio sul database. Se le modifiche di schema non sono compatibili, entrambi possono fallire.
  • Canary dipende dal monitoraggio perché decidi in base a segnali live.
  • Blue-green spesso richiede capacità extra perché esegui due stack completi.

Esempio: se rilasci un'API che a volte restituisce un nuovo campo, un canary ti aiuta a vedere se i client più vecchi vanno in crash su dati inaspettati. Se la modifica richiede il rinome di una colonna che il codice vecchio non può gestire, blue-green non ti salva a meno che la migrazione non sia progettata per supportare entrambe le versioni.

Cosa rende le migrazioni database diverse dai deploy di codice

Un deploy di codice è solitamente facile da rollbackare. Se la nuova versione si comporta male, ridistribuisci la build precedente e torni quasi subito dove eri.

Una modifica al database è diversa perché cambia la forma dei dati. Una volta che le righe sono riscritte, le colonne eliminate o i vincoli irrigiditi, tornare indietro raramente è istantaneo. Anche se fai rollback del codice, potrebbe non capire il nuovo schema.

Per questo il rischio di downtime in una migrazione di schema ha più a che fare con come la migrazione è progettata che con il metodo di deploy.

Basi della migrazione online

Le migrazioni più sicure sono progettate per funzionare mentre vecchie e nuove versioni dell'app girano contemporaneamente. Il pattern è semplice: fai una modifica che sia sicura da ignorare, aggiorna il codice per usarla, poi pulisci più tardi.

Una sequenza comune expand-then-contract è:

  • Cambi additivi prima: aggiungi una colonna nullable, una nuova tabella, un indice in modo che non blocchi le scritture.
  • Comportamento doppio: scrivi sia nel vecchio che nel nuovo, o leggi dal nuovo con fallback al vecchio.
  • Backfill separato: migra i dati esistenti in piccoli batch.
  • Switch: sposta la maggior parte del traffico al comportamento nuovo.
  • Cambi distruttivi per ultimi: elimina colonne vecchie, rimuovi i percorsi di codice obsoleti, irrigidisci i vincoli.

Le migrazioni "big bang" combinano i passaggi più rischiosi in un solo rilascio: lock lunghi, backfill pesanti e codice che assume che il nuovo schema esista ovunque.

Perché gli aggiornamenti mobili lenti alzano l'asticella

I client mobile possono restare su versioni vecchie per settimane. Il backend deve continuare ad accettare richieste vecchie e produrre risposte vecchie mentre il database evolve.

Se un'app più vecchia invia una richiesta senza un nuovo campo, il server non può improvvisamente rendere quel campo obbligatorio nel database. Serve un periodo in cui entrambi i comportamenti funzionano.

Quale strategia riduce il rischio di downtime per le migrazioni di schema

La scelta più sicura dipende meno dallo strumento di deploy e più da una domanda: vecchie e nuove versioni dell'app possono funzionare correttamente sullo stesso schema di database per un po'?

Se la risposta è sì, blue-green è spesso l'opzione a minor downtime. Puoi preparare il cambiamento del database per primo, mantenere il traffico sullo stack vecchio, poi switchare tutto al nuovo stack in un unico cutover. Se qualcosa sembra sbagliato, torni indietro rapidamente.

Blue-green fallisce comunque quando la nuova app richiede immediatamente il nuovo schema. Esempi comuni sono eliminare o rinominare una colonna che la versione vecchia legge, o aggiungere un vincolo NOT NULL prima che l'app scriva il valore. In questi casi il rollback può non essere sicuro perché il database è già incompatibile.

Canary è meglio quando hai bisogno di apprendere in modo controllato. Una piccola fetta di traffico reale colpisce la nuova versione per prima, aiutandoti a scovare edge case come indici mancanti, pattern di query inaspettati o job in background che si comportano diversamente sotto carico. Il compromesso è che devi mantenere entrambe le versioni funzionanti contemporaneamente, il che di solito implica cambi retrocompatibili al database.

Una regola pratica per decidere

Quando pesi blue-green vs canary per il rischio di downtime da migrazione di schema:

  • Scegli blue-green quando puoi mantenere la modifica dello schema additiva e compatibile, e vuoi principalmente uno switch rapido e pulito.
  • Scegli canary quando non sei sicuro di come si comporterà la modifica in produzione, o ti aspetti che forme di dato rare siano rilevanti.
  • Se la migrazione forza un cambiamento immediato e incompatibile, non scegliere tra blue-green e canary: cambia piano verso expand-then-contract.

Come si presenta la "compatibilità" nella pratica

Supponiamo di aggiungere un nuovo campo alla tabella orders. Un percorso sicuro è: aggiungi la colonna nullable, distribuisci l'app che la scrive, backfilla le righe vecchie, poi in seguito applica i vincoli. In quel setup blue-green ti dà un cutover pulito, e canary ti dà un avviso precoce se qualche percorso di codice assume ancora la forma vecchia.

Come gli aggiornamenti mobili lenti cambiano la scelta di deployment

Sviluppa strumenti interni più velocemente
Crea rapidamente un pannello admin o un portale funzionante, poi itera in sicurezza mentre i dati evolvono.
Provala ora

Gli utenti web aggiornano la pagina. Gli utenti mobile no.

Su iOS e Android, le persone restano su versioni vecchie per settimane o mesi. Alcuni non aggiornano finché l'app non lo richiede e alcuni dispositivi restano offline a lungo. Questo significa che il tuo client "vecchio" continua a chiamare la tua API molto tempo dopo che hai rilasciato il backend nuovo. I client mobile più vecchi diventano test permanenti della tua retrocompatibilità.

Questo sposta l'obiettivo da "deploy senza downtime" a "mantenere più generazioni di client funzionanti contemporaneamente." In pratica, il mobile spesso ti spinge verso un pensiero simile al canary per le API, anche se usi blue-green per l'infrastruttura.

Cambi retrocompatibili vs versioning API

La maggior parte delle volte vuoi cambi retrocompatibili, perché permettono a vecchie e nuove app di condividere gli stessi endpoint.

Esempi retrocompatibili includono aggiungere nuovi campi, accettare sia forme di payload vecchie che nuove, mantenere i campi di risposta esistenti ed evitare cambi di significato. Il versioning API per app mobile diventa utile quando il comportamento deve cambiare (non solo aggiungere dati) o quando devi rimuovere o rinominare campi.

Esempio: aggiungere un campo opzionale come marketing_opt_in è di solito sicuro. Cambiare il modo in cui viene calcolato price di solito non lo è.

Pianificare una finestra di deprecazione

Se devi fare un cambiamento incompatibile, tratta la fine del supporto come una decisione di prodotto. Una finestra di deprecazione utile si misura in base agli "utenti attivi ancora su versioni vecchie", non in giorni sul calendario.

Una sequenza pratica:

  • Rilascia il backend che supporta sia client vecchi che nuovi.
  • Pubblica la nuova app mobile e monitora l'adozione per versione.
  • Avvisa o limita solo quando le versioni vecchie scendono sotto una soglia sicura.
  • Rimuovi il comportamento vecchio per ultimo, con un piano di rollback.

Passo dopo passo: un rollout sicuro per API + database

Un modello per ogni client
Costruisci backend, web e app native da un unico modello senza gestire stack separati.
Inizia a costruire

Quando cambi API e database insieme, il piano più sicuro è di solito un rollout in due o tre fasi. Ogni step dovrebbe essere sicuro da deployare da solo, anche se gli utenti mantengono un'app mobile vecchia per settimane.

Un pattern di rollout che evita di rompere client vecchi

Inizia con un cambiamento additivo al database. Aggiungi nuove colonne o tabelle, evita di rinominare o eliminare cose, consenti null dove serve e usa default in modo che il codice più vecchio non incontri vincoli improvvisi.

Poi rilascia codice che tolleri entrambe le forme di dati. Le letture devono accettare "campo mancante" e "campo nuovo presente". Le scritture devono continuare a popolare il campo vecchio per ora, e opzionalmente scrivere anche il nuovo.

Una sequenza tipica:

  • Aggiungi parti di schema (colonne, tabelle, indici) senza rimuovere le vecchie.
  • Distribuisci codice che legge dal vecchio o dal nuovo senza crashare su null.
  • Backfilla le righe esistenti a piccoli batch, poi verifica conteggi, rate di null e performance delle query.
  • Cambia il percorso di scrittura verso il campo nuovo, mantenendo read fallback.
  • Dopo che le versioni mobile più vecchie sono diminuite, rimuovi il campo vecchio e il codice di compatibilità.

Backfill e verifica: dove si nascondono gli outage

I backfill falliscono spesso perché vengono trattati come uno script rapido. Eseguili gradualmente, osserva il carico e verifica i risultati. Se il nuovo comportamento necessita di un indice, aggiungilo prima di cambiare letture o scritture, non dopo.

Esempio: aggiungi phone_country_code per migliorare il formato. Prima aggiungi la colonna (nullable), aggiorna l'API per accettarla ma funzionare se manca, backfilla dai numeri esistenti, poi comincia a scriverla per le nuove registrazioni. Dopo settimane, quando le app vecchie sono per lo più sparite, puoi rimuovere il parsing legacy.

Strumenti che rendono più sicure entrambe le strategie (senza complicare troppo)

Non serve una configurazione complicata per rendere blue-green e canary più sicuri. Alcune pratiche riducono le sorprese quando API e schemi si muovono a velocità diverse.

Dual-read e dual-write (mantienili temporanei)

Dual-write significa che l'app scrive dati sia nel posto vecchio che in quello nuovo durante la transizione (per esempio sia users.full_name sia il nuovo users.display_name). Dual-read significa che può leggere da entrambi, preferendo di solito il nuovo ma ricadendo sul vecchio.

Questo compra tempo per aggiornamenti client lenti, ma deve essere un ponte breve. Decidi come lo rimuoverai, monitora quale percorso è usato (nuovo vs fallback) e aggiungi controlli base per assicurarti che entrambe le scritture rimangano consistenti.

Feature flag per i cambi di comportamento

Le feature flag permettono di distribuire codice senza attivare il comportamento rischioso. Questo aiuta sia blue-green che canary perché puoi separare "deploy" da "attiva".

Esempio: distribuisci il supporto per un nuovo campo di risposta, ma continua a restituire la forma vecchia finché non sei pronto. Poi abilita il comportamento per un piccolo gruppo, osserva gli errori e aumenta. Se qualcosa si rompe, spegni la flag senza fare rollback completo.

Mentalità di contract testing (l'API è una promessa)

Molti incidenti di migrazione non sono davvero "problemi di database." Sono problemi di aspettative dei client.

Tratta l'API come una promessa. Evita di rimuovere campi o cambiarne il significato. Rendi opzionali i campi sconosciuti. I cambi additivi (nuovi campi, nuovi endpoint) sono generalmente sicuri. I cambi incompatibili dovrebbero aspettare una nuova versione API.

Job di migrazione dati affidabili

Le migrazioni spesso richiedono un job di backfill per copiare dati, calcolare valori o ripulire. Questi job dovrebbero essere noiosi e ripetibili: sicuri da eseguire più volte, retryabili, facili da tracciare e limitati per non innalzare troppo il carico.

Errori comuni che causano outage durante le migrazioni

Possiedi il codice sorgente
Crea codice Go, Vue3 e Kotlin o SwiftUI pronto per la produzione che puoi distribuire ovunque.
Genera codice

La maggior parte degli outage da migrazione avviene quando un rilascio presume che tutto si muova insieme: tutti i servizi deployano, tutti i dati sono puliti e tutti i client si aggiornano in tempo. I sistemi reali non funzionano così, soprattutto con il mobile.

Pattern di fallimento comuni:

  • Eliminare o rinominare una colonna troppo presto. API vecchie, job in background o app mobile obsolete possono ancora usarla.
  • Presumere che i client si aggiornino rapidamente. I rilasci mobile impiegano tempo e molti utenti non aggiornano subito.
  • Eseguire migrazioni che bloccano tabelle grandi nelle ore di punta. Un "semplice" indice o cambiamento di colonna può bloccare le scritture.
  • Testare solo dati puliti di esempio. I dati di produzione includono null, formati strani, duplicati e valori legacy.
  • Non avere un piano di rollback per codice e dati. "Ridispieghiamo la versione precedente" non basta se lo schema è cambiato.

Esempio: rinomini status in order_status e distribuisci la nuova API. Il web funziona. Le app mobile più vecchie inviano ancora status e ora l'API rifiuta quelle richieste, causando checkouts falliti. Se hai eliminato la colonna, ripristinare il comportamento non è uno switch veloce.

Una buona regola di default è: fai cambi piccoli e reversibili, mantieni vecchi e nuovi percorsi insieme e scrivi cosa farai se i metrici schizzano (come rimandare il traffico indietro, quale feature flag spegne il comportamento nuovo e come validare e riparare i dati se un backfill va storto).

Checklist rapida prima di distribuire

Aggiungi logica senza riscritture
Usa processi aziendali visivi per aggiungere validazione e logiche di fallback senza riscritture rischiose.
Inizia ora

Subito prima di un rilascio, una checklist corta cattura i problemi che portano a rollback notturni. Questo è cruciale quando cambi API e database insieme, specialmente con aggiornamenti mobile lenti.

Cinque controlli che prevengono la maggior parte degli outage

  • Compatibilità: conferma che le versioni vecchie e nuove dell'app funzionano entrambe contro lo stesso schema. Un test pratico è eseguire la build di produzione corrente contro un database di staging con la nuova migrazione applicata.
  • Ordine delle migrazioni: assicurati che la prima migrazione sia additiva e programma i cambi distruttivi (eliminare colonne, irrigidire vincoli) per dopo.
  • Rollback: definisci il modo più veloce per tornare indietro. Per blue-green è girare il traffico indietro. Per canary è riportare il 100% al percorso stabile. Se il rollback richiede un'altra migrazione, non è semplice.
  • Performance: misura la latenza delle query dopo il cambiamento di schema, non solo la correttezza. Un indice mancante può far sembrare un endpoint in outage.
  • Realtà dei client: identifica la versione mobile più vecchia ancora attiva che chiama la tua API. Se una percentuale significativa è su quella versione, pianifica una finestra di compatibilità più lunga.

Uno scenario di sanità mentale rapido

Se aggiungi un nuovo campo come preferred_language, distribuisci prima la modifica del database come nullable. Poi rilascia il codice server che lo legge se presente ma non lo richiede. Solo dopo che la maggior parte del traffico è su app aggiornate rendilo obbligatorio o rimuovi il comportamento vecchio.

Esempio: aggiungere un campo senza rompere le app mobile più vecchie

Immagina di aggiungere un nuovo campo profilo, country, e il business vuole che sia obbligatorio. Questo può rompere in due punti: i client vecchi potrebbero non inviare il campo, e il database potrebbe rifiutare le scritture se imponi NOT NULL troppo presto.

Un approccio più sicuro è in due cambi separati: prima aggiungi il campo in modo retrocompatibile, poi impone l'obbligatorietà più avanti, dopo che i client sono aggiornati.

Come appare con blue-green

Con blue-green distribuisci la versione nuova accanto a quella vecchia. Devi comunque rendere la modifica del database compatibile con entrambe le versioni.

Un flow sicuro è:

  • distribuire la migrazione (aggiungi country come nullable)
  • distribuire la versione green che accetta country mancante e usa un fallback
  • testare i flussi chiave su green (signup, modifica profilo, checkout)
  • switchare il traffico

Se qualcosa va storto, torna indietro. La chiave è che il switchback funziona solo se lo schema supporta ancora la versione vecchia.

Come appare con canary

Con canary esponi il nuovo comportamento API a una piccola fetta (spesso 1%–5%) e osservi errori di validazione per campo mancante, cambi di latenza e failure DB inattesi.

Una sorpresa comune è che client mobile vecchi inviino aggiornamenti di profilo senza country. Se l'API lo tratta subito come obbligatorio vedrai 400; se il database applica NOT NULL potresti vedere 500.

Una sequenza più sicura:

  • aggiungi country come nullable (opzionalmente con default sicuro come "unknown")
  • accetta country mancante dai client vecchi
  • backfilla country per utenti esistenti in un job background
  • impone "obbligatorio" più tardi (prima nell'API, poi nel database)

Dopo il rilascio, documenta cosa i client vecchi possono inviare e cosa il server garantisce. Quel contratto scritto evita lo stesso problema nella migrazione successiva.

Se costruisci con AppMaster (appmaster.io), la stessa disciplina di rollout si applica anche se puoi generare backend, web e app native da un unico modello. Usa la piattaforma per distribuire prima cambi additivi dello schema e logica API tollerante, poi irrigidisci i vincoli solo dopo che l'adozione è sufficiente.

FAQ

Qual è la differenza più semplice tra blue-green e canary?

Blue-green esegue due ambienti completi e poi passa tutto il traffico in una volta. Canary rilascia la nuova versione solo a una piccola percentuale degli utenti e la scala in base a ciò che osservi nel traffico reale.

Quando dovrei scegliere blue-green per una modifica API + database?

Usa blue-green quando vuoi un cutover pulito e sei sicuro che la nuova versione sia compatibile con lo schema del database corrente. È particolarmente utile quando il rischio principale riguarda il codice applicativo, non comportamenti sconosciuti in produzione.

Quando è più sicuro usare canary?

Scegli canary quando hai bisogno di imparare dal traffico reale prima di andare completamente in produzione, ad esempio quando pattern di query, dati ai limiti o job in background potrebbero comportarsi diversamente. Riduce il raggio d'azione dell'errore, ma richiede monitoraggio accurato e prontezza a fermare il rollout.

Blue-green o canary rendono automaticamente sicure le migrazioni di database?

No. Se la modifica dello schema rompe la compatibilità (per esempio eliminando o rinominando una colonna che il codice vecchio usa), sia blue-green che canary possono fallire. La soluzione più sicura è progettare una migrazione online che supporti vecchie e nuove versioni contemporaneamente.

Perché gli aggiornamenti lenti delle app mobile rendono più rischiose le distribuzioni?

Gli utenti mobile possono restare su versioni più vecchie per settimane, quindi il backend deve supportare più generazioni di client simultaneamente. Questo in genere significa mantenere le API retrocompatibili più a lungo ed evitare cambi che richiedono l'aggiornamento immediato di tutti i client.

Qual è il modo più sicuro per distribuire una modifica di schema senza downtime?

Inizia con cambi additivi che il codice vecchio può ignorare, come colonne nullable o nuove tabelle. Poi distribuisci codice che accetti entrambe le forme, esegui backfill graduali, cambia il percorso di scrittura e solo dopo rimuovi i campi vecchi o rafforza i vincoli.

Come mantengo la retrocompatibilità delle API durante una migrazione?

Fai una lista di ciò che i client vecchi inviano e si aspettano in risposta, quindi evita di rimuovere campi o cambiarne il significato. Preferisci aggiungere campi opzionali, accetta sia le vecchie che le nuove forme di richiesta e rimanda le validazioni “obbligatorie” finché l'adozione non è sufficiente.

Cosa sono dual-read e dual-write, e quando usarli?

Dual-write scrive sia nel campo vecchio che in quello nuovo durante la transizione; dual-read legge il nuovo campo con fallback al vecchio. Usali temporaneamente, monitora quale percorso viene usato e pianifica una pulizia chiara quando i client più vecchi spariscono.

Come riducono il rischio le feature flag durante cambi API o DB?

Le feature flag permettono di distribuire codice senza attivare subito il comportamento rischioso. Così puoi separare il momento del deploy dall'attivazione, abilitarlo gradualmente e spegnerlo se gli errori aumentano, senza dover ridistribuire.

Quali sono gli errori più comuni nelle migrazioni che causano outage?

Eliminare o rinominare colonne troppo presto, imporre NOT NULL prima che i client inviino il valore e lanciare migrazioni bloccanti nelle ore di punta sono cause frequenti. Un altro errore comune è presumere che i dati di test siano uguali a quelli di produzione, quindi i backfill falliscono su null o formati strani.

Facile da avviare
Creare qualcosa di straordinario

Sperimenta con AppMaster con un piano gratuito.
Quando sarai pronto potrai scegliere l'abbonamento appropriato.

Iniziare