Modello di limitazione della velocità

Bus di servizio di Azure
Archiviazione code di Azure
Hub eventi di Azure

Molti servizi usano un modello di limitazione per controllare le risorse utilizzate, imponendo limiti alla frequenza con cui altre applicazioni o servizi possono accedervi. È possibile usare un modello di limitazione della velocità per evitare o ridurre al minimo gli errori di limitazione correlati a questi limiti di limitazione e per facilitare la stima più accurata della velocità effettiva.

Un modello di limitazione della frequenza è appropriato in molti scenari, ma è particolarmente utile per attività automatizzate ripetitive su larga scala, ad esempio l'elaborazione batch.

Contesto e problema

L'esecuzione di un numero elevato di operazioni tramite un servizio limitato può comportare un aumento del traffico e della velocità effettiva, perché sarà necessario tenere traccia delle richieste rifiutate e quindi ripetere le operazioni. Con l'aumentare del numero di operazioni, un limite di limitazione può richiedere più passaggi di invio di dati di nuovo, con un impatto maggiore sulle prestazioni.

Si consideri ad esempio il seguente tentativo ingenuo durante il processo di errore per l'inserimento di dati in Azure Cosmos DB:

  1. L'applicazione deve inserire 10.000 record in Azure Cosmos DB. Ogni record costa 10 unità richiesta (UR) per l'inserimento, richiedendo un totale di 100.000 UR per completare il processo.
  2. L'istanza di Azure Cosmos DB ha una capacità di provisioning di 20.000 UR.
  3. Tutti i 10.000 record vengono inviati ad Azure Cosmos DB. 2.000 record vengono scritti correttamente e vengono rifiutati 8.000 record.
  4. I rimanenti 8.000 record vengono inviati ad Azure Cosmos DB. 2.000 record vengono scritti correttamente e vengono rifiutati 6.000 record.
  5. Si inviano i 6.000 record rimanenti ad Azure Cosmos DB. 2.000 record vengono scritti correttamente e vengono rifiutati 4.000 record.
  6. Si inviano i 4.000 record rimanenti ad Azure Cosmos DB. 2.000 record vengono scritti correttamente e vengono rifiutati 2.000 record.
  7. Si inviano i 2.000 record rimanenti ad Azure Cosmos DB. Tutto viene scritto correttamente.

Il processo di inserimento è stato completato correttamente, ma solo dopo l'invio di 30.000 record ad Azure Cosmos DB anche se l'intero set di dati è costituito solo da 10.000 record.

Esistono altri fattori da considerare nell'esempio precedente:

  • Un numero elevato di errori può comportare anche operazioni aggiuntive per registrare questi errori ed elaborare i dati di log risultanti. Questo approccio ingenuo avrà gestito 20.000 errori e la registrazione di questi errori può imporre un costo di elaborazione, memoria o risorsa di archiviazione.
  • Non conoscendo i limiti di limitazione del servizio di inserimento, l'approccio ingenuo non ha modo di impostare le aspettative per quanto tempo richiederà l'elaborazione dei dati. La limitazione della frequenza consente di calcolare il tempo necessario per l'inserimento.

Soluzione

La limitazione della velocità può ridurre il traffico e migliorare potenzialmente la velocità effettiva riducendo il numero di record inviati a un servizio in un determinato periodo di tempo.

Un servizio può limitare la limitazione in base a metriche diverse nel tempo, ad esempio:

  • Numero di operazioni, ad esempio 20 richieste al secondo.
  • Quantità di dati (ad esempio, 2 GiB al minuto).
  • Costo relativo delle operazioni (ad esempio, 20.000 UR al secondo).

Indipendentemente dalla metrica usata per la limitazione delle richieste, l'implementazione della limitazione della velocità comporta il controllo del numero e/o delle dimensioni delle operazioni inviate al servizio in un periodo di tempo specifico, ottimizzando l'uso del servizio senza superare la capacità di limitazione.

