Sentinel基本使用--基于QPS流量控制(二), 采用Warm Up预热/冷启动方式控制突增流量

2019年02月18日 23:52:37 xiongxianze 阅读数 398更多

分类专栏: 1====>Java
 
版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。

一, Warm Up

Sentinel的Warm Up(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。warm up冷启动主要用于启动需要额外开销的场景,例如建立数据库连接等。

二, 实例

本文结合sentinel提供的示例, 通过dashboard控制台展示warm up方式启动流量曲线变化,

WarmUpFlowDemo类说明:

1 初始化基于QPS流控规则, 流控效果使用warm up; 阈值 : 1000, 预热时间60s;

  1.  
    private static void initFlowRule() {
  2.  
    List<FlowRule> rules = new ArrayList<FlowRule>();
  3.  
    FlowRule rule1 = new FlowRule();
  4.  
    rule1.setResource(KEY);
  5.  
    // 这里设置QPS最大的阈值1000, 尽量设置大一点, 便于在监控台查看流量变化曲线
  6.  
    rule1.setCount(1000);
  7.  
    // 基于QPS流控规则
  8.  
    rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
  9.  
    // 默认不区分调用来源
  10.  
    rule1.setLimitApp("default");
  11.  
    // 流控效果, 采用warm up冷启动方式
  12.  
    rule1.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_WARM_UP);
  13.  
    // 在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。
  14.  
    // warmUpPeriodSec 代表期待系统进入稳定状态的时间(即预热时长)。
  15.  
    // 这里预热时间为1min, 便于在dashboard控制台实时监控查看QPS的pass和block变化曲线
  16.  
    rule1.setWarmUpPeriodSec(60); // 默认值为10s
  17.  
     
  18.  
    rules.add(rule1);
  19.  
    FlowRuleManager.loadRules(rules);
  20.  
    }

2 启动一个TimerTask线程, 统计每一秒的pass, block, total这三个指标;

  1.  
    static class TimerTask implements Runnable {
  2.  
     
  3.  
    @Override
  4.  
    public void run() {
  5.  
    long start = System.currentTimeMillis();
  6.  
    System.out.println("begin to statistic!!!");
  7.  
    long oldTotal = 0;
  8.  
    long oldPass = 0;
  9.  
    long oldBlock = 0;
  10.  
    while (!stop) {
  11.  
    try {
  12.  
    TimeUnit.SECONDS.sleep(1);
  13.  
    } catch (InterruptedException e) {
  14.  
    }
  15.  
     
  16.  
    long globalTotal = total.get();
  17.  
    long oneSecondTotal = globalTotal - oldTotal;
  18.  
    oldTotal = globalTotal;
  19.  
     
  20.  
    long globalPass = pass.get();
  21.  
    long oneSecondPass = globalPass - oldPass;
  22.  
    oldPass = globalPass;
  23.  
     
  24.  
    long globalBlock = block.get();
  25.  
    long oneSecondBlock = globalBlock - oldBlock;
  26.  
    oldBlock = globalBlock;
  27.  
     
  28.  
    System.out.println("currentTimeMillis:" + TimeUtil.currentTimeMillis() + ", totalSeconds:"
  29.  
    + TimeUtil.currentTimeMillis() / 1000 + ", currentSecond:"
  30.  
    + (TimeUtil.currentTimeMillis() / 1000) % 60 + ", total:" + oneSecondTotal
  31.  
    + ", pass:" + oneSecondPass + ", block:" + oneSecondBlock);
  32.  
     
  33.  
    if (seconds-- <= 0) {
  34.  
    stop = true;
  35.  
    }
  36.  
    }
  37.  
     
  38.  
    long cost = System.currentTimeMillis() - start;
  39.  
    System.out.println("time cost: " + cost + " ms");
  40.  
    System.out.println("total:" + total.get() + ", pass:" + pass.get() + ", block:" + block.get());
  41.  
    System.exit(0);
  42.  
    }
  43.  
    }

3 同时启动三个WarmUpTask线程, 设置其休眠时间小于2s, 使系统访问资源处于一个较低的流量 .

①同时启动3个WarmUpTask线程

  1.  
    for (int i = 0; i < 3; i++) {
  2.  
    Thread t = new Thread(new WarmUpTask());
  3.  
    t.setName("sentinel-warmup-task");
  4.  
    t.start();
  5.  
    }

