Throttling – zpomalování API requestů v Node.JS

Dnes krátce a názorně, jak řešit zpomalení odesílání API requestů, aby nedocházelo k překročení limitů na službách třetích stran. Běžně totiž využívané aplikace mají nastavené omezení na počet přijatých požadavků tak, aby klienti nevytěžovali službu více, než mají zaplaceno. Například Google Maps API mají limit na 25’000 požadavků za den.

Vše uvedu na názorném příkladu, ale nejprve si řekněme způsoby, jak je možné zpomalení (čti „retardaci“) requestů nebo také throttling řešit? Je v zásadě 5 možností a jako vždy, výběr závisí na konkrétní situaci. Možné řešení tedy jsou:

  1. Nic neřešit a smířit se s chybovostí při překročení limitů.
  2. Odesílat requesty jako na běžícím páse a ty, co neprojdou, odeslat znovu.
  3. Odeslat najednou maximální počet requestů (maximum je limit na API), zbytek hodit do fronty a nastavit časový zámek, který uvolní frontu a tím odešle další dávku requestů.
  4. Requesty ukládat do fronty a jejich odesílání rozprostřít rovnoměrně do intervalu tak, aby nedocházelo k překročení limitů (menší zatížení API jak v předchozím případě, ale prodlužuje se doba čekání na vyřízení requestu).
  5. Kombinace předchozích dvou, alias rozložení většího počtu requestů do časového intervalu a odesílání po skupinách (asi nejvhodnější řešení při vyšší zátěži).

V mé aplikaci není kritická rychlost, a proto mi stačí, když se requesty rozprostřou do intervalu 60 requestů za sekundu (1 request za 16.7 ms). Celý proces je součástí větší aplikace, která implementuje automatický obchodní systém, pro naše účely z ní vyberu jen část zabývající se komunikací s API brokera, který zpracovává obchodní příkazy a načítání cen akcií.

A právě pro načítání cen jsem využil throttling, kdy 100 requestů (na načtení cen 100 akcií) odesílám zpožděně tak, aby se věšly do limitu 60 requestů za sekundu.

Pro implementaci jsem použil modul throttle-function, který throttling implementuje nějak takto:

  1. Na začátku je vytvořena prázdná fronta, která slouží pro ukládání čekajících requestů.
  2. Pokud je fronta požadavků prázdná a je spuštěný interval, zastav ho a nic nedělej.
  3. Pokud se má odeslat požadavek na API, přidej ho do fronty a spusť zpracovávající funkci v intervalu každých 17ms.
  4. Při každém běhu zpracovávající funkce vem jeden request z fronty a odešli ho na API.
  5. — toť vse —

Použití tohoto modulu je více než jednoduché, stačí do něj zabalit naši funkci pro komunikaci s API a nastavit limity:

var throttle = require("throttle-function");

// originalni funkce pro nacteni cen
var streamTickerOrig = function(symbol, market) {

// zavolame API aby nam poskytla cenu akcie na zvolenem trhu
ib.reqMktData(symbol, market);
console.log("Calling API at %d", Date.now());
};

// funkci obalime nasim mechanismem na zpomaleni requestu
var streamTicker = throttle(streamTickerOrig, {
// max 60 requestu za sekundu
window: 1,
limit: 60
});

// ukazka vytvoreni vice requestu na API a jejich automaticke
for(var i = 0; i < 10000; i++) {
streamTicker("APPL", false);
}

Tímto lze jednodušše omezit počet odeslaných requestů na API a zajistit tím tak rovnoměrné rozložení zátěže.

Pár slov závěrem..
Je samozřejmě možné, že v jedné aplikaci bude více míst, které chtějí komunikovat se stejnou API. Tyto místa by měly používat stejné rozhranní implementující throttling. V případě, že je více aplikací, měly by opět využívat jednu službu, přes kterou s API komunikují.

Modulů implementujících throttling v technologii Node.js je samozřejmě více. Na výběr máme například ze throttle.js, rest-throttler, mini-throttle, promise-throttle, node-rate-limiter, limiter, schedule-limiter, throttled-request, throttle-debounce… a milionu dalších z nichž zajímavým může být třeba throttled-request, který pracuje s modulem request, který je oblíben pro odesílání HTTP requestů.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *