开发者社区 > 云原生 > 正文

Netty Channel接入Sentinel实现QPS限流

Netty Channel Handler 接入Sentinel实现请求拦截完成QPS流量控制,但限流规则并未生效。Netty每个请求以Channel为粒度进行处理,Sentinel只支持线程为粒度进行请求的限流吗??

private static void initFlowRule() {
    List<FlowRule> rules = new ArrayList<>();
    FlowRule rule1 = new FlowRule();
    rule1.setResource("/mercury/onOff");
    // set limit qps to 20
    rule1.setCount(20);
    rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
    rule1.setLimitApp("abc");
    rules.add(rule1);
    FlowRuleManager.loadRules(rules);
}

通过定义上诉流量控制规则,QPS最大值为20次,但是规则并没有生效

Netty Handler拦截器代码:

/** * @author pez1420@gmail.com * @version $ID: SentinelRateLimiterFilter.java v 0.1 2018/8/29 13:46 pez1420 Exp $$ */ public class SentinelRateLimiterFilter extends HttpRequestFilter { static { initFlowRule(); }

private static void initFlowRule() {
    List<FlowRule> rules = new ArrayList<>();
    FlowRule rule1 = new FlowRule();
    rule1.setResource("/mercury/onOff");
    // set limit qps to 20
    rule1.setCount(20);
    rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
    rule1.setLimitApp("abc");
    rules.add(rule1);
    FlowRuleManager.loadRules(rules);
}

@Override
public HttpResponse doFilter(HttpRequest copyRequest, NettyHttpServletRequest nettyRequest,
                             ChannelHandlerContext channelHandlerContext) {

    Channel channel = channelHandlerContext.channel();
    ApiConfigDTO apiConfigDTO = ChannelUtils.getAttribute(channel,
        HttpRequestUtils.APICONFIG_ATTRIBUTE);

    Entry entry = null;

    try {
        String target = apiConfigDTO.getFrontPath();
        ContextUtil.enter(target);
        entry = SphU.entry(target, EntryType.IN);
    } catch (DegradeException e) {
        Tracer.trace(e);
        return HttpRequestUtils
            .toJsonResponse(
                ApiResponse.error(
                    new Message(ErrorCodeEnum.DEGRADE_ERROR.getCode(),
                        ErrorCodeEnum.DEGRADE_ERROR.getMsg()),
                    ChannelUtils.getTraceId(channel)));
    } catch (BlockException e) {
        Tracer.trace(e);
        return HttpRequestUtils
            .toJsonResponse(ApiResponse.error(
                new Message(ErrorCodeEnum.RATE_LIMIT_ERROR.getCode(),
                    ErrorCodeEnum.RATE_LIMIT_ERROR.getMsg()),
                ChannelUtils.getTraceId(channel)));
    } catch (Exception e4) {
        Tracer.trace(e4);
        return HttpRequestUtils
            .toJsonResponse(ApiResponse.error(
                new Message(ErrorCodeEnum.RATE_LIMIT_ERROR.getCode(),
                    ErrorCodeEnum.RATE_LIMIT_ERROR.getMsg()),
                ChannelUtils.getTraceId(channel)));
    } finally {
        if (entry != null) {
            entry.exit();
        }
        ContextUtil.exit();
    }

    return null;
}

}

ContextUtil.enter() 创建资源上下文,从代码实现可以看出是以ThreadLocal线程变量完成上下文的统计。

*/ public class ContextUtil {

/**
 * Store the context in ThreadLocal for easy access.
 */
private static ThreadLocal<Context> contextHolder = new ThreadLocal<Context>();

/**
 * Holds all {@link EntranceNode}
 */
private static volatile Map<String, DefaultNode> contextNameNodeMap = new HashMap<String, DefaultNode>();

private static final ReentrantLock LOCK = new ReentrantLock();
private static final Context NULL_CONTEXT = new NullContext();

原提问者GitHub用户JavaPentesters

展开
收起
码字王 2023-05-19 19:39:12 170 0
1 条回答
写回答
取消 提交回答
  • 您的流量规则设置不正确,我认为您可能误解了FlowRule.limitApp的意思。只要将此字段设置为“默认”,您当前的测试就可以工作。

    原回答者GitHub用户CarpenterLee

    2023-05-19 22:09:34
    赞同 展开评论 打赏
问答分类:
问答地址:

阿里云拥有国内全面的云原生产品技术以及大规模的云原生应用实践,通过全面容器化、核心技术互联网化、应用 Serverless 化三大范式,助力制造业企业高效上云,实现系统稳定、应用敏捷智能。拥抱云原生,让创新无处不在。

相关电子书

更多
阿里云容器 AHAS Sentinel 网关流控揭秘 立即下载
workshop专场-微服务专场-开发者动手实践营-微服务-使用Sentinel进行微服务流量控制 立即下载
Sentinel分布式系统下的流量防卫兵 立即下载