②WarmUpTask线程休眠小于2s, 通过控制休眠时间, 达到控制访问资源的流量处于一个较低的水平.

  1.  
    static class WarmUpTask implements Runnable {
  2.  
     
  3.  
    @Override
  4.  
    public void run() {
  5.  
    while (!stop) {
  6.  
    Entry entry = null;
  7.  
    try {
  8.  
    entry = SphU.entry(KEY);
  9.  
    // token acquired, means pass
  10.  
    pass.addAndGet(1);
  11.  
    } catch (BlockException e1) {
  12.  
    block.incrementAndGet();
  13.  
    } catch (Exception e2) {
  14.  
    // biz exception
  15.  
    } finally {
  16.  
    total.incrementAndGet();
  17.  
    if (entry != null) {
  18.  
    entry.exit();
  19.  
    }
  20.  
    }
  21.  
    Random random2 = new Random();
  22.  
    try {
  23.  
    // 随机休眠时间<2s, 通过设置休眠时间, 模拟访问资源的流量大小
  24.  
    TimeUnit.MILLISECONDS.sleep(random2.nextInt(2000));
  25.  
    } catch (InterruptedException e) {
  26.  
    // ignore
  27.  
    }
  28.  
    }
  29.  
    }
  30.  
    }

4 WarmUpTask线程运行20s后,再同时启动100个线程, 设置其休眠时间小于50ms, 这样就模拟造成了访问资源的流量突增, 一是可以查看后台console观察流量变化数值, 而是查看监控台的实时监控, 能比较直观的看见warm up过程.

①20s后, 再同时启动100个线程

  1.  
    // 20s开始有突增的流量进来, 访问资源
  2.  
    Thread.sleep(20000);

②再同时启动100个线程, 模拟突增的流量访问资源

  1.  
    // 创建一个100线程, 模拟突增的流量访问被保护的资源
  2.  
    for (int i = 0; i < threadCount; i++) {
  3.  
    Thread t = new Thread(new RunTask());
  4.  
    t.setName("sentinel-run-task");
  5.  
    t.start();
  6.  
    }

③RunTask线程休眠时间小于50ms, 这样每个线程就能多次的访问资源, 模拟造成资源被突增的流量访问. 这样对资源的访问流量就处于一个较高的水平.

  1.  
    static class RunTask implements Runnable {
  2.  
     
  3.  
    @Override
  4.  
    public void run() {
  5.  
    while (!stop) {
  6.  
    Entry entry = null;
  7.  
    try {
  8.  
    entry = SphU.entry(KEY);
  9.  
    pass.addAndGet(1);
  10.  
    } catch (BlockException e1) {
  11.  
    block.incrementAndGet();
  12.  
    } catch (Exception e2) {
  13.  
    // biz exception
  14.  
    } finally {
  15.  
    total.incrementAndGet();
  16.  
    if (entry != null) {
  17.  
    entry.exit();
  18.  
    }
  19.  
    }
  20.  
    Random random2 = new Random();
  21.  
    try {
  22.  
    // 随机休眠时间<50ms, 通过设置休眠时间, 模拟访问资源的流量大小
  23.  
    TimeUnit.MILLISECONDS.sleep(random2.nextInt(50));
  24.  
    } catch (InterruptedException e) {
  25.  
    // ignore
  26.  
    }
  27.  
    }
  28.  
    }
  29.  
    }

三, 后台console端每秒展示pass, block, total数据.

①从下图可以很明显的看出, 有一个很明显的流量激增, total由原来的几或者几十, 突然增加到了4000左右, 而pass也是陡然的增加到了几百, block也由原来的0变成了3500左右.

②接着往下看, 由于我们设置的阈值为1000, 所以最终的pass值是稳定在1000没有问题; 流控效果采用warm up方式, pass的值不是一下子增加到1000, 而是由300-->400-->500-->600-->700-->800-->900-->1000逐渐增加的.

③最终QPS流量稳定在最大阈值1000, 如下图:

四, dashboard控制台流量曲线展示

① 下图展示的是, 访问资源的流量刚开始处于一个较低的水平, QPS大概只有3左右;

②下图可以明显的看到绿曲线p_qps是一个逐渐上升的过程, 代表着访问资源的流量逐渐变大, 最终稳定在阈值1000QPS.

③下图, 展示的是38分51秒左右, 经过60s的预热, QPS最终达到阈值1000.

