Rate Limiting in Kotlin: Bibliotheken, Strategien und praktische Beispiele
\n\nRate Limiting (Begrenzung der Anfragegeschwindigkeit) ist ein kritischer Mechanismus zum Schutz von APIs, Microservices und Webanwendungen vor übermäßiger Last, DDoS-Angriffen und zufälligen Traffic-Spitzen. Im Kotlin-Ökosystem, das auf der JVM läuft, gibt es mehrere ausgereifte Bibliotheken, die eine flexible Implementierung dieser Logik ermöglichen. In diesem Artikel betrachten wir drei Hauptansätze und Werkzeuge: Bucket4j, Resilience4j und den integrierten RateLimiter aus Guava.
\n\n1. Bucket4j – Fortschrittliche Token-Bucket-Implementierung
\n\nBucket4j ist eine Java-Bibliothek, die perfekt mit Kotlin kompatibel ist. Sie implementiert den Token-Bucket-Algorithmus (Token-Eimer) und unterstützt sowohl lokale als auch verteilte Begrenzung (über Redis, Hazelcast, Infinispan).
\n\nWichtige Funktionen:
\n- \n
- Konfiguration der Token-Anzahl und ihrer Auffüllrate. \n
- Unterstützung von Bursts (kurzzeitigen Spitzen) durch Token-Akkumulation. \n
- Arbeit in einer Multithread-Umgebung ohne Sperren. \n
- Integration mit Spring Boot über den Starter
bucket4j-spring-boot-starter. \n
Einfaches Beispiel für einen Rate Limiter in 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 Anfragen pro Minute, mit der Möglichkeit, bis zu 20 Token zu akkumulieren\n val limit = Bandwidth.classic(20, Refill.greedy(10, Duration.ofMinutes(1)))\n val bucket = Bucket.builder()\n .addLimit(limit)\n .build()\n\n // Verfügbarkeit eines Tokens prüfen\n if (bucket.tryConsume(1)) {\n println("✅ Anfrage erlaubt")\n } else {\n println("❌ Limit überschritten, bitte später erneut versuchen")\n }\n}\n\nFür verteilte Szenarien (z. B. mehrere Microservice-Instanzen) verwenden Sie Bucket4j mit 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 als Teil des Circuit Breaker
\n\nResilience4j ist eine beliebte Bibliothek für Ausfallsicherheit in Java/Kotlin, die nicht nur einen Rate Limiter, sondern auch Circuit Breaker, Retry und Bulkhead umfasst. Ihr Modul RateLimiter basiert auf dem Sliding-Window-Algorithmus (gleitendes Fenster).
Besonderheiten:
\n- \n
- Einfache Integration mit Kotlin-Koroutinen über
suspend-Funktionen. \n - Konfiguration des Fensterzeitraums und des Anfragelimit. \n
- Flexible Fehlerbehandlung: Ausnahme auslösen, Fallback oder Warten. \n
Beispiel mit Koroutinen:
\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 Anfragen\n .limitRefreshPeriod(Duration.ofSeconds(1)) // pro 1 Sekunde\n .timeoutDuration(Duration.ofMillis(500)) // Timeout für Wartezeit\n .build()\n\nval rateLimiter = RateLimiter.of("api-limiter", config)\n\nsuspend fun fetchData(): String {\n return awaitRateLimiter(rateLimiter) {\n // Ihr API-Aufruf\n "Daten empfangen"\n }\n}\n\nfun main() = runBlocking {\n val result = fetchData()\n p