Gestisci i rischi di scalabilità

L'infrastruttura di Google è progettata per operare in modo elastico su larga scala: la maggior parte dei livelli è in grado di adattarsi alla maggiore richiesta di traffico su larga scala. Un modello di progettazione fondamentale che rende possibile tutto ciò sono i livelli adattivi, ovvero i componenti dell'infrastruttura che riallocano dinamicamente il carico in base ai modelli di traffico. Questo adattamento, tuttavia, richiede tempo. Poiché Cloud Tasks consente l'invio di volumi molto elevati di traffico, espone rischi di produzione in situazioni in cui il traffico può salire più velocemente di quanto l'infrastruttura possa adattarsi.

Panoramica

Questo documento fornisce linee guida sulle best practice per mantenere prestazioni elevate di Cloud Tasks in code a traffico elevato. Una coda con TPS elevato è una coda con almeno 500 attività create o inviate al secondo (TPS). Un gruppo di code con TPS elevato è un insieme contiguo di code, ad esempio [queue0001, queue0002, ..., queue0099], con almeno 2000 attività create o inviate in totale. I TPS storici di una coda o di un gruppo di code sono visualizzabili utilizzando le metriche di Stackdriver, api/request_count per le operazioni "CreateTask" e queue/task_attempt_count per i tentativi di attività. Le code e i gruppi di code a traffico elevato sono soggetti a due ampie classi di errori:

Il sovraccarico delle code si verifica quando la creazione e l'invio delle attività a una singola coda o a un singolo gruppo di code aumentano più velocemente di quanto l'infrastruttura delle code sia in grado di adattarsi. Analogamente, il sovraccarico target si verifica quando la frequenza di invio delle attività causa picchi di traffico nell'infrastruttura di destinazione a valle. In entrambi i casi, consigliamo di seguire un pattern 500/50/5: se si esegue la scalabilità oltre i 500 TPS, aumentare il traffico non più del 50% ogni 5 minuti. Questo documento esamina diversi scenari che possono introdurre rischi di scalabilità e fornisce esempi di come applicare questo pattern.

Sovraccarico coda

Le code o i gruppi di code possono sovraccaricarsi ogni volta che il traffico aumenta improvvisamente. Di conseguenza, queste code possono presentare i seguenti problemi:

  • Aumento della latenza nella creazione delle attività
  • Aumento della percentuale di errori di creazione delle attività
  • Tariffa di spedizione ridotta

Per difenderti da ciò, ti consigliamo di implementare controlli in ogni situazione in cui la frequenza di creazione o invio di una coda o di un gruppo di code può aumentare improvvisamente. Consigliamo un massimo di 500 operazioni al secondo su una coda a freddo o un gruppo di code, per poi aumentare il traffico del 50% ogni 5 minuti. In teoria, puoi arrivare a 740.000 operazioni al secondo dopo 90 minuti utilizzando questa pianificazione di applicazione graduale. Esistono numerose circostanze in cui ciò può verificarsi.

Ad esempio:

  • Lancio di nuove funzionalità che fanno un uso intensivo di Cloud Tasks
  • Spostamento del traffico tra code
  • Ribilanciamento del traffico su un numero maggiore o minore di code
  • Esecuzione di job batch che inseriscono un numero elevato di attività

In questi e in altri casi, seguire lo schema 500/50/5.

Utilizzo della suddivisione del traffico di App Engine

Se le attività vengono create da un'app App Engine, puoi utilizzare la suddivisione del traffico di App Engine (Standard/Flex) per ottimizzare gli aumenti del traffico. Suddividendo il traffico tra le versioni (Standard/Flex), le richieste che devono essere gestite dalla tariffa possono essere attivate nel tempo per proteggere l'integrità della coda. Prendiamo come esempio l'attivazione del traffico verso un gruppo di code appena espanso: permetti a [queue0000, queue0199] di essere una sequenza di code con TPS elevato che ricevono 100.000 creazioni in totale di TPS nei momenti di punta.

Sia [queue0200, queue0399] sia una sequenza di nuove code. Dopo che tutto il traffico è stato spostato, il numero di code nella sequenza è raddoppiato e il nuovo intervallo di code riceve il 50% del traffico totale della sequenza.