Negli scenari in cui le API possono gestire le richieste più velocemente di qualsiasi servizio di inserimento limitato consentito, è necessario gestire la velocità con cui è possibile usare il servizio. Tuttavia, trattando solo la limitazione come un problema di mancata corrispondenza della frequenza dei dati e semplicemente memorizzando nel buffer le richieste di inserimento fino a quando il servizio limitato non può recuperare, è rischioso. Se l'applicazione si arresta in modo anomalo in questo scenario, si rischia di perdere uno qualsiasi di questi dati memorizzati nel buffer.

Per evitare questo rischio, prendere in considerazione l'invio dei record a un sistema di messaggistica durevole in grado di gestire la velocità di inserimento completa. (Servizi come Hub eventi di Azure possono gestire milioni di operazioni al secondo). È quindi possibile usare uno o più processori di processi per leggere i record dal sistema di messaggistica a una velocità controllata entro i limiti del servizio limitato. L'invio di record al sistema di messaggistica può salvare la memoria interna consentendo di rimuovere dalla coda solo i record che possono essere elaborati durante un determinato intervallo di tempo.

Azure offre diversi servizi di messaggistica durevole che è possibile usare con questo modello, tra cui:

Flusso di messaggistica durevole con tre processori di processo che chiamano in un servizio limitato.

Quando si inviano record, il periodo di tempo usato per il rilascio dei record può essere più granulare rispetto al periodo in cui il servizio limita. I sistemi spesso impostano limitazioni in base agli intervalli di tempo con cui è possibile comprendere e lavorare facilmente. Tuttavia, per il computer che esegue un servizio, questi intervalli di tempo possono essere molto lunghi rispetto alla velocità di elaborazione delle informazioni. Ad esempio, un sistema potrebbe limitare al secondo o al minuto, ma in genere il codice viene elaborato in base all'ordine di nanosecondi o millisecondi.

Sebbene non sia necessario, è spesso consigliabile inviare quantità di record più piccole con maggiore frequenza per migliorare la velocità effettiva. Pertanto, invece di provare a raggruppare le operazioni per una versione una volta al secondo o una volta al minuto, è possibile essere più granulari rispetto a quello per mantenere il consumo di risorse (memoria, CPU, rete e così via) che scorre a una velocità più uniforme, impedendo potenziali colli di bottiglia a causa di picchi improvvisi di richieste. Ad esempio, se un servizio consente 100 operazioni al secondo, l'implementazione di un limite di velocità può persino escludere le richieste rilasciando 20 operazioni ogni 200 millisecondi, come illustrato nel grafico seguente.

Grafico che mostra la limitazione della frequenza nel tempo.

Inoltre, a volte è necessario per più processi non coordinati condividere un servizio limitato. Per implementare la limitazione della frequenza in questo scenario, è possibile partizionare logicamente la capacità del servizio e quindi usare un sistema di esclusione reciproca distribuito per gestire blocchi esclusivi su tali partizioni. I processi non coordinati possono quindi competere per i blocchi su tali partizioni ogni volta che hanno bisogno di capacità. Per ogni partizione per cui un processo contiene un blocco, viene concessa una determinata quantità di capacità.

Ad esempio, se il sistema limitato consente 500 richieste al secondo, è possibile creare 20 partizioni che valgono 25 richieste al secondo ognuna. Se un processo necessario per inviare 100 richieste, potrebbe chiedere al sistema di esclusione reciproca distribuita quattro partizioni. Il sistema potrebbe concedere due partizioni per 10 secondi. Il processo quindi limita a 50 richieste al secondo, completa l'attività in due secondi e quindi rilascia il blocco.

Un modo per implementare questo modello consiste nell'usare Archiviazione di Azure. In questo scenario viene creato un BLOB a 0 byte per ogni partizione logica in un contenitore. Le applicazioni possono quindi ottenere lease esclusivi direttamente su tali BLOB per un breve periodo di tempo (ad esempio, 15 secondi). Per ogni lease viene concessa un'applicazione, sarà in grado di usare la capacità di tale partizione. L'applicazione deve quindi tenere traccia del tempo di lease in modo che, alla scadenza, possa smettere di usare la capacità concessa. Quando si implementa questo modello, è spesso necessario che ogni processo tenti di creare un lease di una partizione casuale quando richiede capacità.

