服务限流的几种实现方案

这篇文章记录基于 Guava、Nginx的服务限流的实现。

背景

服务器能处理的请求数有限,如果瞬时流量过大可能会造成服务宕机,限流是通过对并发访问/请求进行限速来保护系统,一旦达到限制速率则可以拒绝服务。

限流算法

限流算法主要有:令牌桶算法漏桶算法。网上有很多文章都对两个算法进行了详细的解说,这里就不在介绍了。下面记录下基于 Guava 和 Nginx 限流的实现。

基于 GuavaRateLimiter 实现

限流注解:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Limiter {
    int NOT_LIMIT = 0;
    /**
     * qps:Queries-per-second, 每秒查询率,QPS = req/sec = 请求数/秒
     */
    @AliasFor("qps") double value() default NOT_LIMIT;

    @AliasFor("value") double qps() default NOT_LIMIT;

    /**
     * 超时时长
     */
    int timeout() default 0;

    /**
     * 超时时间单位
     */
    TimeUnit timeUnit() default TimeUnit.MILLISECONDS;

}

使用切面进行统一处理:

@Aspect
@Component
@Slf4j
public class RateLimiterAspect {

    private static final ConcurrentHashMap<String, RateLimiter> LIMIT_CACHE = new ConcurrentHashMap<>();

    @Pointcut("@annotation(com.example.demo.aspect.Limiter)")
    public void pointcut() {
    }

    @Around("pointcut()")
    public Object pointcut(ProceedingJoinPoint point) throws Throwable {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        Limiter limiter = AnnotationUtils.findAnnotation(method, Limiter.class);
        if (limiter != null && limiter.qps() > Limiter.NOT_LIMIT) {
            double qps = limiter.qps();
            if (LIMIT_CACHE.get(method.getName()) == null) {
                LIMIT_CACHE.put(method.getName(), RateLimiter.create(qps));
            }
            log.debug("【{}】的QPS设置为: {}", method.getName(), LIMIT_CACHE.get(method.getName()).getRate());
            // 尝试获取令牌
            if (LIMIT_CACHE.get(method.getName()) != null &&
                    !LIMIT_CACHE.get(method.getName()).tryAcquire(limiter.timeout(), limiter.timeUnit())) {
                throw new RuntimeException("访问太频繁了,请稍后再试...");
            }
        }
        return point.proceed();
    }
}

在设置QPS=1时,频繁的访问链接,则会抛出以下提示:

使用 Nginx 进行限流

用 Nginx 进行限流,主要使用 limit_req_zone 模块,用来限制单位时间内的请求数,主要采用的是漏桶算法。配置示例如下:

http {
    limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
    server {
        location /search/ {
            limit_req zone=one burst=5 nodelay;
        }
}   
  • $binary_remote_addr 表示限制同一客户端 ip 地址。zone=one 表示生成一个大小为 10 M,名字为 one 的内存区域,用来存储访问频次的信息。rate = 1r/s 表示限制同一 ip 客户端每秒只能访问一次。
  • burst=5 表示设置一个大小为5的缓冲区,当有大量请求(爆发)过来时,超过了访问频次限制的请求可以先放到这个缓冲区内。nodelay 表示访问频次而且缓冲区也满了的时候就会直接返回503,如果没有设置,则所有请求会等待排队。

访问过快,可以看到以下信息:

参考链接

个人博客:https://www.kangpeiqin.cn/#/index
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值