Přeskočit na hlavní obsah

Rate limiting

Konfigurace rate limitingu vám umožní omezit počet požadavků, které může uživatel provést za určitý časový úsek. Tímto způsobem můžete ochránit vaši aplikaci před DDoS útoky a zároveň zajistit, že API bude dostupné pro všechny uživatele.

Nastavení rate limitingu

Nejjednodušší možností, jak nastavit rate limiting bez zásahu do samotného kódu aplikace je využítí NGINX Rate Limiteru. Nejprve si ukážeme, jak vypadá stávající konfigurace NGINX, kterou používáme v našem Dockeru. V následujícím odstavci Vysvětlení direktiv a parametrů si pak vysvětlíme jak konfiguraci upravit.

Definice zóny

Téměř na konci bloku http v souboru docker/nginx/nginx.conf nelezneme definici zóny pro rate limiting:

docker/nginx/nginx.conf
http {
# ...

# Definice zóny pro rate limiting
limit_req_zone $http_x_real_ip zone=primaryZone:5m rate=10r/s;
}

Omezení endpointu

Téměř na konci bloku server v souboru docker/nginx/http.d/default.conf pak nalezneme konfiguraci pro konkrétní endpoint, kde chceme rate limiting aplikovat:

docker/nginx/http.d/default.conf
server {
# ...

location ~ \.php$ {
# ...

# Aplikace rate limitingu na konkrétní endpoint
# V tomto případě na všechny volání PHP skriptů

limit_req zone=primaryZone burst=5 nodelay;
}
}

Vysvětlení direktiv a parametrů

Direktiva limit_req_zone

Direktiva limit_req_zone je obvykle definována v bloku http, takže je dostupná pro použití ve více kontextech. Vyžaduje následující tři parametry:

  • key - Definuje charakteristiku požadavku, proti které je limit aplikován. V příkladu je to NGINX proměnná $http_x_real_ip, která obsahuje IP adresu klienta. To znamená, že omezujeme každou jedinečnou IP adresu. (Pokud by náš server neběžel v Dockeru za traefik proxy, bylo by mnohem vhodnější použít $binary_remote_addr, jenž reprezentuje IP adresu klienta v binární podobě a zabírá méně paměti.

  • zone - Definuje zónu sdílené paměti, která se používá k uložení stavu každé IP adresy a jak často přistupovala ke konkrétnímu endpointu. Uchovávání informací ve sdílené paměti znamená, že informace lze sdílet mezi procesy NGINX workerů. Definice má dvě části: název zóny identifikovaný klíčovým slovem zone= a velikost za dvojtečkou :. Informace o stavu pro 16 000 IPs v binární podobě zabere cca 1 MB. V případě použití $http_x_real_ip je IP reprezentována jako řetězec, takže je potřeba počítat s mnohem větší paměťovou náročností.

    Pokud je úložiště vyčerpáno a NGINX potřebuje přidat nový záznam, odstraní nejstarší záznam. Pokud uvolněné místo stále nestačí k uložení nového záznamu, NGINX vrátí stavový kód 503 (Service Temporarily Unavailable). Navíc, aby se zabránilo vyčerpání paměti, pokaždé, když NGINX vytvoří nový záznam, odstraní až dva záznamy, které nebyly použity v předchozích 60 sekundách.

  • rate - Nastavuje maximální rychlost požadavků. V příkladu nemůže rychlost překročit 10 požadavků za sekundu. NGINX ve skutečnosti sleduje požadavky s milisekundovou granularitou, takže tento limit odpovídá 1 požadavku každých 100 ms.

Direktiva limit_req_zone nastavuje parametry pro omezení rychlosti a zónu sdílené paměti. Ve skutečnosti ale neomezuje rychlost požadavků. K tomu je potřeba použít direktivu limit_req u konkrétního endpointu.

Direktiva limit_req

Direktiva limit_req omezuje rychlost požadavků na konkrétním endpointu. Má následující parametry:

  • zone - Přiřazuje zónu, která byla definována pomocí limit_req_zone.

  • burst - Umožňuje definovat, kolik požadavků nad rámec nastavené rychlosti (rate) může být dočasně akceptováno předtím, než NGINX začne vracet chybu 503. Tento mechanismus je užitečný pro absorbování nárazových zvýšení počtu požadavků, které jsou typické pro webové aplikace. Například, pokud je rate nastaven na 10 požadavků za sekundu a burst na 20, NGINX umožní přijmout 20 požadavků nad rámec normální rychlosti a zařadí je do fronty. Tyto požadavky jsou poté zpracovávány v intervalu určeném parametrem rate. Pokud počet požadavků v queue přesáhne limit nastavený v burst, začne NGINX vracet chybový kód 503.

  • delay / nodelay - Slouží k ovlivnění způsobu, jakým NGINX zpracovává požadavky ve frontě. Delay způsobí, že NGINX bude požadavky ve frontě postupně uvolňovat podle rychlosti nastavené v rate, což může způsobit zpoždění ve zpracování požadavků. Na druhou stranu, nodelay umožňuje NGINXu zpracovat všechny požadavky okamžitě, pokud je ve frontě volné místo. Požadavky jsou pak okamžitě předány bez zbytečného čekání, což znamená, že když přijde více požadavků najednou, NGINX je může všechny zpracovat hned, pokud existuje volný slot - pak postupně uvolňuje sloty podle rychlosti nastavené v rate. Toto nastavení je obzvláště užitečné pro minimalizaci latence a zajištění plynulého toku dat, aniž by se příliš omezovaly rozestupy mezi jednotlivými požadavky.

Zdroje