Quando esegui il deployment della versione che aumenta il numero di code, incrementa gradualmente il traffico verso la nuova versione e quindi le nuove code, utilizzando la suddivisione del traffico:

  • Inizia a trasferire l'1% del traffico alla nuova release. Ad esempio,il 50% dell'1% di 100.000 TPS restituisce 500 TPS per l'insieme di nuove code.
  • Ogni 5 minuti, aumenta del 50% il traffico inviato alla nuova release, come descritto nella tabella seguente:
Minuti dall'inizio del deployment % di traffico totale spostato alla nuova versione % del traffico totale verso le nuove code % del traffico totale verso le vecchie code
0 1,0 0.5 99,5
5 1.5 0,75 99,25
10 2.3 1.15 98.85
15 3.4 1.7 98.3
20 5.1 2.55 97.45
25 7.6 3,8 96.2
30 11.4 5.7 94.3
35 17.1 8.55 91.45
40 25,6 12,8 87.2
45 38.4 19.2 80,8
50 57.7 28.85 71.15
55 86.5 43.25 56.75
60 100 50 50

Picchi di traffico generati dalle release

Quando lanci una release che aumenta in modo significativo il traffico in una coda o in un gruppo di code, l'implementazione graduale è, ancora una volta, un meccanismo importante per livellare gli aumenti. Implementa gradualmente le istanze in modo che il lancio iniziale non superi le 500 operazioni totali nelle nuove code, con un aumento non superiore al 50% ogni 5 minuti.

Nuove code o gruppi di code con TPS elevato

Le code appena create sono particolarmente vulnerabili. I gruppi di code, ad esempio [queue0000, queue0001, ..., queue0199], sono sensibili quanto le singole code durante le fasi iniziali di implementazione. Per queste code, l'implementazione graduale è una strategia importante. Lanciare servizi nuovi o aggiornati, che creano code o gruppi di code con TPS elevato, in fasi in cui il caricamento iniziale è inferiore a 500 TPS e gli incrementi pari o inferiori al 50% vengono eseguiti a intervalli di 5 minuti o più.

Gruppi di code appena espansi

Quando aumenti la capacità totale di un gruppo di code, ad esempio espandendo [queue0000-queue0199 a queue0000-queue0399], segui il pattern 500/50/5. È importante notare che, per le procedure di implementazione, i nuovi gruppi di code si comportano in modo simile alle singole code. Applica il pattern 500/50/5 all'intero gruppo, non solo alle singole code all'interno del gruppo. Per queste espansioni dei gruppi di code, l'implementazione graduale è nuovamente una strategia importante. Se la sorgente del traffico è App Engine, puoi utilizzare la suddivisione del traffico (consulta la sezione Picco di traffico basato sul rilascio). Quando esegui la migrazione del tuo servizio per aggiungere attività all'aumento del numero di code, implementa gradualmente le istanze in modo che il lancio iniziale non superi le 500 operazioni totali nelle nuove code, con un aumento non superiore al 50% ogni 5 minuti.

Espansione del gruppo di code di emergenza

A volte, potresti voler espandere un gruppo di code esistente, ad esempio perché le attività dovrebbero essere aggiunte al gruppo di code più velocemente di quanto il gruppo possa inviarle. Se i nomi delle nuove code sono distribuiti uniformemente tra i nomi delle code esistenti quando sono ordinati lessicograficamente, il traffico può essere inviato immediatamente a queste code purché non vi siano più del 50% di nuove code con interleaving e il traffico verso ogni coda sia inferiore a 500 TPS. Questo metodo rappresenta un'alternativa all'utilizzo della suddivisione del traffico e dell'implementazione graduale, come descritto nelle sezioni precedenti.

Questo tipo di denominazione con interleaving può essere ottenuto aggiungendo un suffisso alle code che terminano con numeri pari. Ad esempio, se hai 200 code esistenti [queue0000-queue0199] e vuoi crearne 100 nuove, scegli [queue0000a, queue0002a, queue0004a, ..., queue0198a] invece di [queue0-9ue] come i nuovi nomi queue0-9uequeue-9ue.

Se hai bisogno di un ulteriore aumento, puoi ancora interfoliare fino al 50% di code in più ogni 5 minuti.

