Rate Limiting del Proxy
Rate limiting por IP usando una ventana deslizante. Cuenta requests en ventanas de 1 segundo; devuelve HTTP 429 al superarse el límite. Para rate limiting distribuido entre múltiples instancias del proxy, usar nyx-kv INCR + EXPIRE.
Código
// nyx-proxy rate limiting — per-IP sliding window
// Rate limiting nyx-proxy — ventana deslizante por IP
var ip_counts: Map = Map.new()
var window_start: Map = Map.new()
fn now_seconds() -> int {
return time()
}
// Check if an IP has exceeded the rate limit
// Returns true if allowed, false if rate-limited
fn rate_check(ip: String, max_per_sec: int) -> bool {
let now: int = now_seconds()
// Initialize window if new IP
if not ip_counts.contains(ip) {
ip_counts.insert(ip, "1")
window_start.insert(ip, int_to_string(now))
return true
}
// Reset window if more than 1 second elapsed
let start_s: String = window_start.get(ip)
let start: int = string_to_int(start_s)
if now - start >= 1 {
ip_counts.insert(ip, "1")
window_start.insert(ip, int_to_string(now))
return true
}
// Increment count
let count_s: String = ip_counts.get(ip)
let count: int = string_to_int(count_s) + 1
ip_counts.insert(ip, int_to_string(count))
return count <= max_per_sec
}
fn main() -> int {
let max_rps: int = 5 // allow 5 requests per second per IP
let ip: String = "192.168.1.100"
// Simulate 8 rapid requests from the same IP
var i: int = 0
while i < 8 {
let ok: bool = rate_check(ip, max_rps)
if ok {
print("request " + int_to_string(i + 1) + ": ALLOWED")
} else {
print("request " + int_to_string(i + 1) + ": 429 Too Many Requests")
}
i = i + 1
}
return 0
}
Salida
request 1: ALLOWED request 2: ALLOWED request 3: ALLOWED request 4: ALLOWED request 5: ALLOWED request 6: 429 Too Many Requests request 7: 429 Too Many Requests request 8: 429 Too Many Requests
Explicación
El rate limiting es la primera línea de defensa tanto contra el abuso como contra clientes descontrolados. El contador de ventana fija que se ve aquí es la implementación más simple: para cada IP, recordar cuándo empezó su ventana y cuántos requests han llegado; reiniciar el contador en cada segundo nuevo. No es perfecto — un cliente que golpea el límite exacto puede llegar a ráfagas de 2x el límite — pero es barato y suficientemente bueno para la mayoría de los proxies. En un despliegue con múltiples instancias los contadores se desincronizan porque cada instancia solo ve su propio tráfico; la solución es mantener los conteos en nyx-kv con INCR + EXPIRE para que todas las instancias compartan una única vista. Para una equidad más estricta, el token bucket o una ventana deslizante real son los siguientes pasos.