Limitador de Tasa Distribuido

Un limitador de tasa de ventana deslizante respaldado por Redis para servicios Go escalados horizontalmente.

Repositorio

Demo de terminal: Limitador de Tasa Distribuido

Este proyecto implementa un limitador de tasa de ventana deslizante que guarda marcas de tiempo de solicitudes en sorted sets de Redis, de modo que cada instancia de la aplicación evalúa el mismo contador compartido. Cada decisión elimina entradas expiradas, cuenta los hits restantes dentro de la ventana activa y registra la solicitud actual con un TTL que limita el crecimiento del almacenamiento.

El diseño es deliberadamente pequeño: Redis aporta ordenamiento casi atómico mediante un pipeline transaccional, mientras Go mantiene una interfaz sincrónica fácil de envolver en handlers HTTP o interceptores RPC. Las solicitudes denegadas eliminan su entrada tentativa después de completar el pipeline, manteniendo la ventana precisa sin coordinación entre clientes.

func Allow(ctx context.Context, rdb *redis.Client, key string, limit int, window time.Duration) (bool, error) {
	now := time.Now()
	cutoff := now.Add(-window).UnixMilli()
	member := strconv.FormatInt(now.UnixNano(), 10)

	pipe := rdb.TxPipeline()
	pipe.ZRemRangeByScore(ctx, key, "0", strconv.FormatInt(cutoff, 10))
	count := pipe.ZCard(ctx, key)
	pipe.ZAdd(ctx, key, redis.Z{Score: float64(now.UnixMilli()), Member: member})
	pipe.Expire(ctx, key, window)
	if _, err := pipe.Exec(ctx); err != nil {
		return false, err
	}
	if count.Val() >= int64(limit) {
		_ = rdb.ZRem(ctx, key, member).Err()
		return false, nil
	}
	return true, nil
}
RedisLimitadorClienteRedisLimitadorClientealt[bajo el límite][sobre el límite]Solicitud con identidadRecortar ventana y contar hitsConteo actualRegistrar hit con TTLPermitirDenegar