![image.png](https://i-blog.csdnimg.cn/blog_migrate/afb93a253a76007298e9c5acbf72161d.png)
- Java中的流量限制方式;
- 容器限流:常用的有tomcat容器最大线程数,最大连接数,nginx限制ip的链接和并发等
- tomcat参数配置
- backlog:当所有可能的请求处理县曾都在使用时,队列中排队的请求最大数目,默认为10,当队列已满,任何请求都将被拒绝
- maxSpareThread:允许存在空闲线程的最大数目,默认值为50
- maxThreads:最大线程书,默认值200
- minSpareThreads:设当连接器第一次启动时创建线程的数目,确保至少有这么多的空闲线程可用,默认为4
- Port:服务端套接字的TCP端口号,默认值8089
- topDoDelay:为true时,可以提高性能,默认值为true
- soTimeout:超时值
- nginx限流:
- httplimit zone 参数配置
- limit_conn zone_name the_size 默认值为0 作用域:http,server,location ; 指定一个会话最大的并发连接数,当超过指定的最大并发连接数时,服务器将返回“Service unavailable”(503)
- 定义一个叫one的记录区,总容量为10M,以变量$binary_remote_addr作为会话的判断基准(即一个地址一个会话),限制/download/目录下,一个会话只能进行一个连接,就是限制该目录下,一个ip只能发起一个连接,躲过一个,一律503
- limit_req_zone参数配置:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ms9m3GmR-1602677557861)(https://i.loli.net/2020/09/19/13oAx7rS4J9OpVK.png)]:$binary_remote_addr:表示根据客户端ip限制;zone=one:10m:生成10m空间,命名为one,用于存储访问频率:rate=1r/s:意思是限制相同ip每秒访问频次,这里是1s/次
- 限制总的资源数
- 限制接口的请求的总并发数/请求数
- Guava实现限流:
- Guava是谷歌开源的java库,里面对于封装了一些常用的类库,是对JDK的扩展延伸丰富,它里边的RateLimite类,提供了令牌桶算法的实现:平滑突发限流和平滑预热限流实现
/**
* 平滑突发限流(SmoothBursty)
*/
public class SmoothBurstyRateLimitTest {
public static void main(String[] args) {
//QPS = 5,每秒允许5个请求
RateLimiter limiter = RateLimiter.create(5);
//limiter.acquire() 返回获取token的耗时,以秒为单位
System.out.println(limiter.acquire());
System.out.println(limiter.acquire());
System.out.println(limiter.acquire());
System.out.println(limiter.acquire());
System.out.println(limiter.acquire());
System.out.println(limiter.acquire());
}
}
/**
* 平滑突发限流(smoothbursty)
*/
public class SmoothBurstyRateLimitTest02 {
public static void main(String[] args) {
//每秒允许5个请求,表示桶容量为5且每秒新增5个令牌,即每隔0.2毫秒新增一个令牌
RateLimiter limiter = RateLimiter.create(5);
//一次性消费5个令牌
System.out.println(limiter.acquire(5));
//limiter.acquire(1)将等待差不多1秒桶中才能有令牌
System.out.println(limiter.acquire(1));
//固定速率
System.out.println(limiter.acquire(1));
//固定速率
System.out.println(limiter.acquire(1));
//固定速率
System.out.println(limiter.acquire(1));
}
}
/**
* 平滑突发限流(smoothbursty)
*/
public class SmoothBurstyRateLimitTest03 {
public static void main(String[] args) {
//每秒允许5个请求,表示桶容量为5且每秒新增5个令牌,即每隔0.2毫秒新增一个令牌
RateLimiter limiter = RateLimiter.create(5);
//第一秒突发了10个请求
System.out.println(limiter.acquire(10));
//limiter.acquire(1)将等待差不多2秒桶中才能有令牌
System.out.println(limiter.acquire(1));
//固定速率
System.out.println(limiter.acquire(1));
//固定速率
System.out.println(limiter.acquire(1));
//固定速率
System.out.println(limiter.acquire(1));
}
}
平滑预热限流:
/**
* 平滑预热限流(SmoothWarmingUp)
*/
public class SmoothWarmingUp {
public static void main(String[] args) {
//permitsPerSecond:每秒新增的令牌数 warmupPeriod:从冷启动速率过渡到平均速率的时间间隔
//系统冷启动后慢慢的趋于平均固定速率(即刚开始速率慢一些,然后慢慢趋于我们设置的固定速率)
RateLimiter limiter = RateLimiter.create(10, 1000, TimeUnit.MILLISECONDS);
for(int i = 0; i < 10;i++) {
//获取一个令牌
System.out.println(limiter.acquire(1));
}
}
}
guava 秒杀场景的实现
public class MiaoShaTest {
public static void main(String[] args) throws InterruptedException {
//限流,每秒允许10个请求进入秒杀
RateLimiter limiter = RateLimiter.create(10);
for (int i = 0; i < 100; i++) {
//100个线程同时抢购
new Thread(() -> {
//每个秒杀请求如果100ms以内得到令牌,就算是秒杀成功,否则就返回秒杀失败
if (limiter.tryAcquire(100, TimeUnit.MILLISECONDS)) {
System.out.println("恭喜您,秒杀成功");
} else {
System.out.println("秒杀失败,请继续努力");
}
}).start();
//等待新的令牌生成
Thread.sleep(10);
}
}
}