Sentinel基本使用--基於QPS流量控制(二), 采用Warm Up預熱/冷啟動方式控制突增流量


 

Sentinel基本使用--基於QPS流量控制(二), 采用Warm Up預熱/冷啟動方式控制突增流量

版權聲明:本文為博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
本文鏈接: https://blog.csdn.net/xiongxianze/article/details/87580917

一, 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冷啟動方式控制突增流量, 保護資源, 維護系統的穩定性的.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM