weixin_46114677 2023-04-28 17:46 采纳率: 100%
浏览 5
已结题

sentinel规则问题

为什么sentinel的流量控制不准,而且处理模式为 均速排队时不生效?

业务代码:

@Service
public class SentinelServiceImpl implements SentinelService {

    private final AtomicInteger NUM = new AtomicInteger(0);

    @PostConstruct
    private  void initFlowRules(){
        System.out.println("init sentinel rules");
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        rule.setResource("name");
        //0线程,1QPS
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        //处理模式
        //直接拒绝:(RuleConstant.CONTROL_BEHAVIOR_DEFAULT)方式是默认的
        //Warm Up:(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即预热/冷启动
        //均速排队:(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)
        rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER);
        // 阈值
        rule.setCount(2);

        rules.add(rule);
        FlowRuleManager.loadRules(rules);
    }

    @SentinelResource(value = "name",blockHandler = "reject")
    @Override
    public String getMsg() {
        int andIncrement = NUM.getAndIncrement();
        System.out.println(new Date() + ":get msg success :" + andIncrement);
        return "success" + andIncrement;
    }

    public String reject(BlockException ex){
        int andIncrement = NUM.getAndIncrement();
        System.out.println(new Date() + ":blockHandler:" + andIncrement);
        return "reject" + andIncrement;
    }
}

设置QPS为2,模式为 匀速排队,看看调用方的同时发生10个请求的结果:

1682674982090--> result:success1
1682674982090--> result:success0
1682674982090--> result:reject3
1682674982090--> result:success2
1682674982093--> result:reject4
1682674982095--> result:reject5
1682674982095--> result:reject7
1682674982096--> result:reject6
1682674982098--> result:reject8
1682674982552--> result:success9

首先一秒了通过了4个请求,其次超流量的请求没有排队等待处理,而是直接走了拒绝了

  • 写回答

1条回答 默认 最新

  • CSDN-Ada助手 CSDN-AI 官方账号 2023-04-28 20:58
    关注
    • 关于该问题,我找了一篇非常好的博客,你可以看看是否有帮助,链接:sentinel 控制台讲解-流控规则 QPS和线程数的区别
    • 除此之外, 这篇博客: Sentinel的基本使用(1)-流量控制及其源码调用分析中的 1、QPS方式 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
    • public class SimpleEntryMain {
      
          private static String resourceName = "simpleEntry";
      
          public static void main(String[] args) throws InterruptedException {
              initFlowRule();
              for (int i = 0; i < 10; i++) {
                  Thread t = new Thread(new RunTask());
                  t.setName("simulate-traffic-Task");
                  t.start();
                  Thread.sleep(50);
              }
          }
      
          private static void initFlowRule() {
              List<FlowRule> rules = new ArrayList<FlowRule>();
              FlowRule rule1 = new FlowRule();
              rule1.setResource(resourceName);
              rule1.setCount(2);
              rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
              rule1.setLimitApp("default");
              rules.add(rule1);
              FlowRuleManager.loadRules(rules);
          }
      
          static class RunTask implements Runnable {
              @Override
              public void run() {
                      Entry entry = null;
                      try {
                          entry = SphU.entry(resourceName);
                          doSomeThing();
                      } catch (BlockException e1) {
                          System.out.println("Block   ----------");
                      } finally {
                          if (entry != null) {
                              entry.exit();
                          }
                      }
              }
          }
      
          public static void doSomeThing(){
              System.out.println("++++++++++++++++++");
              try {
                  Thread.sleep(3000);
              } catch (InterruptedException e) {
                  // ignore
              }
          }
      }
      

      ​ 这个demo首先是通过initFlowRule()方法设置了规则,然后我们通过多线程来模拟多个调用规则,方法的调用我们简单的模拟花费Thread.sleep(3000)也就是3秒。然后线程中运行的就是Sentinel的使用:

      Entry entry = null;
      try {
          entry = SphU.entry(resourceName);
          doSomeThing();
      } catch (BlockException e1) {
          System.out.println("Block   ----------");
      } finally {
          if (entry != null) {
              entry.exit();
          }
      }
      

      ​ 这里就是try-catch-finally的标准使用流程,其主要是通过SphU.entry(resourceName)的调用在里面解析规则的配置校验,如果能通过的话就不会抛出异常,如果不能通过就抛出BlockException异常。我们上面是直接使用,当我们在SpringBoot中直接使用的话,其本身的封装可能使用动态代理或者AOP的方式来将这里的doSomeThingSphU.entry(resourceName)的获取做解耦,我们加了注解后就可以直接专注于我们的doSomeThing()的方法逻辑。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

问题事件

  • 系统已结题 5月14日
  • 已采纳回答 5月6日
  • 创建了问题 4月28日

悬赏问题

  • ¥20 求各位懂行的人,注册表能不能看到usb使用得具体信息,干了什么,传输了什么数据
  • ¥15 个人网站被恶意大量访问,怎么办
  • ¥15 Vue3 大型图片数据拖动排序
  • ¥15 Centos / PETGEM
  • ¥15 划分vlan后不通了
  • ¥20 用雷电模拟器安装百达屋apk一直闪退
  • ¥15 算能科技20240506咨询(拒绝大模型回答)
  • ¥15 自适应 AR 模型 参数估计Matlab程序
  • ¥100 角动量包络面如何用MATLAB绘制
  • ¥15 merge函数占用内存过大