jmeter测试SpringBoot+Redis令牌桶算法实现接口限流实例

本文介绍如何在SpringBoot项目中使用令牌桶算法实现接口限流,通过自定义注解和拦截器控制请求频率,确保系统稳定运行。

一、前言

在开发高并发系统时有三把利器用来保护系统:缓存、降级和限流

1缓存 缓存的目的是提升系统访问速度和增大系统处理容量
2降级 降级是当服务出现问题或者影响到核心流程时,需要暂时屏蔽掉,待高峰或者问题解决后再打开
3限流 限流的目的是通过对并发访问/请求进行限速,或者对一个时间窗口内的请求进行限速来保护系统,一旦达到限制速率则可以拒绝服务、排队或等待、降级等处

涉及到的技术:

(1)SpringBoot拦截器

(2)ScheduledThreadPoolExecutor定时任务

(3)Redis队列

(4)SpringBoot RedisTemplate操作redis

(5)jmeter测试工具

使用令牌桶算法实现接口限流

 

令牌桶算法(Token Bucket):随着时间流逝,系统会按恒定1/QPS时间间隔(如果QPS=100,则间隔是10ms)往桶里加入Token,如果桶已经满了就不再加了.新请求来临时,会各自拿走一个Token,如果没有Token可拿了就阻塞或者拒绝服务。

在SpringBoot项目中通过拦截器拦截增加了@LimitingRequired注解的接口查询是否有token来决定是否限制请求。

二、关键代码

@LimitingRequired注解

package com.asyf.demo.annotation;

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LimitingRequired {
    boolean required() default true;
}

常量类

package com.asyf.demo.common;

public class Constant {

    public static final String TOKEN_BUCKET_KEY = "token_bucket";//令牌桶key

    public static final Long TOKEN_BUCKET_SIZE = 10L;//令牌桶容量

}

类ApplicationRunnerImpl,此方法实现了向桶中添加令牌的功能

package com.asyf.demo.config;

import com.asyf.demo.common.Constant;
import com.asyf.demo.utils.DateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Component
@ConfigurationProperties(
        prefix = "server",
        ignoreUnknownFields = true
)
public class ApplicationRunnerImpl implements ApplicationRunner {

    private Integer port;

    @Autowired
    private RedisTemplate redisTemplate;

    public Integer getPort() {
        return port;
    }

    public void setPort(Integer port) {
        this.port = port;
    }

    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("通过实现ApplicationRunner接口,在spring boot项目启动后打印参数");
        String[] sourceArgs = args.getSourceArgs();
        for (String arg : sourceArgs) {
            System.out.print(arg + " ");
        }
        //给令牌桶添加令牌-分布式部署时只需要一个端口添加令牌桶即可
        if (port.compareTo(8080) == 0) {
            addTokenBucket();
        }
    }

    private void addTokenBucket() {
        ScheduledThreadPoolExecutor scheduled = new ScheduledThreadPoolExecutor(1);
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                ListOperations listOperations = redisTemplate.opsForList();
                //获取队列的长度,当redis队列不存在返回0
                Long size = listOperations.size(Constant.TOKEN_BUCKET_KEY);
                if (size.compareTo(Constant.TOKEN_BUCKET_SIZE) == -1) {
                    long current
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值