Per ridurre ulteriormente la latenza, è possibile allocare una piccola quantità di capacità esclusiva per ogni processo. Un processo cercherà quindi di ottenere un lease sulla capacità condivisa solo se necessario per superare la capacità riservata.

Partizioni BLOB di Azure

In alternativa a Archiviazione di Azure, è anche possibile implementare questo tipo di sistema di gestione lease usando tecnologie come Zookeeper, Consul, etcd, Redis/Redsync e altri.

Considerazioni e problemi

Quando si decide come implementare questo modello, tenere presente quanto segue:

  • Anche se il modello di limitazione della frequenza può ridurre il numero di errori di limitazione, l'applicazione dovrà comunque gestire correttamente eventuali errori di limitazione che possono verificarsi.
  • Se l'applicazione ha più flussi di lavoro che accedono allo stesso servizio limitato, sarà necessario integrarli tutti nella strategia di limitazione della frequenza. Ad esempio, è possibile supportare il caricamento bulk di record in un database, ma anche l'esecuzione di query per i record nello stesso database. È possibile gestire la capacità assicurando che tutti i flussi di lavoro vengano gestiti tramite lo stesso meccanismo di limitazione della velocità. In alternativa, è possibile riservare pool di capacità separati per ogni flusso di lavoro.
  • Il servizio limitato può essere usato in più applicazioni. In alcuni casi, ma non tutti, è possibile coordinare tale utilizzo (come illustrato in precedenza). Se si inizia a visualizzare un numero di errori di limitazione superiore al previsto, potrebbe trattarsi di un segno di contesa tra le applicazioni che accedono a un servizio. In tal caso, potrebbe essere necessario prendere in considerazione la riduzione temporanea della velocità effettiva imposta dal meccanismo di limitazione della velocità fino a quando l'utilizzo di altre applicazioni non diminuisce.

Quando usare questo modello

Usare questo modello per:

  • Ridurre gli errori di limitazione generati da un servizio con limitazioni.
  • Ridurre il traffico rispetto a un tentativo ingenuo sull'approccio di errore.
  • Ridurre il consumo di memoria dequeundo i record solo quando è disponibile la capacità di elaborarli.

Progettazione del carico di lavoro

Un architetto deve valutare il modo in cui il modello di limitazione della frequenza può essere usato nella progettazione del carico di lavoro per soddisfare gli obiettivi e i principi trattati nei pilastri di Azure Well-Architected Framework. Ad esempio:

Concetto fondamentale Come questo modello supporta gli obiettivi di pilastro
Le decisioni di progettazione dell'affidabilità consentono al carico di lavoro di diventare resilienti a malfunzionamenti e di assicurarsi che venga ripristinato in uno stato completamente funzionante dopo che si verifica un errore. Questa tattica protegge il client riconoscendo e rispettando le limitazioni e i costi di comunicazione con un servizio quando il servizio desidera evitare un utilizzo eccessivo.

- RE:07 Conservazione automatica

Come per qualsiasi decisione di progettazione, prendere in considerazione eventuali compromessi rispetto agli obiettivi degli altri pilastri che potrebbero essere introdotti con questo modello.

Esempio

L'applicazione di esempio seguente consente agli utenti di inviare record di vari tipi a un'API. È disponibile un processore di processi univoco per ogni tipo di record che esegue i passaggi seguenti:

  1. Convalida
  2. Arricchimento
  3. Inserimento del record nel database

Tutti i componenti dell'applicazione (API, processore di processi A e processore di processi B) sono processi separati che possono essere ridimensionati in modo indipendente. I processi non comunicano direttamente tra loro.

Flusso multi-coda multiprocessore con archiviazione partizionata per i lease, scrittura in un database.

