栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java > SpringBoot

在springboot中使用Guava基于令牌桶实现限流

SpringBoot 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

在springboot中使用Guava基于令牌桶实现限流

限流说详细了,名堂也多。这种算法那种算法,这种策略那种策略的。没有绝对的银弹。都要结合实际的场景来实现。最简单的,使用Google的Guava,几行代码。就可以优雅的对一个接口完成限流

令牌桶算法

通俗的理解就是,有一个固定大小的水桶,水龙头一直按照一定的频率往里面滴水。水满了,就不滴了。客户端每次进行请求之前,都要先尝试从水桶里面起码取出“一滴水”,才能处理业务。因为桶的大小固定,水龙头滴水频率固定。从而也就保证了数据接口的访问流量。

Guava

谷歌的一个工具库,包含了大量的Java工具类,像hash算法,字符串处理,集合等等。。。

https://github.com/google/guava



	com.google.guava
	guava
	29.0-jre

速率限制器 RateLimiter

RateLimiter rateLimiter = RateLimiter.create(2.5, 1, TimeUnit.SECONDS);


double waitSeconds = rateLimiter.acquire();


boolean success = rateLimiter.tryAcquire();

好了,这就是核心代码。就3行。首先创建一个限速器,指定令牌的生产频率。
核心的方法就是2种,阻塞获取令牌,非阻塞获取令牌。代码也通俗易懂。

重载方法

不论是阻塞获取令牌还是非阻塞获取令牌,它们都有几个重载方法。一看也清楚,就是可以设置获取令牌的数量,以及阻塞的时间。

public double acquire(int permits)

public boolean tryAcquire(Duration timeout)
public boolean tryAcquire(int permits)
public boolean tryAcquire(long timeout, TimeUnit unit)
public boolean tryAcquire(int permits, long timeout, TimeUnit unit) 
public boolean tryAcquire(int permits, Duration timeout)
Controller ,也就是被限速的接口
@RestController
@RequestMapping("/test")
public class TestController {
	
	@GetMapping
	public Object test () {
		return Collections.singletonMap("success", "true");
	}
}

RateLimiterInterceptor,负责实现限速逻辑
import java.nio.charset.StandardCharsets;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.http.MediaType;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import com.google.common.util.concurrent.RateLimiter;

public class RateLimiterInterceptor extends HandlerInterceptorAdapter {

	private final RateLimiter rateLimiter;

	
	public RateLimiterInterceptor(RateLimiter rateLimiter) {
		super();
		this.rateLimiter = rateLimiter;
	}

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		
		if(this.rateLimiter.tryAcquire()) {
			
			return true;
		}

		
		response.setCharacterEncoding(StandardCharsets.UTF_8.name());
		response.setContentType(MediaType.TEXT_PLAIN_VALUE);
		response.getWriter().write("服务器繁忙");
		return false;
	}
}
拦截器的配置
import java.util.concurrent.TimeUnit;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import com.google.common.util.concurrent.RateLimiter;

import io.springboot.jwt.web.interceptor.RateLimiterInterceptor;


@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
	
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		
		registry.addInterceptor(new RateLimiterInterceptor(RateLimiter.create(1, 1, TimeUnit.SECONDS)))
			.addPathPatterns("/test");
	}
	
}

客户端演示限流效果


原文:https://springboot.io/t/topic/2352

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号