完整代码:

  1.  
    public class WarmUpFlowDemo {
  2.  
     
  3.  
    private static final String KEY = "abc";
  4.  
     
  5.  
    private static AtomicInteger pass = new AtomicInteger();
  6.  
    private static AtomicInteger block = new AtomicInteger();
  7.  
    private static AtomicInteger total = new AtomicInteger();
  8.  
     
  9.  
    private static volatile boolean stop = false;
  10.  
     
  11.  
    private static final int threadCount = 100;
  12.  
    private static int seconds = 60 + 40;
  13.  
     
  14.  
    public static void main(String[] args) throws Exception {
  15.  
    initFlowRule();
  16.  
    // trigger Sentinel internal init
  17.  
    Entry entry = null;
  18.  
    try {
  19.  
    entry = SphU.entry(KEY);
  20.  
    } catch (Exception e) {
  21.  
    } finally {
  22.  
    if (entry != null) {
  23.  
    entry.exit();
  24.  
    }
  25.  
    }
  26.  
     
  27.  
    Thread timer = new Thread(new TimerTask());
  28.  
    timer.setName("sentinel-timer-task");
  29.  
    timer.start();
  30.  
     
  31.  
    // first make the system run on a very low condition
  32.  
    // 创建3个线程, 模拟一个系统处于一个低水平流量
  33.  
    for (int i = 0; i < 3; i++) {
  34.  
    Thread t = new Thread(new WarmUpTask());
  35.  
    t.setName("sentinel-warmup-task");
  36.  
    t.start();
  37.  
    }
  38.  
     
  39.  
    // 20s开始有突增的流量进来, 访问资源
  40.  
    Thread.sleep(20000);
  41.  
     
  42.  
    /*
  43.  
    * Start more thread to simulate more qps. Since we use {@link RuleConstant.CONTROL_BEHAVIOR_WARM_UP} as {@link
  44.  
    * FlowRule#controlBehavior}, real passed qps will increase to {@link FlowRule#count} in {@link
  45.  
    * FlowRule#warmUpPeriodSec} seconds.
  46.  
    */
  47.  
    // 创建一个100线程, 模拟突增的流量访问被保护的资源
  48.  
    for (int i = 0; i < threadCount; i++) {
  49.  
    Thread t = new Thread(new RunTask());
  50.  
    t.setName("sentinel-run-task");
  51.  
    t.start();
  52.  
    }
  53.  
    }
  54.  
     
  55.  
    private static void initFlowRule() {
  56.  
    List<FlowRule> rules = new ArrayList<FlowRule>();
  57.  
    FlowRule rule1 = new FlowRule();
  58.  
    rule1.setResource(KEY);
  59.  
    // 设置最大阈值为20
  60.  
    // rule1.setCount(20);
  61.  
    // 这里设置QPS最大的阈值1000, 便于查看变化曲线
  62.  
    rule1.setCount(1000);
  63.  
    rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
  64.  
    rule1.setLimitApp("default");
  65.  
    rule1.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_WARM_UP);
  66.  
    // 在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。
  67.  
    // warmUpPeriodSec 代表期待系统进入稳定状态的时间(即预热时长)。
  68.  
    // 这里预热时间为1min, 便于在dashboard控制台实时监控查看QPS的pass和block变化曲线
  69.  
    rule1.setWarmUpPeriodSec(60); // 默认值为10s
  70.  
     
  71.  
    rules.add(rule1);
  72.  
    FlowRuleManager.loadRules(rules);
  73.  
    }
  74.  
     
  75.  
    static class WarmUpTask implements Runnable {
  76.  
     
  77.  
    @Override
  78.  
    public void run() {
  79.  
    while (!stop) {
  80.  
    Entry entry = null;
  81.  
    try {
  82.  
    entry = SphU.entry(KEY);
  83.  
    // token acquired, means pass
  84.  
    pass.addAndGet(1);
  85.  
    } catch (BlockException e1) {
  86.  
    block.incrementAndGet();
  87.  
    } catch (Exception e2) {
  88.  
    // biz exception
  89.  
    } finally {
  90.  
    total.incrementAndGet();
  91.  
    if (entry != null) {
  92.  
    entry.exit();
  93.  
    }
  94.  
    }
  95.  
    Random random2 = new Random();
  96.  
    try {
  97.  
    // 随机休眠时间<2s, 通过设置休眠时间, 模拟访问资源的流量大小
  98.  
    TimeUnit.MILLISECONDS.sleep(random2.nextInt(2000));
  99.  
    } catch (InterruptedException e) {
  100.  
    // ignore
  101.  
    }
  102.  
    }
  103.  
    }
  104.  
    }
  105.  
     
  106.  
    static class RunTask implements Runnable {
  107.  
     
  108.  
    @Override
  109.  
    public void run() {
  110.  
    while (!stop) {
  111.  
    Entry entry = null;
  112.  
    try {
  113.  
    entry = SphU.entry(KEY);
  114.  
    pass.addAndGet(1);
  115.  
    } catch (BlockException e1) {
  116.  
    block.incrementAndGet();
  117.  
    } catch (Exception e2) {
  118.  
    // biz exception
  119.  
    } finally {
  120.  
    total.incrementAndGet();
  121.  
    if (entry != null) {
  122.  
    entry.exit();
  123.  
    }
  124.  
    }
  125.  
    Random random2 = new Random();
  126.  
    try {
  127.  
    // 随机休眠时间<50ms, 通过设置休眠时间, 模拟访问资源的流量大小
  128.  
    TimeUnit.MILLISECONDS.sleep(random2.nextInt(50));
  129.  
    } catch (InterruptedException e) {
  130.  
    // ignore
  131.  
    }
  132.  
    }
  133.  
    }
  134.  
    }
  135.  
     
  136.  
    static class TimerTask implements Runnable {
  137.  
     
  138.  
    @Override
  139.  
    public void run() {
  140.  
    long start = System.currentTimeMillis();
  141.  
    System.out.println("begin to statistic!!!");
  142.  
    long oldTotal = 0;
  143.  
    long oldPass = 0;
  144.  
    long oldBlock = 0;
  145.  
    while (!stop) {
  146.  
    try {
  147.  
    TimeUnit.SECONDS.sleep(1);
  148.  
    } catch (InterruptedException e) {
  149.  
    }
  150.  
     
  151.  
    long globalTotal = total.get();
  152.  
    long oneSecondTotal = globalTotal - oldTotal;
  153.  
    oldTotal = globalTotal;
  154.  
     
  155.  
    long globalPass = pass.get();
  156.  
    long oneSecondPass = globalPass - oldPass;
  157.  
    oldPass = globalPass;
  158.  
     
  159.  
    long globalBlock = block.get();
  160.  
    long oneSecondBlock = globalBlock - oldBlock;
  161.  
    oldBlock = globalBlock;
  162.  
     
  163.  
    System.out.println("currentTimeMillis:" + TimeUtil.currentTimeMillis() + ", totalSeconds:"
  164.  
    + TimeUtil.currentTimeMillis() / 1000 + ", currentSecond:"
  165.  
    + (TimeUtil.currentTimeMillis() / 1000) % 60 + ", total:" + oneSecondTotal
  166.  
    + ", pass:" + oneSecondPass + ", block:" + oneSecondBlock);
  167.  
     
  168.  
    if (seconds-- <= 0) {
  169.  
    stop = true;
  170.  
    }
  171.  
    }
  172.  
     
  173.  
    long cost = System.currentTimeMillis() - start;
  174.  
    System.out.println("time cost: " + cost + " ms");
  175.  
    System.out.println("total:" + total.get() + ", pass:" + pass.get() + ", block:" + block.get());
  176.  
    try {
  177.  
    TimeUnit.SECONDS.sleep(60);
  178.  
    } catch (InterruptedException e) {
  179.  
    // TODO Auto-generated catch block
  180.  
    e.printStackTrace();
  181.  
    }
  182.  
    System.exit(0);
  183.  
    }
  184.  
    }
  185.  
    }

