首先谈谈为什么要限流,有哪些限流方案?
限流是指控制系统中的流量,以保护系统免于过载或崩溃。在高并发、大数据量和分布式场景下,限流可以保护系统稳定性,防止由于流量超负荷而导致的服务降级或崩溃。
常见的限流方案包括:
- 令牌桶算法:系统会根据一个固定速率往令牌桶(Token Bucket)中添加令牌,每次请求需要获取一个令牌,当没有令牌时则请求被拒绝。
- 漏桶算法:系统会按照一个固定速率从漏桶中漏出请求,当请求到达时需要先进入漏桶中等待,当漏桶为空则请求被拒绝。
- 计数器算法:系统会记录单位时间内服务响应请求的次数,当到达设定的阈值时则请求被拒绝。
- 时间窗口算法:系统将时间分成多个窗口,每个窗口有一个最大请求量的限制,当当前窗口内的请求量超过该限制时则请求被拒绝。
- 基于权重的算法:系统根据业务需求和实际情况,对不同的请求设置不同的权重,在高流量时优先处理权重高的请求,避免因低优先级请求过多造成整体系统拥塞。
以上这些算法都可以通过在服务器端配置来实现限流,但不同的算法适用于不同的业务场景,需要根据实际情况做出选择。
在限流中有两个概念需要了解
阈值:在一个单位时间内允许的请求量。如 QPS 限制为10,说明 1 秒内最多接受 10 次请求。
拒绝策略:超过阈值的请求的拒绝策略,常见的拒绝策略有直接拒绝、排队等待等。
为什么限流
是防止用户恶意刷新接口,因为部署在外部服务器,并且我们采用websocket的接口实现的,公司没有对硬件升级,导致程序时长崩溃,为了解决这个问题,请教公司的大佬,提出一个方案,限流操作。
但是最后找到原因所在,解决了,吞吐量1万6左右,用的测试服务器,进行测试的,我开发的笔记本进行压测,工具是Jmeter,结果我的电脑未响应,卡了,服务器还没有挂。
常见的限流:
Netflix的hystrix
阿里系开源的sentinel
说白了限流,为了处理高并发接口那些方式:队列,线程,线程池,消息队列、 kafka、中间件、sentinel:直接拒绝、Warm Up、匀速排队等
技术层面:
判断是否有相同的请求,可以通过自身缓存挡住相同请求
用负载均衡,比如nginx
用缓存数据库,把热点数据get到缓存中,redis,ES
善于使用连接池。面试题整理好了,关注公众号后端面试那些事,回复:2022面经,即可获取
业务层面:加入交互,排队等待
怎么实现令牌桶限流?
首先,是微服务项目,创建一个gateway服务,一个测试服务
测试的时候通过网关端口访问测试服务的路径
1.父项目的依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.5.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--声明SpringBoot的依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
2.在gateway服务里面添加相关依赖
<!-- 网关依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<!--redis gateway令牌桶依赖 监控依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!—redis令牌桶依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
<version>2.1.2.RELEASE</version>
</dependency>
3.在gateway服务里面的启动类添加一段代码
/***
* IP限流
* @return
*/
@Bean(name="ipKeyResolver")
public KeyResolver userKeyResolver() {
return new KeyResolver() {
@Override
public Mono<String> resolve(ServerWebExchange exchange) {
//获取远程客户端IP
String hostName = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
System.out.println("hostName:"+hostName);
return Mono.just(hostName);
}
};
}
4. 在gateway服务里面的application.yml里面添加配置
spring:
cloud:
gateway:
globalcors:
corsConfigurations:
'[/**]': # 匹配所有请求
allowedOrigins: "*" #跨域处理 允许所有的域
allowedMethods: # 支持的方法
- GET
- POST
- PUT
- DELETE
routes:
- id: gateway1
uri: http://localhost:8080
predicates:
- Path=/abc/test/**
filters:
- StripPrefix=1
- name: RequestRateLimiter #请求数限流 名字不能随便写 ,使用默认的facatory
args:
key-resolver: "#{@ipKeyResolver}"
redis-rate-limiter.replenishRate: 1 #是你希望允许用户每秒执行多少请求,而不会丢弃任何请求。这是令牌桶填充的速率
redis-rate-limiter.burstCapacity: 3 #是指令牌桶的容量,允许在一秒钟内完成的最大请求数,将此值设置为零将阻止所有请求
application:
name: gateway-web
#Redis配置
redis:
host: 127.0.0.1
port: 6379
server:
port: 8001
management:
endpoint:
gateway:
enabled: true
web:
exposure:
include: true
5. 在测试服务
@RestController
@RequestMapping("test")
public class TestqController {
@GetMapping("getTest")
public String getTest(){
return "成功了!!!!";
}
}
使用postman测试或者网页上测试或者jmeter测试