Gestisci i rischi di scalabilità

l'infrastruttura di Google è progettata per funzionare in modo elastico su larga scala: la maggior parte dei livelli è in grado di adattarsi all'aumento del traffico su larga scala. Un pattern di progettazione principale che rende possibile tutto questo è l'adattamento dei livelli, ovvero i componenti dell'infrastruttura che riallocano dinamicamente il carico in base ai modelli di traffico. L'adattamento, tuttavia, richiede tempo. Poiché Cloud Tasks consente l'invio di volumi di traffico molto elevati, espone i rischi di produzione in situazioni in cui il traffico può scalare più velocemente di quanto l'infrastruttura possa adattarsi.

Panoramica

Questo documento fornisce linee guida sulle best practice per mantenere elevate le prestazioni di Cloud Tasks nelle code con traffico elevato. Una coda TPS elevata è una coda che contiene almeno 500 attività create al secondo (TPS) o inviate. Un gruppo di code 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 con traffico elevato e i gruppi di code sono soggetti a due diverse classi di errori generali:

Il sovraccarico di code si verifica quando la creazione e l'invio di attività a una singola coda o a un singolo gruppo di code aumenta più velocemente di quanto l'infrastruttura della coda possa 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: quando si scala oltre i 500 TPS, aumenta il traffico di non più del 50% ogni 5 minuti. Questo documento esamina diversi scenari che possono introdurre rischi di scalabilità e fornisce esempi su come applicare questo pattern.

Sovraccarico di code

Le code o i gruppi di code possono essere sovraccarichi ogni volta che il traffico aumenta improvvisamente. Di conseguenza, queste code possono registrare:

  • Aumento della latenza di creazione delle attività
  • Percentuale di errore di creazione attività aumentata
  • Riduzione della percentuale di spedizioni

Per difenderti da questo problema, ti consigliamo di stabilire dei controlli in qualsiasi situazione in cui la frequenza di creazione o invio di una coda o di un gruppo di code può subire un improvviso picco. Consigliamo un massimo di 500 operazioni al secondo a una coda di attesa o un gruppo di code, poi aumenta il traffico del 50% ogni 5 minuti. In teoria, puoi crescere fino a 740.000 operazioni al secondo dopo 90 minuti utilizzando questo programma iniziale. Ciò può verificarsi in una serie di circostanze.

Ad esempio:

  • Lancio di nuove funzionalità che consentono un uso intensivo di Cloud Tasks
  • Spostamento del traffico tra code
  • Ribilanciare il traffico in più o meno code
  • Esecuzione di job batch che inseriscono un numero elevato di attività

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

Utilizzo della suddivisione del traffico di App Engine

Se le attività vengono create da un'app App Engine, puoi usare la suddivisione del traffico di App Engine (Standard/Flex) per gestire meglio l'aumento del traffico. Suddividendo il traffico tra versioni (Standard/Flex), le richieste che devono essere gestite a livello di frequenza possono essere pubblicate nel tempo per proteggere lo stato della coda. Ad esempio, considera il caso di avviare il traffico a un gruppo di code appena espanso: considera [queue0000, queue0199] una sequenza di code con TPS elevato che ricevono 100.000 creazioni TPS in totale.

Consenti [queue0200, queue0399] di essere 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, aumenta gradualmente il traffico alla nuova versione e, di conseguenza, alle nuove code, utilizzando la suddivisione del traffico:

  • Inizia a spostare l'1% del traffico sulla nuova versione. Ad esempio,il 50% di 1% di 100.000 TPS restituisce 500 TPS al set di nuove code.
  • Ogni 5 minuti, aumenta del 50% il traffico che viene inviato alla nuova release, come descritto in dettaglio nella tabella seguente:
Minuti dall'inizio del deployment % di traffico totale spostato alla nuova versione % di traffico totale verso le nuove code % di traffico totale verso le code precedenti
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 basati sulla release

Quando avvii una release che aumenta in modo significativo il traffico verso una coda o un gruppo di code, l'implementazione graduale è, di nuovo, un meccanismo importante per uniformare gli aumenti. Implementa gradualmente le tue istanze in modo che il lancio iniziale non superi le 500 operazioni totali nelle nuove code, aumentando di oltre il 50% ogni 5 minuti.

Nuove code o gruppi di code High-TPS