Questo diagramma incorpora il flusso di lavoro seguente:

  1. Un utente invia 10.000 record di tipo A all'API.
  2. L'API accoda tali 10.000 record nella coda A.
  3. Un utente invia 5.000 record di tipo B all'API.
  4. L'API accoda tali 5.000 record nella coda B.
  5. Il processore di processi A vede la coda A contiene record e tenta di ottenere un lease esclusivo nel BLOB 2.
  6. Il processore di processi B vede che la coda B contiene record e tenta di ottenere un lease esclusivo nel BLOB 2.
  7. Processore di processi A non riesce a ottenere il lease.
  8. Processore di processi B ottiene il lease nel BLOB 2 per 15 secondi. Ora può limitare le richieste al database a una velocità di 100 al secondo.
  9. Processore di processi B rimuove dalla coda B 100 record dalla coda B e li scrive.
  10. Un secondo passa.
  11. Il processore di processi A vede la coda A ha più record e tenta di ottenere un lease esclusivo nel BLOB 6.
  12. Il processore di processi B vede che la coda B ha più record e tenta di ottenere un lease esclusivo nel BLOB 3.
  13. Processore di processi A ottiene il lease nel BLOB 6 per 15 secondi. Ora può limitare le richieste al database a una velocità di 100 al secondo.
  14. Il processore di processi B ottiene il lease nel BLOB 3 per 15 secondi. Ora può limitare le richieste al database a una velocità di 200 al secondo. Contiene anche il lease per BLOB 2.
  15. Elaborazione processi A rimuove dalla coda A 100 record dalla coda A e li scrive.
  16. Processore di processi B rimuove dalla coda B 200 record dalla coda B e li scrive.
  17. Un secondo passa.
  18. Il processore di processi A vede la coda A ha più record e tenta di ottenere un lease esclusivo nel BLOB 0.
  19. Il processore di processi B vede che la coda B ha più record e tenta di ottenere un lease esclusivo nel BLOB 1.
  20. Processore di processi A ottiene il lease nel BLOB 0 per 15 secondi. Ora può limitare le richieste al database a una velocità di 200 al secondo. Contiene anche il lease per BLOB 6.
  21. Processore di processi B ottiene il lease nel BLOB 1 per 15 secondi. Ora può limitare le richieste al database a una velocità di 300 al secondo. Contiene anche il lease per i BLOB 2 e 3.
  22. Elaborazione processi A rimuove dalla coda A 200 record dalla coda A e li scrive.
  23. Processore di processi B rimuove dalla coda B 300 record dalla coda B e li scrive.
  24. E così via.

Dopo 15 secondi, uno o entrambi i processi non verranno ancora completati. Quando i lease scadono, un processore deve anche ridurre il numero di richieste che rimuove dalla coda e scrive.

Logo di GitHub Le implementazioni di questo modello sono disponibili in linguaggi di programmazione diversi:

  • L'implementazione di Go è disponibile in GitHub.
  • L'implementazione java è disponibile in GitHub.

Per l'implementazione di questo modello possono risultare utili i modelli e le informazioni aggiuntive seguenti:

  • Limitazione. Il modello di limitazione della velocità descritto di seguito viene in genere implementato in risposta a un servizio limitato.
  • Nuovo tentativo. Quando le richieste al servizio limitato generano errori di limitazione, è in genere consigliabile riprovare dopo un intervallo appropriato.

Il livellamento del carico basato su coda è simile ma differisce dal modello di limitazione della frequenza in diversi modi principali:

  1. La limitazione della frequenza non deve necessariamente usare le code per gestire il carico, ma deve usare un servizio di messaggistica durevole. Ad esempio, un modello di limitazione della frequenza può usare servizi come Apache Kafka o Hub eventi di Azure.
  2. Il modello di limitazione della velocità introduce il concetto di sistema di esclusione reciproca distribuita nelle partizioni, che consente di gestire la capacità per più processi non coordinati che comunicano con lo stesso servizio limitato.
  3. Un modello di livellamento del carico basato su coda è applicabile ogni volta che si verifica una mancata corrispondenza delle prestazioni tra i servizi o per migliorare la resilienza. In questo modo è un modello più ampio rispetto alla limitazione della frequenza, che è più specificamente interessato all'accesso efficiente a un servizio limitato.