前景回顾:
《基于计数器的服务接口限流实例》
《基于RateLimiter的服务接口限流实例》
一、Semaphore信号量的介绍
Semaphore是一种在多线程环境下使用的设施,该设施负责协调各个线程,以保证它们能够正确、合理的使用公共资源的设施,也是操作系统中用于控制进程同步互斥的量。
我们通常使用Semaphore来确保系统中的最大线程并发数量。
二、使用信号量的acquire和release
我们在以下实例中,设置getUserMail
这个URL最多只能同时被两个请求访问,其它请求要想访问该URL,必须等待前面的请求释放信号量才行。
@Slf4j
@RestController
public class UserMailRest {
/**
* 同一时刻最多只允许有两个并发
*/
private Semaphore semaphore = new Semaphore(2);
@GetMapping("/getUserMail")
public String getUserMail() {
try {
// 获取信号量的请求立即得到执行,未获取到信号量的请求需要等待
semaphore.acquire();
Thread.sleep(2000);
log.info("请求得到服务!");
return "OK";
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 请求结束后将信号量释放供其它请求使用
semaphore.release();
}
return "fail";
}
}
我们使用Jmeter模拟10个用户在1秒内的并发请求该URL得到的结果如下:
2019-12-24 20:59:04.862: 请求得到服务!
2019-12-24 20:59:04.862: 请求得到服务!
2019-12-24 20:59:06.864: 请求得到服务!
2019-12-24 20:59:06.864: 请求得到服务!
2019-12-24 20:59:08.865: 请求得到服务!
2019-12-24 20:59:08.865: 请求得到服务!
2019-12-24 20:59:10.867: 请求得到服务!
2019-12-24 20:59:10.867: 请求得到服务!
2019-12-24 20:59:12.869: 请求得到服务!
2019-12-24 20:59:12.869: 请求得到服务!
可以看出,该URL确实在同一时间最多只能供两个请求访问。
三、使用信号量的tryAcquire
和前面文章中提到的RateLimiter类似,Semaphore也有tryAcquire方法,用来拒绝单位时间内超出的并发请求。
@Slf4j
@RestController
public class UserMailRest {
/**
* 同一时刻最多只允许有两个并发
*/
private Semaphore semaphore = new Semaphore(2);
@GetMapping("/getUserMail")
public String getUserMail() {
if(!semaphore.tryAcquire()){
log.warn("调用太频繁了,拒绝服务!");
return "调用太频繁了,拒绝服务!";
}
try {
log.info("接受服务!");
Thread.sleep(2000);
return "ok";
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
}
return "fail";
}
}
运行结果如下:
2019-12-24 21:15:16.034 : 接受服务!
2019-12-24 21:15:16.034 : 接受服务!
2019-12-24 21:15:16.050 : 调用太频繁了,拒绝服务!
2019-12-24 21:15:16.149 : 调用太频繁了,拒绝服务!
2019-12-24 21:15:16.259 : 调用太频繁了,拒绝服务!
2019-12-24 21:15:16.352 : 调用太频繁了,拒绝服务!
2019-12-24 21:15:16.455 : 调用太频繁了,拒绝服务!
2019-12-24 21:15:16.552 : 调用太频繁了,拒绝服务!
2019-12-24 21:15:16.658 : 调用太频繁了,拒绝服务!
2019-12-24 21:15:16.754 : 调用太频繁了,拒绝服务!
可以看出,与acquire的区别是,超出的8个请求全部直接被拒绝了,而不是一直等待信号量的释放。
四、总结
Semaphore是比较常用的服务接口限流方案,它与计数器和RateLimiter比较最大的优点是,能限制住接口的最大并发数,哪怕每一个请求都是Long Call,也都不用害怕累计的并发线程会将服务器压垮的问题了。
全文完。