Web安全 之 限流机制
2019-02-26 本文已影响0人
诺之林
限流的三个层次 (1) 通用网关服务 (Kong, 阿里云, AWS) (2) Spring Cloud网关服务 (Spring Cloud Gateway, Netflix/zuul) (3) 应用内限流机制 (Laravel 的路由中间件) 本文主要讨论限流机制
目录
Leaky Bucket
限流机制-Leaky-Bucket.pngLaravel采用基于Leaky Bucket的限流机制 (1) 优势在于封装了Cache(底层可基于File或Redis) (2) 劣势在于Key基于User或Domain和IP(需扩展支持HTTP Method和URI)
Token Bucket
spring init -dweb --build gradle GuavaBasic && cd GuavaBasic
vim build.gradle
compile group: 'com.google.guava', name: 'guava', version: '22.0'
vim src/main/java/com/example/GuavaBasic/RateLimiterController.java
package com.example.GuavaBasic;
import com.google.common.util.concurrent.RateLimiter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.TimeUnit;
@RestController
public class RateLimiterController {
private final static long timeout = 2;
private final static double interval = 5;
private final static RateLimiter rateLimiter = RateLimiter.create(1.0 / interval);
private final static Logger log = LoggerFactory.getLogger(RateLimiterController.class);
@GetMapping("/test1")
public String test1() {
// 租塞式 返回sleeping时长
double time = rateLimiter.acquire();
log.info("acquire time: " + time);
return "test1";
}
@GetMapping("/test2")
public String test2() {
// 非租塞式 等待timeout返回
if (!rateLimiter.tryAcquire(timeout, TimeUnit.SECONDS)) {
return "rate limiter";
}
return "test2";
}
}
- 测试
./gradlew bootrun
# 第一次
curl localhost:8080/test1
# acquire time: 0.0
# test1
# 第二次 => 和第一次间隔短
curl localhost:8080/test1
# acquire time: 3.257715
# test1
# 第一次
curl localhost:8080/test2
# test2
# 第二次 => 和第一次间隔短
curl localhost:8080/test2
# rate limiter
# 第三次
curl localhost:8080/test2
# test2
比较
-
Leaky Bucket会丢弃请求 而Token Bucket可以灵活动态控制
-
Leaky Bucket可预防攻击 而Token Bucket可以用于削峰缓压
参考
git clone https://github.com/eugenp/tutorials.git
cd tutorials/spring-cloud/spring-cloud-zuul
mvn test
# Tests run: 2, Failures: 0, Errors: 0, Skipped: 0