一、为什么要限流?
- 并发量特别大(突然流量)。
- 防止用户恶意刷接口。
二、限流的实现方式
限流的实现方式有以下几种:
- tomcat: 可以设置最大连接数
- Nginx: 漏桶算法
- 网关:令牌
- 桶算法
- 自定义拦截器
2.1 tomcat限流
可以在tomcat中设置最大线程数maxThreads。每一次HTTP请求到达WEB服务,Tomcat都会创建一个线程来处理该请求,那么最大线程数决定了web服务容器可以同时处理多少个请求。
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="2000" maxThreads="50" redirectPort="8443">
不过使用tomcat做限流适合用在单体项目中,不适合分布式服务。
2.1 Nginx限流
2.1.1 漏桶算法,控制速率
漏桶的大小是固定的;漏出请求的速率也是固定的;如果漏桶已经满了,那么多么请求需要等待或直接丢弃。
http{
limit_req_zone $binary_remote_addr zone=service1RateLimit:10m rate=10r/s
server{
listen 80;
server_name localhost;
location / {
limit_req_zone = service1RateLimit burst=20 nodelay;
proxy_pass http://targetserver;
}
}
}
- 语法:
limit_req_zone key zone rate - key:定义限流对象,binary_remote_addr就是一种key,基于客户端IP限流
- zone:定义共享存储区来存储访问信息,10m指申请了10m的内存空间,可以存储16w个 IP地址访问信息
- rate:最大访问速率,rate=10r/s,表示每秒最多处理10个请求
- burst:相当于桶的大小
- nodelay: 快速处理。桶中请求要快速处理,桶满后的多余请求要快速抛弃。
- service1RateLimit:自定义标识
2.1.2 控制并发连接数
http{
limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn_zone $server_name zone=perserver:10m;
server{
listen 80;
server_name localhost;
location / {
...
limit_conn perip 20;
limit_conn perserver 100;
proxy_pass http://targetservser;
}
}
}
- limit_conn perip 20: 对应的key是$binary_remote_addr,表示限制单个IP同时最多能支持20个连接。
- limit_conn perserver 100:对应的key是$server_name,表示虚拟主机(server)同时能处理并发连接的总数。
2.2 gateway网关限流
yml配置文件中,微服务路由设置添加局部过滤器RequestRateLimiter
- id: gateway-consumer
url: lb://GATEWAY-CONSUMER
predicates:
- Path=/order/**
filters:
- name: RequestRateLimiter
args:
# 使用SpEL从容器中获取对象
key-resolver: '#{@pathKeyResolver}'
# 令牌桶每秒填充平均速率
redis-rate-limiter.replenishRate: 1
# 令牌桶的上限
redis-rate-limiter.burstCapacity: 3
- key-resolver: 定义限流对象(ip、路径、参数),需代码实现,使用spel表达式获取
- replenishRate: 令牌桶每秒填充平均速率。
- burstCapacity: 令牌桶总容量。
- 令牌默认是存储到redis的,在网关的配置文件中需要配置redis连接。
令牌桶算法与漏桶算法的区别
- 令牌桶存储的是令牌,漏桶存储的是请求。
- 处理请求的速率不同。
- 令牌桶处理请求的速率是不固定的。如果桶中已经有令牌,可以同时处理令牌数量个请求;如果桶中没有令牌,需要等待令牌生成后再处理请求。
- 漏桶以固定速率漏出请求,以恒定速度放行请求
令牌桶算法与漏桶算法的共同点
- 都可以处理突发请求。