Accoda attività in batch/su larga scala

Quando è necessario aggiungere un numero elevato di attività, ad esempio milioni o miliardi, può essere utile un pattern a doppia iniezione. Invece di creare attività da un singolo job, utilizza una coda di injector. Ogni attività aggiunta alla coda degli iniettore si espande e aggiunge 100 attività alla coda o al gruppo di code desiderati. La coda degli iniettori può essere accelerata nel tempo, ad esempio iniziando a 5 TPS, per poi aumentare del 50% ogni 5 minuti.

Attività con nome

Quando crei una nuova attività, Cloud Tasks assegna all'attività un nome univoco per impostazione predefinita. Puoi assegnare il tuo nome a un'attività utilizzando il parametro name. Tuttavia, questo introduce un notevole overhead per le prestazioni, con un conseguente aumento delle latenze e un potenziale aumento dei tassi di errore associati alle attività con nome. Questi costi possono essere aumentati notevolmente se le attività vengono denominate in sequenza, ad esempio con i timestamp. Pertanto, se assegni nomi personalizzati, ti consigliamo di utilizzare un prefisso ben distribuito per i nomi delle attività, ad esempio un hash dei contenuti. Consulta la documentazione per ulteriori dettagli sull'assegnazione del nome a un'attività.

Sovraccarico target

Cloud Tasks può sovraccaricare altri servizi in uso, come App Engine, Datastore e l'utilizzo della rete, se gli invii da una coda aumentano drasticamente in un breve periodo di tempo. Se si è accumulato un backlog di attività, la riattivazione di queste code può sovraccaricare questi servizi. La difesa consigliata è lo stesso pattern 500/50/5 suggerito per il sovraccarico della coda: se una coda invia più di 500 TPS, aumenta il traffico attivato da una coda di non più del 50% ogni 5 minuti. Utilizza le metriche di Stackdriver per monitorare in modo proattivo gli aumenti del traffico. Gli avvisi di Stackdriver possono essere utilizzati per rilevare situazioni potenzialmente pericolose.

Riattivazione o ripristino di code con TPS elevato

Quando una coda o una serie di code viene riattivata o riattivata, le code riprendono l'invio. Se la coda contiene molte attività, la velocità di invio della coda appena attivata potrebbe aumentare drasticamente da 0 TPS alla piena capacità della coda. Per aumentare la velocità, la coda scaglionata riprende o controlla le velocità di invio della coda utilizzando maxDispatchesPerSecond di Cloud Tasks.

Attività pianificate collettive

Anche un numero elevato di attività, che è pianificato per l'invio contemporaneamente, può introdurre un rischio di sovraccarico target. Se devi avviare un numero elevato di attività contemporaneamente, ti consigliamo di utilizzare i controlli della velocità di coda per aumentare gradualmente la velocità di invio o di attivare esplicitamente la capacità target in anticipo.

fan-out aumentato

Durante l'aggiornamento dei servizi eseguiti tramite Cloud Tasks, l'aumento del numero di chiamate da remoto può creare rischi di produzione. Ad esempio, supponiamo che le attività in una coda con TPS elevato chiamino il gestore /task-foo. Una nuova release potrebbe aumentare significativamente il costo della chiamata a /task-foo se, ad esempio, questa nuova release aggiunge al gestore diverse chiamate Datastore costose. Il risultato netto di una release di questo tipo sarebbe un massiccio aumento del traffico di Datastore, immediatamente correlato alle variazioni del traffico degli utenti. Utilizza l'implementazione graduale o la suddivisione del traffico per gestire l'aumento.

Nuovi tentativi

Il codice può riprovare in caso di errore quando effettui chiamate API Cloud Tasks. Tuttavia, quando una percentuale significativa di richieste non riesce con errori sul lato server, un'elevata percentuale di nuovi tentativi può sovraccaricare ulteriormente le code e causarne il recupero più lento. Consigliamo quindi di limitare la quantità di traffico in uscita se il client rileva che una percentuale significativa di richieste non va a buon fine con errori lato server, ad esempio utilizzando l'algoritmo di limitazione adattiva descritto nel capitolo Gestione dell'overload del libro relativo a Site Reliablity Engineering. Le librerie client gRPC di Google implementano una variante di questo algoritmo.