Rate Limiting в Kotlin: библиотеки, стратегии и практические примеры
Rate limiting (ограничение скорости запросов) — критически важный механизм для защиты API, микросервисов и веб-приложений от чрезмерной нагрузки, DDoS-атак и случайных всплесков трафика. В экосистеме Kotlin, работающей поверх JVM, существует несколько зрелых библиотек, которые позволяют гибко реализовать эту логику. В этой статье мы разберём три основных подхода и инструмента: Bucket4j, Resilience4j и встроенный RateLimiter из Guava.
1. Bucket4j — продвинутая реализация Token Bucket
Bucket4j — это Java-библиотека, идеально совместимая с Kotlin. Она реализует алгоритм Token Bucket (корзина токенов) и поддерживает как локальное, так и распределённое ограничение (через Redis, Hazelcast, Infinispan).
Ключевые возможности:
- Настройка количества токенов и скорости их пополнения.
- Поддержка «burst» (кратковременных всплесков) за счёт накопления токенов.
- Работа в многопоточном окружении без блокировок.
- Интеграция с Spring Boot через стартер
bucket4j-spring-boot-starter.
Пример простого rate limiter в Kotlin:
import io.github.bucket4j.Bandwidth
import io.github.bucket4j.Bucket
import io.github.bucket4j.Refill
import java.time.Duration
fun main() {
// 10 запросов в минуту, с возможностью накопления до 20 токенов
val limit = Bandwidth.classic(20, Refill.greedy(10, Duration.ofMinutes(1)))
val bucket = Bucket.builder()
.addLimit(limit)
.build()
// Проверяем доступность токена
if (bucket.tryConsume(1)) {
println("✅ Запрос разрешён")
} else {
println("❌ Превышен лимит, попробуйте позже")
}
}
Для распределённого сценария (например, несколько экземпляров микросервиса) используйте Bucket4j с Redis:
import io.github.bucket4j.distributed.proxy.ProxyManager
import io.github.bucket4j.redis.lettuce.Bucket4jLettuce
import io.lettuce.core.RedisClient
val redisClient = RedisClient.create("redis://localhost:6379")
val proxyManager: ProxyManager<String> = Bucket4jLettuce
.builder(redisClient)
.build()
val bucket = proxyManager.builder()
.build("user:123", Bucket4jConfiguration(
Bandwidth.classic(100, Refill.intervally(100, Duration.ofMinutes(1)))
))
2. Resilience4j — RateLimiter как часть Circuit Breaker
Resilience4j — это популярная библиотека устойчивости для Java/Kotlin, включающая не только rate limiter, но и circuit breaker, retry, bulkhead. Её модуль RateLimiter работает на основе алгоритма Sliding Window (скользящее окно).
Особенности:
- Лёгкая интеграция с корутинами Kotlin через
suspendфункции. - Настройка периода окна и лимита запросов.
- Гибкая обработка отказов: возврат исключения, fallback или ожидание.
Пример с корутинами:
import io.github.resilience4j.ratelimiter.RateLimiter
import io.github.resilience4j.ratelimiter.RateLimiterConfig
import io.github.resilience4j.kotlin.ratelimiter.awaitRateLimiter
import java.time.Duration
import kotlinx.coroutines.runBlocking
val config = RateLimiterConfig.custom()
.limitForPeriod(10) // 10 запросов
.limitRefreshPeriod(Duration.ofSeconds(1)) // за 1 секунду
.timeoutDuration(Duration.ofMillis(500)) // таймаут ожидания
.build()
val rateLimiter = RateLimiter.of("api-limiter", config)
suspend fun fetchData(): String {
return awaitRateLimiter(rateLimiter) {
// Ваш API-вызов
"Данные получены"
}
}
fun main() = runBlocking {
val result = fetchData()
println(result)
}
3. Google Guava RateLimiter — простота и скорость
Встроенный RateLimiter из библиотеки Guava — самый лёгкий вариант для простых сценариев. Он использует Token Bucket с плавным пополнением (smooth burst). Однако он не поддерживает распределённое состояние.
Пример использования:
import com.google.common.util.concurrent.RateLimiter
fun main() {
val limiter = RateLimiter.create(5.0) // 5 запросов в секунду Также в библиотеке
Работа с S3 и облачными хранилищами в TypeScript: библиотеки и примеры
Генерация PDF-отчётов на C++ с libharu и PoDoFo