山东大学-创新实训-智评Code+:基于DeepSeek的AI代码纠错与优化评测平台-(5)提交限流设计

限流设计:保护系统的第一道防线

为了防止用户频繁提交、滥用评测资源,智评 Code+ 实现了一套基于 Redis 的用户提交限流中间件。它作为中间件插入每次提交请求中,在高并发场景下起到了良好的流量控制作用。

为什么需要限流?

  • 保护评测资源:每次代码提交会触发 Docker 评测,成本较高;

  • 防刷防误触:避免用户频繁提交影响他人评测任务;

  • 保障系统稳定性:防止 Redis 队列和数据库在短时间内被刷爆。


实现方式:Redis 计数 + 过期时间窗口

核心思路:每个用户每隔 N 秒最多允许提交 M 次代码

我使用了 Redis 的 key-value 机制实现滑动窗口限流:

key := fmt.Sprintf("rate_limit:user:%d", userID)

每次提交:

  1. 读取当前提交次数(通过 Redis 的 GET);

  2. 如果 key 不存在,则初始化为 1 并设置过期时间;

  3. 如果存在且未超限,则自增一次;

  4. 如果超出限制,则直接 Abort 拦截请求。


代码实现要点

func RateLimitMiddleware(maxReq int, duration time.Duration) gin.HandlerFunc {
    return func(c *gin.Context) {
        // 获取用户 ID
        val, exists := c.Get("user_id")
        ...
        key := fmt.Sprintf("rate_limit:user:%d", userID)

        // 读取提交次数
        countStr, err := utils.RDB.Get(ctx, key).Result()
        if err == redis.Nil {
            // 第一次提交,初始化 key
            _ = utils.RDB.Set(ctx, key, 1, duration).Err()
        } else if count >= maxReq {
            c.AbortWithStatusJSON(http.StatusTooManyRequests, gin.H{"error": "提交过于频繁"})
            return
        } else {
            _ = utils.RDB.Incr(ctx, key).Err()
        }

        c.Next()
    }
}

注意几个细节:

  • Redis 设置了 过期时间,窗口自动滑动;

  • 支持配置参数:每 N 秒 M 次,灵活调节;

  • 错误处理逻辑较为稳健,避免因 Redis 错误导致服务异常。


实战应用场景

比如:每个用户 10 秒内最多提交 3 次

在 Gin 中使用非常简单:

r.POST("/auth/problems/:id/submit", RateLimitMiddleware(3, 10*time.Second), SubmitCode)

只需一句话,就能为所有敏感路由提供限流保护。


后续可扩展点

拓展点

思路

精细限流策略

可针对不同 API 设置不同限流规则

IP + User 双维度

限制用户行为的同时防止匿名滥用

滑动窗口算法

可引入 token bucket / leaky bucket 算法实现更平滑的流控

限流监控

将被限流日志接入 Prometheus / ELK 方便运维观测


总结

限流中间件虽然是一个小组件,但在系统高可用性设计中起着至关重要的作用。它为整个智评平台建立了一道流量防火墙,确保了服务稳定与公平使用。、

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值