使用Guava库的RateLimit完成限流的,而其底层使用的是令牌桶算法实现的限流。
常用的限流算法有两种:漏桶算法和令牌桶算法
漏桶算法思路,水(请求)先进入到漏桶里,漏桶以一定的速度出水,当水流入速度过大会直接溢出,可以看出漏桶算法能强行限制数据的传输速率。
漏桶图1
对于很多应用场景来说,除了要求能够限制数据的平均传输速率外,还要求允许某种程度的突发传输。这时候漏桶算法可能就不合适了,令牌桶算法更为适合。如图2所示,令牌桶算法的原理是系统会以一个恒定的速度往桶里放入令牌,而如果请求需要被处理,则需要先从桶里获取一个令牌,当桶里没有令牌可取时,则拒绝服务。
令牌桶图2
(1)创建项目,命名00-eurekaserver-8000
(2)依赖
4.0.0
com.abc
00-eurekaserver-8000
0.0.1-SNAPSHOT
jar
org.springframework.boot
spring-boot-starter-parent
2.1.7.RELEASE
1.8
Greenwich.SR2
org.springframework.cloud
spring-cloud-starter-netflix-eureka-server
org.springframework.boot
spring-boot-starter-test
test
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
org.springframework.boot
spring-boot-maven-plugin
(3)application.yml配置
server:
port: 8000
eureka:
instance:
hostname: localhost # 指定Eureka主机
client:
register-with-eureka: false # 指定当前主机是否向Eureka服务器进行注册
fetch-registry: false # 指定当前主机是否要从Eurka服务器下载服务注册列表
service-url: # 服务暴露地址
defaultZone: http://localhost:8000/eureka
# defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka
# server:
# enable-self-preservation: false # 关闭自我保护
(4)启动类
package com.abc.eureka;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer // 开启Eureka服务
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
(1)创建项目,命名00-zuul-tokenbucket-9000
(2)依赖
4.0.0
com.abc
00-zuul-tokenbucket-9000
0.0.1-SNAPSHOT
jar
org.springframework.boot
spring-boot-starter-parent
2.1.7.RELEASE
1.8
Greenwich.SR1
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-actuator
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
org.springframework.cloud
spring-cloud-starter-netflix-zuul
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
org.springframework.boot
spring-boot-maven-plugin
(3)application.yml配置
server:
port: 9000
eureka:
client:
service-url:
defaultZone: http://localhost:8000/eureka
spring:
application:
name: abcmsc-zuul-depart
zuul:
routes:
# 指定微服务的路由规则
abcmsc-consumer-depart-8080: /abc8080/**
abcmsc-consumer-depart-8090: /abc8090/**
abcmsc-consumer-depart: /abc012/**
(4)ZuulFilter类
package com.abc.zuul.filter;
import com.google.common.util.concurrent.RateLimiter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class RouteFilter extends ZuulFilter {
// 定义一个令牌桶,每秒产生2个令牌,即每秒最多处理2个请求
private static final RateLimiter RATE_LIMITER = RateLimiter.create(2);
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
@Override
public int filterOrder() {
return -5;
}
@Override
public Object run() throws ZuulException {
log.info("通过过滤");
return null;
}
@Override
public boolean shouldFilter() {
// 获取请求上下文
RequestContext context = RequestContext.getCurrentContext();
// tryAcquire() 只要能够马上获致到1个令牌,则返回true,不阻塞
// tryAcquire(5, 3, TimeUnit.SECONDS) 在3秒钟内可以获取到5个令牌,则返回true,不阻塞
// acquire(5) 获取到5个令牌,否则一直等待,会阻塞,返回值为阻塞的时长
// acquire() 获取到1个令牌,否则一直等待,会阻塞,返回值为阻塞的时长
if(!RATE_LIMITER.tryAcquire()) {
log.warn("访问量超载");
// 指定当前请求未通过过滤
context.setSendZuulResponse(false);
// 向客户端返回响应码429,请求数量过多
context.setResponseStatusCode(429);
return false;
}
return true;
}
}
(5)启动类
package com.abc.zuul;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@EnableZuulProxy // 开启zuul代理模式
@SpringBootApplication
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
}
五、测试
(1)启动eureka
(2)启动zuul
(3)一秒内浏览器帅新2次
http://localhost:9000/abc8090/consumer/depart/get/1
浏览器显示
后台显示