前言
流量控制是老生常谈的话题,包括两方面:
- 对本系统的保护。位于业务系统的最前面;
- 对外部调用的并发控制。处于系统的底层;
大部分系统聊的都是前者,今天我们聊聊后者。
背景
请求外部服务,或者做批量数据同步,下游依赖服务有最大并发控制,不想接口因为限流而失败,同时又想尽可能的提高并发,怎么控制?
实战
Guava 的 RateLimiter 实现了这个功能,使用方式如下:
private static final ThreadPoolExecutor tx = new ThreadPoolExecutor(5, 10, 60, TimeUnit.SECONDS,
new LinkedBlockingDeque<>(10),
new NamedThreadFactory("yuan-cus", false),
new ThreadPoolExecutor.CallerRunsPolicy());
public static void main(String[] args) {
test(30);
}
public static void test(int permitsPerSecond) {
RateLimiter limiter = RateLimiter.create(permitsPerSecond);
//记录上一次执行时间
final long[] prev = {System.nanoTime()};
//测试执行20次
for (Long i = 0L; i < 100; i++) {
//提交任务异步执行
Long finalI = i;
dot("submit No." + i);
tx.execute(() -> {
double acquire = limiter.acquire();
dot("limiter sleep " + acquire * 1000);
long cur = System.nanoTime();
long interval = (cur - prev[0]) / 1000_000;
//打印时间间隔:毫秒
dot("Run No. " + finalI + " interval==> " + interval);
prev[0] = cur;
});
}
tx.shutdown();
}
private static void dot(String s) {
long millis = System.currentTimeMillis();
String name = Thread.currentThread().getName();
int size = tx.getQueue().size();
int activeCount = tx.getActiveCount();
System.out.println("Mills:" + millis + " Thread:" + name + " QueueSize:" + size + "activeCt:" + activeCount + " ==> " + s);
}
特点
那么RateLimiter有哪些特点呢?
我以为主要有以下几点:
- 单机
- 基于内存
- 均匀的时间窗口
- 可以动态调整
limiter.setRate(30.0);