Sentinel 关于线程限流问题的讨论

ou6hu8tu  于 2021-11-29  发布在  Java
关注(0)|答案(23)|浏览(566)

Issue Description

bug report

Describe what happened (or what feature you want)

sentinel采用类似于责任链的设计模式,将统计、限流、降级、监控等功能串起来,使每个环节自责更清晰(见DefaultSlotsChainBuilder),这种设计模式对于大多数关于“数量”的统计场景是没问题的,比如QPS、错误量等。但对于线程数限流(即并发限流)这样做是有问题的,详见:https://blog.csdn.net/manzhizhen/article/details/81413014。

在Sentinel中,当前服务对线程数加(请求进来)和减(请求执行完毕)的操作是在StatisticSlot中完成的:

@Override
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count, Object... args) throws Throwable {

        // 注意: 其他代码省略
        fireEntry(context, resourceWrapper, node, count, args);
      **node.increaseThreadNum();**
}

@Override
public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
        DefaultNode node = (DefaultNode)context.getCurNode();
        // 注意: 其他代码省略
      **node.decreaseThreadNum();**
}

而线程数的限流操作是在另一个类来做的,例如SystemSlot

@Override
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count, Object... args)  throws Throwable {
  **SystemRuleManager.checkSystem(resourceWrapper);**
    fireEntry(context, resourceWrapper, node, count, args);
}

其中SystemRuleManager.checkSystem的操作如下:
public static void checkSystem(ResourceWrapper resourceWrapper) throws BlockException {

// 注意: 其他代码省略
    // total thread
    int currentThread = Constants.ENTRY_NODE == null ? 0 : Constants.ENTRY_NODE.curThreadNum();
  **if (currentThread > maxThread) {
        throw new SystemBlockException(resourceWrapper.getName(), "thread");
    }**
}

将统计和限流分开的这种方式,无法真正做到线程数量(也就是并发度)的精准控制,会有竞态条件产生,比较好的做法是用信号量来实现。

Describe what you expected to happen

How to reproduce it (as minimally and precisely as possible)

Tell us your environment

Anything else we need to know?

rt4zxlrg

rt4zxlrg16#

好的!!…

------------------------------------------------------------------ 发件人:yizhenqiang notifications@github.com 发送时间:2018年8月20日(星期一) 11:02 收件人:alibaba/Sentinel Sentinel@noreply.github.com 抄 送:林佳梁(子矜) jialiang.linjl@taobao.com; Mention mention@noreply.github.com 主 题:Re: [alibaba/Sentinel] 关于线程限流问题的讨论 (#59) @jialianglinjl@sczyh30@byamao1 我想到一种方案,通过信号量+ThreadLocal来实现,我写完到时候各位看一下 — You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.

t98cgbkg

t98cgbkg17#

@jialianglinjl@sczyh30@byamao1 我想到一种方案,通过信号量+ThreadLocal来实现,我写完到时候各位看一下

3df52oht

3df52oht18#

@byamao1 你这段代码也是有问题的,令牌桶其实很难实现并发控制的效果:https://blog.csdn.net/manzhizhen/article/details/81413014

aelbi1ox

aelbi1ox19#

用令牌的方式来限制资源被访问次数应该是可行的。与信号量差不多的思路(水平有限),只不过是利用原子类实现了令牌的个数限制。代码放在博客,有问题互相交流。

https://blog.csdn.net/byamao1/article/details/81747230

gj3fmq9x

gj3fmq9x20#

如果有办法将线程限流的判断还有加减1放在一个地方(就可以会用信号量来做了),就可以规避这个问题,而且性能不会太差,但可能会违背了现有的操作链的设计方式,不妨尝试一下

c9x0cxw0

c9x0cxw021#

太好了!! 欢迎提一个PR!!! 发件人: byamao1 [mailto:notifications@github.com] 发送时间: 2018年8月15日 15:25 收件人: alibaba/Sentinel Sentinel@noreply.github.com 抄送: 林佳梁(子矜) jialiang.linjl@taobao.com; Comment comment@noreply.github.com 主题: Re: [alibaba/Sentinel] 关于线程限流问题的讨论 (#59) 我对工程中的FlowThreadDemo进行了修改: * 开启10个线程群(1个群25个线程)进行饱和测试 * 加入CyclicBarrier保证线程群内能够同时触发SphU.entry * 在log处改造为if(oneSecondPass > 20) 测试结果来看,限流能力与methodBRunningTime有正比比关系:methodBRunningTime越小,能力越小。 下步我会结合效率和限流能力,试图找到一个平衡点方案。(有苛刻之处乃本人之误,如需测试代码可联系本人) — You are receiving this because you commented. Reply to this email directly, view it on GitHub <#59 (comment)> , or mute the thread <https://github.com/notifications/unsubscribe-auth/AgQHwIREJbPuK8Hm_0fnrHrr3knVg7X7ks5uQ8yvgaJpZM4V74Ec> . <https://github.com/notifications/beacon/AgQHwGt2fII3L3u401OObTU2HoGfM_bOks5uQ8yvgaJpZM4V74Ec.gif>

vohkndzv

vohkndzv22#

我对工程中的FlowThreadDemo进行了修改:

  • 开启10个线程群(1个群25个线程)进行饱和测试
  • 加入CyclicBarrier保证线程群内能够同时触发SphU.entry
  • 在log处改造为if(oneSecondPass > 20),使得显示的log为超限情境

测试结果来看,限流能力与methodBRunningTime有正比比关系:methodBRunningTime越小,能力越小。

下步我会结合效率和限流能力,试图找到一个平衡点方案。(有苛刻之处乃本人之误,如需测试代码可联系本人)

6qqygrtg

6qqygrtg23#

这里面不做同步的一个重要的原因,是一个性能的平衡. 如果我们在所有的检查中都加锁,会带来一个性能的骤降;所以我们选择了放弃处理这种极端情况. 如果有什么好的建议,也请告知我们。 Regards, 发件人: byamao1 [mailto:notifications@github.com] 发送时间: 2018年8月15日 13:59 收件人: alibaba/Sentinel Sentinel@noreply.github.com 抄送: Subscribed subscribed@noreply.github.com 主题: Re: [alibaba/Sentinel] 关于线程限流问题的讨论 (#59) 我同意这个issue。源码中确实会存在这种可能。DefaultProcessorSlotChain中首先会进行例如FlowSlot.entry的检查,然后才会在StatisticSlot.entry进行统计数量。如果不使用同步机制,有可能会同时几个线程同时调用DefaultProcessorSlotChain超过线程上限。 — You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub <#59 (comment)> , or mute the thread <https://github.com/notifications/unsubscribe-auth/AgQHwEniJJTkmmTnkR5lUO-aWw-cxf86ks5uQ7iTgaJpZM4V74Ec> . <https://github.com/notifications/beacon/AgQHwNZXXD0DTyG0TZUTXLmyvFBR-_IDks5uQ7iTgaJpZM4V74Ec.gif>

相关问题