L'infrastruttura di Google è progettata per operare in modo elastico su larga scala: la maggior parte dei livelli può adattarsi all'aumento della domanda di traffico fino a raggiungere dimensioni enormi. Un pattern di progettazione fondamentale che lo rende possibile sono i livelli adattivi, ovvero componenti dell'infrastruttura che riassegnano dinamicamente il carico in base ai pattern di traffico. Questo 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ò aumentare più rapidamente di quanto l'infrastruttura possa adattarsi.
Panoramica
Questo documento fornisce linee guida sulle best practice per mantenere prestazioni elevate di Cloud Tasks
nelle code con traffico elevato. Una coda con TPS elevato è una coda con 500 attività create o
inviate al secondo (TPS) o più. Un gruppo di code con TPS elevato è un insieme contiguo di code, ad esempio [queue0001, queue0002, …, queue0099], in cui sono state create o inviate in totale almeno 2000 attività. Il TPS storico di una coda o di un gruppo di code è visualizzabile
utilizzando le metriche di Cloud Monitoring, api/request_count
per le operazioni CreateTask e queue/task_attempt_count per i tentativi di attività. Le code e i gruppi di code con traffico elevato
sono soggetti a due diverse classi generali di errori:
Il sovraccarico della coda si verifica quando la creazione e l'invio di attività a una singola coda o a un gruppo di code aumentano più rapidamente di quanto l'infrastruttura delle code sia in grado di adattarsi. Analogamente, il sovraccarico target si verifica quando la velocità con cui vengono inviate le attività causa picchi di traffico nell'infrastruttura di destinazione downstream. In entrambi i casi, ti consigliamo di seguire un pattern 500/50/5: quando la scalabilità supera 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 di come applicare questo pattern.
Sovraccarico della coda
Le code o i gruppi di code possono sovraccaricarsi in qualsiasi momento in caso di aumento improvviso del traffico. Di conseguenza, queste code possono riscontrare:
- Aumento della latenza di creazione delle attività
- Aumento del tasso di errori di creazione delle attività
- Frequenza di invio ridotta
Per difenderti da questo problema, ti consigliamo di stabilire controlli in qualsiasi situazione in cui la velocità di creazione o invio di una coda o di un gruppo di code può aumentare improvvisamente. Consigliamo un massimo di 500 operazioni al secondo per una coda o un gruppo di code fredde, per poi aumentare il traffico del 50% ogni 5 minuti. In teoria, puoi raggiungere 740.000 operazioni al secondo dopo 90 minuti utilizzando questa pianificazione dell'aumento. Ciò può verificarsi in diverse circostanze.
Ad esempio:
- Lancio di nuove funzionalità che utilizzano molto Cloud Tasks
- Spostare il traffico tra le 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 casi e in altri, segui il pattern 500/50/5.
Aumento iniziale della coda
Il pattern 500/50/5 si applica alle code che operano già in uno stato stabile. L'avvio iniziale di una coda fredda è un processo indipendente progettato per raggiungere in sicurezza lo stato stazionario iniziale.
Quando una coda è nuova o è rimasta inattiva, non distribuisce immediatamente le attività alla frequenza maxDispatchesPerSecond configurata. Per proteggere il sistema da improvvisi picchi di traffico, Cloud Tasks aumenta gradualmente la frequenza di invio.
Se hai un tasso di creazione delle attività costante, il sistema alla fine aumenterà fino al tasso di distribuzione configurato. Tuttavia, se il tuo traffico è irregolare, con picchi di attività separati da più di una settimana di inattività, potresti notare in particolare questo comportamento di aumento graduale. Si tratta di un comportamento previsto che garantisce la stabilità.
Utilizzo della suddivisione del traffico di App Engine
Se le attività vengono create da un'app App Engine, puoi sfruttare la suddivisione del traffico di App Engine (Standard/Flex) per attenuare gli aumenti di traffico. Suddividendo il traffico tra le versioni (Standard/Flex), le richieste che devono essere gestite in base alla frequenza possono essere aumentate nel tempo per proteggere l'integrità della coda. Ad esempio, considera il caso di aumento del traffico verso un gruppo di code appena espanso: siano [queue0000, queue0199] una sequenza di code con TPS elevato che ricevono in totale 100.000 creazioni di TPS al picco.
Sia [queue0200, queue0399] una sequenza di nuove code. Dopo lo spostamento di tutto il traffico, 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 verso le nuove code utilizzando la suddivisione del traffico:
- Inizia a spostare l'1% del traffico sulla nuova release. Ad esempio,il 50% dell'1% di 100.000 TPS produce 500 TPS per l'insieme di nuove code.
- Ogni 5 minuti, aumenta del 50% il traffico inviato alla nuova release, come indicato nella tabella seguente:
| Minuti dall'inizio del deployment | % del traffico totale spostato sulla 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 basati sulle uscite
Quando lanci una release che aumenta in modo significativo il traffico verso una coda o un gruppo di code, l'implementazione graduale è, ancora una volta, un meccanismo importante per attenuare gli aumenti. Implementa gradualmente le tue istanze in modo che l'avvio iniziale non superi le 500 operazioni totali nelle nuove code, aumentando non più del 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. Avvia nuovi servizi o servizi aggiornati, che creano code o gruppi di code con un numero elevato di TPS, in modo che il carico iniziale sia inferiore a 500 TPS e gli aumenti del 50% o meno siano scaglionati a intervalli di almeno 5 minuti.
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 non 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 dei gruppi di code, l'implementazione graduale è ancora una strategia importante. Se la sorgente del traffico è App Engine, puoi utilizzare la suddivisione del traffico (vedi Picchi di traffico basati sulle release). Quando esegui la migrazione del servizio per aggiungere attività al numero maggiore di code, esegui il rollout graduale delle istanze in modo che l'avvio iniziale non superi le 500 operazioni totali nelle nuove code, aumentando non più del 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ù rapidamente di quanto il gruppo possa distribuirle. Se i nomi delle nuove code sono distribuiti in modo uniforme tra i nomi delle code esistenti quando vengono ordinati in ordine lessicografico, il traffico può essere inviato immediatamente a queste code, a condizione che non ci siano più del 50% di nuove code interleaved e che il traffico verso ogni coda sia inferiore a 500 TPS. Questo metodo è un'alternativa all'utilizzo della divisione del traffico e dell'implementazione graduale descritti nelle sezioni precedenti.
Questo tipo di denominazione intercalata 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] come nuovi nomi delle code, anziché [queue0200-queue0299].
Se hai bisogno di un ulteriore aumento, puoi comunque alternare fino al 50% di code in più ogni 5 minuti.
Accodamenti di attività su larga scala/batch
Quando è necessario aggiungere un numero elevato di attività, ad esempio milioni o miliardi, può essere utile un pattern di doppia iniezione. Anziché creare attività da un singolo job, utilizza una coda di inserimento. Ogni attività aggiunta alla coda dell'injector si espande e aggiunge 100 attività alla coda o al gruppo di code pertinente. La coda dell'injector può essere accelerata nel tempo, ad esempio inizia a 5 TPS, poi aumenta del 50% ogni 5 minuti.
Attività denominate
Quando crei una nuova attività, Cloud Tasks le assegna un nome univoco per impostazione predefinita. Puoi assegnare il tuo nome a un'attività utilizzando il parametro name. Tuttavia, ciò introduce un overhead delle prestazioni significativo, con conseguente aumento delle latenze e potenzialmente dei tassi di errore associati alle attività denominate. Questi costi possono aumentare in modo significativo se le attività vengono denominate in sequenza, ad esempio con i timestamp. Pertanto, se assegni i tuoi nomi, 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 di un nome a un'attività.
Target overload
Cloud Tasks può sovraccaricare altri servizi che utilizzi, 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ò potenzialmente 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. Per monitorare in modo proattivo gli aumenti del traffico, utilizza le metriche di Cloud Monitoring. Puoi utilizzare gli avvisi di Cloud Monitoring per rilevare situazioni potenzialmente pericolose.
Annullamento della pausa o ripresa delle code ad alto TPS
Quando una coda o una serie di code viene riattivata o riabilitata, le code riprendono
l'invio. Se la coda ha molte attività, la velocità di distribuzione della coda appena attivata
potrebbe aumentare notevolmente da 0 TPS alla piena capacità della coda. Per
aumentare gradualmente, scaglionare la ripresa delle code o controllare le velocità di distribuzione delle code utilizzando maxDispatchesPerSecond di Cloud Tasks.
Attività pianificate collettive
Un numero elevato di attività, la cui spedizione è pianificata contemporaneamente, può anche introdurre un rischio di sovraccarico della destinazione. Se devi avviare un numero elevato di attività contemporaneamente, valuta la possibilità di utilizzare i controlli della frequenza della coda per aumentare gradualmente la frequenza di distribuzione o aumentare esplicitamente la capacità target in anticipo.
Aumento del fan-out
Quando aggiorni i servizi eseguiti tramite Cloud Tasks, l'aumento del 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 significativamente il costo della chiamata /task-foo
se, ad esempio, aggiunge diversi costosi chiamate Datastore al gestore. Il risultato netto di un rilascio di questo tipo sarebbe un aumento massiccio del traffico 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 durante l'esecuzione di chiamate all'API Cloud Tasks. Tuttavia, quando una parte significativa delle richieste non va a buon fine a causa di errori lato server, un alto tasso di nuovi tentativi può sovraccaricare ulteriormente le code e farle recuperare più lentamente. Pertanto, ti consigliamo di limitare la quantità di traffico in uscita se il client rileva che una parte significativa delle richieste non va a buon fine a causa di errori lato server, ad esempio utilizzando l'algoritmo di limitazione adattiva descritto nel capitolo Gestione del sovraccarico del libro Site Reliability Engineering. Le librerie client gRPC di Google implementano una variante di questo algoritmo.