Le code appena create sono particolarmente vulnerabili. I gruppi di code, ad esempio [queue0000, queue0001, ..., queue0199], sono sensibili come singole code durante le fasi di implementazione iniziale. Per queste code, l'implementazione graduale è una strategia importante. Avviare servizi nuovi o aggiornati, che creano code o gruppi di code con TPS elevati, in fasi tale da far sì che il caricamento iniziale sia inferiore a 500 TPS e l'aumento del 50% o inferiore avviene in sequenza 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 diverso dalle singole code. Applica il pattern 500/50/5 al nuovo gruppo nel suo complesso, non solo alle singole code all'interno del gruppo. Per queste espansioni di gruppi di code, l'implementazione graduale è di nuovo una strategia importante. Se la sorgente del tuo traffico è App Engine, puoi utilizzare la suddivisione del traffico (vedi Segnali di traffico basati su release). Quando esegui la migrazione del 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, aumentando di oltre il 50% ogni 5 minuti.

Espansione del gruppo di code di emergenza

A volte potresti voler espandere un gruppo di code esistente, ad esempio perché è previsto che le attività vengano 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 di coda esistenti quando ordinati nell'ordine lessicografico, il traffico può essere inviato immediatamente a tali code purché non ci siano più del 50% di nuove code interlacciate e il traffico verso ciascuna coda sia inferiore a 500 TPS. Questo metodo rappresenta un'alternativa all'uso della suddivisione del traffico e dell'implementazione graduale come descritto nelle sezioni precedenti.

Questo tipo di denominazione con interfoliazione può essere ottenuto aggiungendo un suffisso alle code che terminano con numeri pari. Ad esempio, se hai 200 code esistenti [queue0000-queue0199] e vuoi creare 100 nuove code, scegli [queue0000a, queue0002a, queue0004a, ..., queue0198a]0 come 02

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

Accoda attività su larga scala/batch

Quando è necessario aggiungere un elevato numero di attività, ad esempio milioni o miliardi, può essere utile uno schema di doppia iniezione. Anziché creare attività da un singolo job, usa una coda di inserimento. Ogni attività aggiunta alla coda dell'iniettore si espande e aggiunge 100 attività alla coda o al gruppo di code desiderato. La coda dell'iniettore può essere accelerata nel tempo, ad esempio iniziare a 5 TPS, quindi 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, ciò genera un overhead di prestazioni significativo, con conseguente aumento delle latenze e potenziali percentuali di errore associate alle attività denominate. Questi costi possono essere aumentati in modo significativo se le attività sono denominate in sequenza, ad esempio con timestamp. Quindi, 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 sulla denominazione di un'attività.

Sovraccarico target

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

Riattivare o riattivare le code con TPS elevato

Quando una coda o una serie di code viene riattivata o riattivata, le code continuano a essere inviate. Se la coda include molte attività, la velocità di invio della coda appena abilitata potrebbe aumentare notevolmente da 0 TPS all'intera capacità della coda. Per aumentare la velocità, la coda di scaglioni riprende o controlla le frequenze di invio delle code utilizzando Cloud TasksmaxDispatchesPerSecond.

Attività programmate collettivamente

Un elevato numero di attività, che sono pianificate per la spedizione nello stesso momento, può anche comportare un rischio di sovraccarico. Se devi avviare un numero elevato di attività contemporaneamente, valuta la possibilità di utilizzare i controlli della coda di coda per aumentare la velocità di invio gradualmente o di ruotare esplicitamente la capacità target in anticipo.

Aumento del fan-out

Quando aggiorni i servizi che vengono eseguiti tramite Cloud Tasks, aumentare il numero di chiamate remote 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 notevolmente il costo di chiamata al numero /task-foo se, ad esempio, la nuova release aggiunge numerose chiamate Datastore costose al gestore. Il risultato netto di questa release sarebbe un enorme aumento del traffico di Datastore immediatamente correlato alle modifiche al traffico degli utenti. Utilizza l'implementazione graduale o la suddivisione del traffico per gestire la strategia di applicazione graduale.

Nuovi tentativi

Il codice può riprovare in caso di errore quando effettui chiamate API Cloud Tasks. Tuttavia, quando una percentuale significativa delle richieste non riesce con errori lato server, un'elevata frequenza di nuovi tentativi può sovraccaricare ulteriormente le code e causarne il recupero più lento. Ti consigliamo quindi di limitare la quantità di traffico in uscita se il tuo client rileva che una parte significativa delle richieste non riesce con errori lato server, ad esempio utilizzando l'algoritmo di throttling adattivo descritto nel capitolo Gestione del sovraccarico del libro di Site Reliablity Engineering. Le librerie client gRPC di Google implementano una variazione di questo algoritmo.