一、冷启动含义
除了匀速器,另一种在面对RocketMQ 场景下流量突增时来保障系统稳定性的的方式是冷启动。Sentinel的Warm Up(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。warm up冷启动主要用于启动需要额外开销的场景,例如建立数据库连接等。
二、验证实例
1、首先设置限流规则以及流控效果(采用warm up冷启动方式)
private static void initFlowRule() {
List<FlowRule> rules = new ArrayList<FlowRule>();
FlowRule rule1 = new FlowRule();
rule1.setResource(KEY);
// 设置最大阈值为20
// rule1.setCount(20);
// 这里设置QPS最大的阈值1000, 便于查看变化曲线
rule1.setCount(1000);
// 基于QPS流控规则
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
// 默认不区分调用来源
rule1.setLimitApp("default");
// 流控效果, 采用warm up冷启动方式
rule1.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_WARM_UP);
// 在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。
// warmUpPeriodSec 代表期待系统进入稳定状态的时间(即预热时长)。
// 这里预热时间为1min, 便于在dashboard控制台实时监控查看QPS的pass和block变化曲线
rule1.setWarmUpPeriodSec(60); // 默认值为10s
rules.add(rule1);
FlowRuleManager.loadRules(rules);
}
2、启动一个TimerTask线程, 统计每一秒的pass, block, total这三个指标
static class TimerTask implements Runnable {
@Override
public void run() {
long start = System.currentTimeMillis();
System.out.println("begin to statistic!!!");
long oldTotal = 0;
long oldPass = 0;
long oldBlock = 0;
while (!stop) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
}
long globalTotal = total.get();
long oneSecondTotal = globalTotal - oldTotal;
oldTotal = globalTotal;
long globalPass = pass.get();
long oneSecondPass = globalPass - oldPass;
oldPass = globalPass;
long globalBlock = block.get();
long oneSecondBlock = globalBlock - oldBlock;
oldBlock = globalBlock;
System.out.println("currentTimeMillis:" + TimeUtil.currentTimeMillis() + ", totalSeconds:"
+ TimeUtil.currentTimeMillis() / 1000 + ", currentSecond:"
+ (TimeUtil.currentTimeMillis() / 1000) % 60 + ", total:" + oneSecondTotal
+ ", pass:" + oneSecondPass + ", block:" + oneSecondBlock);
if (seconds-- <= 0) {
stop = true;
}
}
long cost = System.currentTimeMillis() - start;
System.out.println("time cost: " + cost + " ms");
System.out.println("total:" + total.get() + ", pass:" + pass.get() + ", block:" + block.get());
try {
TimeUnit.SECONDS.sleep(60);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.exit(0);
}
}
pass:是限流允许的访问数量,block:是被限流的访问数量,total是总数量。
3、同时启动三个WarmUpTask线程, 设置其休眠时间小于2s, 使系统访问资源处于一个较低的流量
// 创建3个WarmUpTask线程, 模拟一个系统处于一个低水平流量
for (int i = 0; i < 3; i++) {
Thread t = new Thread(new WarmUpTask());
t.setName("sentinel-warmup-task");
t.start();
}
//WarmUpTask线程休眠小于2s, 通过控制休眠时间, 达到控制访问资源的流量处于一个较低的水平.
static class WarmUpTask implements Runnable {
@Override
public void run() {
while (!stop) {
Entry entry = null;
try {
entry = SphU.entry(KEY);
// token acquired, means pass
pass.addAndGet(1);
} catch (BlockException e1) {
block.incrementAndGet();
} catch (Exception e2) {
// biz exception
} finally {
total.incrementAndGet();
if (entry != null) {
entry.exit();
}
}
Random random2 = new Random();
try {
// 随机休眠时间<2s, 通过设置休眠时间(挡板业务耗时), 模拟访问资源的流量大小
TimeUnit.MILLISECONDS.sleep(random2.nextInt(2000));
} catch (InterruptedException e) {
// ignore
}
}
}
}
4、WarmUpTask线程运行20s后,再同时启动100个线程, 设置其休眠时间小于50ms, 这样就模拟造成了访问资源的流量突增, 一是可以查看后台console观察流量变化数值, 二是查看监控台的实时监控, 能比较直观的看见warm up过程.
// 20s开始有突增的流量进来, 访问资源
Thread.sleep(20000);
// 创建一个100线程, 模拟突增的流量访问被保护的资源
for (int i = 0; i < threadCount; i++) {
Thread t = new Thread(new RunTask());
t.setName("sentinel-run-task");
t.start();
}
static class RunTask implements Runnable {
@Override
public void run() {
while (!stop) {
Entry entry = null;
try {
entry = SphU.entry(KEY);
pass.addAndGet(1);
} catch (BlockException e1) {
//以原子方式将当前值加 1。
block.incrementAndGet();
} catch (Exception e2) {
// biz exception
} finally {
total.incrementAndGet();
if (entry != null) {
entry.exit();
}
}
Random random2 = new Random();
try {
// 随机休眠时间<50ms, 通过设置休眠时间, 模拟访问资源的流量大小
TimeUnit.MILLISECONDS.sleep(random2.nextInt(50));
} catch (InterruptedException e) {
// ignore
}
}
}
}
5、控制台中打印的日志的展示效果是:
可以看到在20秒时有一个明显的流量激增,total由原来的一百多突然长到三千多pass也激增到几百了,block也长到了几千。
接着往下看
可以看到由于我们设置的阈值为1000, 所以最终的pass值是稳定在1000没有问题; 流控效果采用warm up方式, pass的值不是一下子增加到1000, 而是由300-->400-->500-->600-->700-->800-->900-->1000逐渐增加的。最终QPS流量稳定在最大阈值1000。
6、sentinel控制台展示效果图:
刚开始在qps未激增的时候:
激增之后有一个明显的激增点,也可以看到通过的QPS也就是图中红色的线,是平稳上升的:
由于阔值是1000可以看到经过60s的预热最后稳定到1000
7、总结
上面主要讲述了QPS流量控制, 采用Warm Up预热/冷启动方式控制突增流量, 通过在后台console观察打印的数据以及结合dashboard图表的形式, 能很清晰的了解到warm up冷启动方式控制突增流量, 保护资源, 维护系统的稳定性的.