要想在将变化数据展示在dashboard控制台, 启动时需要配置:

-Dcsp.sentinel.dashboard.server=127.0.0.1:8080
-Dcsp.sentinel.api.port=8719
-Dproject.name=WarmUpFlowDemo

具体接入dashboard, 可参考上一篇博客, Sentinel基本使用--基于QPS流量控制(一), 采用默认快速失败/直接拒绝策略控制超过阈值的流量(结合Dashboard使用)

五, 总结

上面主要讲述了QPS流量控制, 采用Warm Up预热/冷启动方式控制突增流量, 通过在后台console观察数据以及结合dashboard图表的形式, 能很清晰的了解到warm up冷启动方式控制突增流量, 保护资源, 维护系统的稳定性的.

Sentinel基本使用--基于QPS流量控制(二), 采用Warm Up预热/冷启动方式控制突增流量的更多相关文章

  1. 3. Sentinel源码分析— QPS流量控制是如何实现的?

    Sentinel源码解析系列: 1.Sentinel源码分析-FlowRuleManager加载规则做了什么? 2. Sentinel源码分析-Sentinel是如何进行流量统计的? 上回我们用基于并 ...

  2. Sentinel Dashboard(基于1.8.1)流控规则持久化到Nacos——涉及部分Sentinel Dashboard源码改造

    前言 之前虽然也一直在使用sentinel实现限流熔断功能,但却没有好好整理之前看的源码与资料,今天有时间将之前自己整理过的资料写成一篇博文,或者是是一篇关于Sentinel(基于目前最近版本1.8, ...

  3. [github项目]基于百度地图二次开发实现的车辆监管(包含车辆定位、车辆图片和方向控制,电子围栏,图形绘制等功能)前端实现(不包含后端实现)

    前言:基于百度地图javascript版本开发,百度地图中所用的key已承诺仅用于测试,不用于商业用途 注:本文所有代码可以到github上进行下载,github地址:http://map.eguid ...

  4. ASP.NET Core中使用IOC三部曲(二.采用Autofac来替换IOC容器,并实现属性注入)

    前言 本文主要是详解一下在ASP.NET Core中,自带的IOC容器相关的使用方式和注入类型的生命周期. 这里就不详细的赘述IOC是什么 以及DI是什么了.. emm..不懂的可以自行百度. 目录 ...

  5. 基于Zxing的二维码的二维码扫描之横屏扫描

    最近项目条码扫描要改为横屏,网上所搜了一下,然后发现我写的需要改动几行代码就可以了,还是很给力的. 如未查看之前的代码,请移步: 基于Zxing的二维码生成和二维码扫描 修改下面写代码就可以实现横屏条 ...

  6. 深入理解基于selenium的二次开发

    对于做web端自动化测试的人来说,可能接触selenium比QTP还要多,但是我们在做基于selenium的二次开发的时候,经常会说到二次开发是为了易于维护,很多人可能不懂得维护的价值是什么,和到底要 ...

  7. 基于zxing的二维码(网格)扫描

    基于zxing的二维码(网格)扫描 前言:对于二维码扫描我们使用的是开源框架Zxing或者Zbar,这里使用基于zxing的二维码扫描,类似支付宝网格扫描, 二维码原理介绍: 二维码是用某种特定的几何 ...

  8. Kvm虚拟化的一种打包及部署方案(采用tar包,lvm方式)

    Kvm虚拟化的一种打包部署方案(采用tar包,lvm方式) –-–-–-2016年终总结 一 毕业之后跟师兄学到的第一块主要内容,理解花了不少时间.期间经历了shell的入门.linux基础知识入门. ...

  9. 基于MVC4+EasyUI的Web开发框架形成之旅--权限控制

    我在上一篇随笔<基于MVC4+EasyUI的Web开发框架形成之旅--框架总体界面介绍>中大概介绍了基于MVC的Web开发框架的权限控制总体思路.其中的权限控制就是分为“用户登录身份验证” ...

随机推荐

  1. BZOJ刷题列表【转载于hzwer】

    沿着黄学长的步伐~~ 红色为已刷,黑色为未刷,看我多久能搞完吧... Update on 7.26 :之前咕了好久...(足见博主的flag是多么emmm......)这几天开始会抽时间刷的,每天几道 ...

  2. 有趣但是没有用的linux命令

    1,小火车 #yum install sl 2,黑客帝国,代码雨 # wget https://jaist.dl.sourceforge.net/project/cmatrix/cmatrix/1.2 ...

  3. Bug集锦-Spring Cloud Feign调用其它接口报错

    问题描述 Spring Cloud Feign调用其它服务报错,错误提示如下:Failed to instantiate [java.util.List]: Specified class is an ...

  4. 8 Linux 文件类型

    Linux 系统中的文件是没有扩展名的. 1.通过 ls -l 文件名,看第一个字符判断文件类型: -  普通文件(文本文件.二进制文件.压缩文件.电影.图片等) d  目录文件 b  设备文件(块设 ...

  5. tomcat manager 配置

    使用网页部署新 Web 应用程序或取消现有 Web 应用程序部署,且无需重启容器. 一.开启管理 编辑 conf/tomcat-users.xml 添加如下内容,这里用户名和密码都为 tomcat & ...

  6. Java生成三位随机数

    转: [转]Java生成三位随机数 public class Test2 { public static void main(String [] srgs) { int i=(int)(Math.ra ...

  7. linux卸载Python3

    一.卸载Python3 1.卸载python3 rpm -qa|grep python3|xargs rpm -ev --allmatches --nodeps 卸载pyhton3 2.whereis ...

  8. JS原生上传大文件显示进度条-php上传文件

    JS原生上传大文件显示进度条-php上传文件 在php.ini修改需要的大小: upload_max_filesize = 8M    post_max_size = 10M    memory_li ...

  9. Centos 在线安装 nginx

    centos 在线安装 nginx 安装nginx ​ 参考文档: http://nginx.org/en/linux_packages.html 中的RHEL/CentOS章节,按照步骤安装repo ...

  10. C基础知识(10):预处理器

    C预处理器不是编译器的组成部分,但是它是编译过程中一个单独的步骤.简言之,C预处理器只不过是一个文本替换工具而已,它们会指示编译器在实际编译之前完成所需的预处理. 所有的预处理器命令都是以井号(#)开 ...