Limitación de Tasa en Kotlin: bibliotecas, estrategias y ejemplos prácticos
\n\nLa limitación de tasa (rate limiting) es un mecanismo críticamente importante para proteger API, microservicios y aplicaciones web contra cargas excesivas, ataques DDoS y picos repentinos de tráfico. En el ecosistema de Kotlin, que funciona sobre la JVM, existen varias bibliotecas maduras que permiten implementar esta lógica de forma flexible. En este artículo, analizaremos tres enfoques y herramientas principales: Bucket4j, Resilience4j y el RateLimiter integrado de Guava.
\n\n1. Bucket4j — implementación avanzada de Token Bucket
\n\nBucket4j es una biblioteca de Java, perfectamente compatible con Kotlin. Implementa el algoritmo Token Bucket (cubo de fichas) y admite limitación tanto local como distribuida (a través de Redis, Hazelcast, Infinispan).
\n\nCaracterísticas clave:
\n- \n
- Configuración de la cantidad de tokens y su velocidad de reposición. \n
- Soporte para ráfagas (bursts) mediante la acumulación de tokens. \n
- Funcionamiento en entornos multiproceso sin bloqueos. \n
- Integración con Spring Boot a través del starter
bucket4j-spring-boot-starter. \n
Ejemplo de un limitador de tasa simple en Kotlin:
\nimport io.github.bucket4j.Bandwidth\nimport io.github.bucket4j.Bucket\nimport io.github.bucket4j.Refill\nimport java.time.Duration\n\nfun main() {\n // 10 solicitudes por minuto, con posibilidad de acumular hasta 20 tokens\n val limit = Bandwidth.classic(20, Refill.greedy(10, Duration.ofMinutes(1)))\n val bucket = Bucket.builder()\n .addLimit(limit)\n .build()\n\n // Verificar disponibilidad de token\n if (bucket.tryConsume(1)) {\n println("✅ Solicitud permitida")\n } else {\n println("❌ Límite excedido, intente más tarde")\n }\n}\n\nPara un escenario distribuido (por ejemplo, varias instancias de un microservicio) use Bucket4j con Redis:
\nimport io.github.bucket4j.distributed.proxy.ProxyManager\nimport io.github.bucket4j.redis.lettuce.Bucket4jLettuce\nimport io.lettuce.core.RedisClient\n\nval redisClient = RedisClient.create("redis://localhost:6379")\nval proxyManager: ProxyManager<String> = Bucket4jLettuce\n .builder(redisClient)\n .build()\n\nval bucket = proxyManager.builder()\n .build("user:123", Bucket4jConfiguration(\n Bandwidth.classic(100, Refill.intervally(100, Duration.ofMinutes(1)))\n ))\n\n\n2. Resilience4j — RateLimiter como parte de Circuit Breaker
\n\nResilience4j es una popular biblioteca de resiliencia para Java/Kotlin que incluye no solo un limitador de tasa, sino también circuit breaker, retry y bulkhead. Su módulo RateLimiter funciona basado en el algoritmo Sliding Window (ventana deslizante).
Características:
\n- \n
- Fácil integración con corrutinas de Kotlin mediante funciones
suspend. \n - Configuración del período de ventana y el límite de solicitudes. \n
- Manejo flexible de fallos: devolución de excepción, fallback o espera. \n
Ejemplo con corrutinas:
\nimport io.github.resilience4j.ratelimiter.RateLimiter\nimport io.github.resilience4j.ratelimiter.RateLimiterConfig\nimport io.github.resilience4j.kotlin.ratelimiter.awaitRateLimiter\nimport java.time.Duration\nimport kotlinx.coroutines.runBlocking\n\nval config = RateLimiterConfig.custom()\n .limitForPeriod(10) // 10 solicitudes\n .limitRefreshPeriod(Duration.ofSeconds(1)) // por 1 segundo\n .timeoutDuration(Duration.ofMillis(500)) // tiempo de espera\n .build()\n\nval rateLimiter = RateLimiter.of("api-limiter", config)\n\nsuspend fun fetchData(): String {\n return awaitRateLimiter(rateLimiter) {\n // Su llamada a la API\n "Datos obtenidos"\n }\n}\n\nfun main() = runBlocking {\n val result = fetchData()\n p