Molti servizi usano un modello di limitazione per controllare le risorse usate, imponendo limiti alla frequenza in cui altre applicazioni o servizi possono accedervi. È possibile usare un modello di limitazione della frequenza 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à ripetitive 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 tali operazioni. Poiché il numero di operazioni aumenta, un limite di limitazione può richiedere più passaggi di dati di nuovo, causando un impatto maggiore sulle prestazioni.
Ad esempio, prendere in considerazione il seguente tentativo ingenuo sul processo di errore per inserire dati in Azure Cosmos DB:
- L'applicazione deve inserire 10.000 record in Azure Cosmos DB. Ogni record costa 10 unità richiesta (UR) per inserire, richiedendo un totale di 100.000 UR per completare il processo.
- L'istanza di Azure Cosmos DB ha una capacità di provisioning di 20.000 UR.
- Inviare tutti i 10.000 record ad Azure Cosmos DB. 2.000 record vengono scritti correttamente e vengono rifiutati 8.000 record.
- Si inviano i 8.000 record rimanenti ad Azure Cosmos DB. 2.000 record vengono scritti correttamente e vengono rifiutati 6.000 record.
- Si inviano i 6.000 record rimanenti ad Azure Cosmos DB. 2.000 record vengono scritti correttamente e vengono rifiutati 4.000 record.
- Si inviano i 4.000 record rimanenti ad Azure Cosmos DB. 2.000 record vengono scritti correttamente e vengono rifiutati 2.000 record.
- Si inviano i 2.000 record rimanenti ad Azure Cosmos DB. Tutti vengono scritti 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 l'elaborazione dei dati richiederà. La limitazione della frequenza può consentire di calcolare il tempo necessario per l'inserimento.
Soluzione
La limitazione della frequenza 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 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 della velocità, l'implementazione della limitazione della frequenza comporta il controllo del numero e/o della dimensione delle operazioni inviate al servizio in un periodo di tempo specifico, ottimizzando l'uso del servizio mentre non supera 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 il modo in cui è possibile usare il servizio. Tuttavia, trattando solo la limitazione come un problema di mancata corrispondenza della frequenza dei dati e semplicemente buffering delle 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 dei dati memorizzati nel buffer.
Per evitare questo rischio, prendere in considerazione l'invio dei record a un sistema di messaggistica durevole che può 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 processo per leggere i record dal sistema di messaggistica a una frequenza controllata entro i limiti del servizio limitato. L'invio di record al sistema di messaggistica può salvare la memoria interna consentendo di dequeuere solo i record che possono essere elaborati durante un determinato intervallo di tempo.
Azure offre diversi servizi di messaggistica durevoli che è possibile usare con questo modello, tra cui:
Quando si inviano record, il periodo di tempo usato per il rilascio dei record può essere più granulare del periodo in cui il servizio limita. I sistemi spesso impostano limitazioni in base ai tempi in cui è possibile comprendere e lavorare facilmente. Tuttavia, per il computer che esegue un servizio, questi intervalli di tempo possono essere molto lunghi rispetto al modo in cui può elaborare le informazioni. Ad esempio, un sistema potrebbe limitare al secondo o al minuto, ma in genere il codice sta elaborando sull'ordine di nanosecondi o millisecondi.
Anche se non è necessario, è spesso consigliabile inviare quantità più piccole di record più frequentemente per migliorare la velocità effettiva. Invece di provare a eseguire il batch di elementi per una versione una volta al secondo o una volta al minuto, è possibile essere più granulari di 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 improvvisi picchi di richieste. Ad esempio, se un servizio consente 100 operazioni al secondo, l'implementazione di un limite di frequenza può anche uscire dalle richieste rilasciando 20 operazioni ogni 200 millisecondi, come illustrato nel grafico seguente.
Inoltre, a volte è necessario per più processi non coordinati per 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 in tali partizioni. I processi non coordinati possono quindi competere per i blocchi su tali partizioni ogni volta che necessitano 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 vale 25 richieste al secondo. Se un processo necessario per inviare 100 richieste, potrebbe richiedere il sistema di esclusione reciproca distribuito per 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 a cui 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 interrompere l'uso della capacità concessa. Quando si implementa questo modello, si vuole spesso che ogni processo tenti di eseguire il lease di una partizione casuale quando necessita della 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 se necessario per superare la capacità riservata.
In alternativa all'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, prendere in considerazione 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 potrebbero verificarsi.
- Se l'applicazione dispone di più flussi di lavoro che accedono allo stesso servizio limitato, sarà necessario integrarli nella strategia di limitazione della frequenza. Ad esempio, è possibile supportare il caricamento bulk dei record in un database, ma anche la query per i record nello stesso database. È possibile gestire la capacità assicurando che tutti i flussi di lavoro siano vincolati tramite lo stesso meccanismo di limitazione della frequenza. In alternativa, è possibile riservare pool separati di capacità 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 sopra). Se si inizia a visualizzare un numero maggiore di errori di limitazione previsti, potrebbe trattarsi di un segno di contesa tra applicazioni che accedono a un servizio. In tal caso, potrebbe essere necessario considerare la riduzione temporanea della velocità effettiva imposta dal meccanismo di limitazione della frequenza fino a quando l'utilizzo da altre applicazioni è inferiore.
Quando usare questo modello
Usare questo modello per:
- Ridurre gli errori di limitazione generati da un servizio limitato a limitazione.
- Ridurre il traffico rispetto a un tentativo ingenuo sull'approccio di errore.
- Ridurre il consumo di memoria dequeuando i record solo quando è disponibile la capacità di elaborarli.
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 la procedura seguente:
- Convalida
- Arricchimento
- 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.
Questo diagramma incorpora il flusso di lavoro seguente:
- Un utente invia 10.000 record di tipo A all'API.
- L'API esegue tali 10.000 record in Coda A.
- Un utente invia 5.000 record di tipo B all'API.
- L'API esegue l'esecuzione di tali 5.000 record nella coda B.
- Job Processor A vede la coda A ha record e tenta di ottenere un lease esclusivo nel BLOB 2.
- Il processore di processi B vede la coda B ha record e tenta di ottenere un lease esclusivo nel BLOB 2.
- Il processore di processi A non riesce a ottenere il lease.
- Job Processor B ottiene il lease nel BLOB 2 per 15 secondi. È ora possibile limitare le richieste al database a una frequenza di 100 al secondo.
- Elaborazione processi B dequeues 100 record dalla coda B e li scrive.
- Un secondo passa.
- Il processore di processi A vede la coda A ha più record e tenta di ottenere un lease esclusivo nel BLOB 6.
- Il processore di processi B vede la coda B ha più record e tenta di ottenere un lease esclusivo nel BLOB 3.
- Job Processor A ottiene il lease nel BLOB 6 per 15 secondi. È ora possibile limitare le richieste al database a una frequenza di 100 al secondo.
- Il processore di processi B ottiene il lease nel BLOB 3 per 15 secondi. Ora può limitare le richieste al database a una frequenza di 200 al secondo. Contiene anche il lease per BLOB 2.
- Elaborazione processi A dequeues 100 record dalla coda A e li scrive.
- Elaborazione processi B dequeue 200 record dalla coda B e li scrive.
- Un secondo passa.
- Il processore di processi A vede la coda A ha più record e tenta di ottenere un lease esclusivo nel BLOB 0.
- Il processore di processi B vede la coda B ha più record e tenta di ottenere un lease esclusivo nel BLOB 1.
- Job Processor A ottiene il lease sul BLOB 0 per 15 secondi. Ora può limitare le richieste al database a una frequenza di 200 al secondo. Contiene anche il lease per BLOB 6.
- Job Processor B ottiene il lease nel BLOB 1 per 15 secondi. Ora può limitare le richieste al database a una frequenza di 300 al secondo. Contiene anche il lease per i BLOB 2 e 3.
- Elaborazione processi A dequeues 200 record dalla coda A e li scrive.
- Job Processor B dequeues 300 record dalla coda B e li scrive.
- E così via.
Dopo 15 secondi, uno o entrambi i processi non verranno ancora completati. Al termine dei lease, un processore deve anche ridurre il numero di richieste che dequeue e scrive.
Un'implementazione di questo modello, implementata in Go, è disponibile in GitHub.
Risorse correlate
Per l'implementazione di questo modello possono risultare utili i modelli e le informazioni aggiuntive seguenti:
- Limitazione delle richieste. Il modello di limitazione della frequenza illustrato qui viene in genere implementato in risposta a un servizio limitato.
- Riprovare. Quando le richieste al servizio limitato comportano errori di limitazione, è in genere consigliabile ripetere i tentativi dopo un intervallo appropriato.
Il livello di carico basato su coda è simile ma è diverso dal modello di limitazione della frequenza in diversi modi chiave:
- 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.
- Il modello di limitazione della frequenza introduce il concetto di un 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.
- Un modello di livello di carico basato su coda è applicabile ogni volta che si verifica una mancata corrispondenza delle prestazioni tra i servizi o per migliorare la resilienza. Ciò rende questo modello più ampio rispetto alla limitazione della frequenza, che è più specificamente interessato all'accesso efficiente a un servizio limitato.