Sentinel Can servlet filter(CommonFilter) support ParamFlow?

kfgdxczn  于 2021-11-29  发布在  Java
关注(0)|答案(4)|浏览(364)

Issue Description

Type: feature request

Describe what happened (or what feature you want)

Can servlet filter support ParamFlow?
Servlet filter模式的限流(com.alibaba.csp.sentinel.adapter.servlet.CommonFilter)可以支持热点参数限流吗?

Describe what you expected to happen

ParamFlow is supported in servlet filter mode.
热点参数限流可以在servlet限流模式中被支持。

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

  1. Define a GET method by springMVC
    使用springMVC定义一个GET方法
    @GetMapping("param") public String testParam(Integer param) { LOGGER.info("Dubbo request succeed. param is [{}]", param); return "Dubbo request succeed."; }
  2. Configure a param flow rule
    如下所示,配置一条热点参数限流规则
    [ { "resource": "/param", "limitApp": "default", "grade": 1, "paramIdx": 0, "count": 1, "controlBehavior": 0, "maxQueueingTimeMs": 0, "burstCount": 0, "durationInSec": 1, "paramFlowItemList": [ { "object": "1", "count": 2, "classType": "int" } ], "clusterMode": false } ]
  3. Send a request '/param'
    发送’param‘的http请求
  4. The result is that the param flow rule is not activated.
    结果是热点参数限流规则没有生效。
  5. I found out the reason is that the com.alibaba.csp.sentinel.adapter.servlet.CommonFilter does not carry the arguments when it invoke com.alibaba.csp.sentinel.SphU#entry(java.lang.String, int, com.alibaba.csp.sentinel.EntryType)。
    初步分析,原因是CommonFilter这个类调用SphU#entry方法时,没有传入参数列表。
  6. If I define the get method like this , the param rule will be activated, because com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect carries the arguments.
    如果使用@SentinelResource来做资源定义,热点参数限流规则可以生效。

    @SentinelResource(value = "/param")
    public String testParam(Integer param) {
    LOGGER.info("Dubbo request succeed. param is [{}]", param);
    return "Dubbo request succeed.";
    }

Tell us your environment

mac,sentinel-1.8.0

Anything else we need to know?

No more.

tgabmvqs

tgabmvqs1#

是的,原因是CommonFilter这个类调用SphU#entry方法时,没有传入参数列表

目前sentinel-web-servletsentinel-spring-webmvc-adapter均不支持热点参数限流。

可能原因是,对于http request请求,不同项目可能获取参数的方式不一样。比如:
有的是get请求,参数在url里;
有的是post请求,参数在body里;
有的参数是form data形式;
有的参数是json格式;
有的参数就一个,比如body里有个data参数,data里面是具体的json格式参数;
有的不区分get/post;
SphU#entry方法最后1个参数是Object[] args,可用于支持热点参数限流。
理论上说,如果项目的请求参数格式统一,应该可以按某个标准统一获取参数,最后转换为Object[] args形式。
有什么好的建议吗?大家一起讨论下 @furaul@jasonjoo2010@sczyh30

PS:
sentinel-web-servlet模块提供了UrlCleaner扩展,
参考:https://github.com/alibaba/Sentinel/wiki/主流框架的适配#web-servlet

它可用于清洗或者过滤资源(比如将满足 /foo/:id 的 URL 都归到 /foo/* 资源下,比如通过返回""排除某个URL)
如果换个思路,基于它扩展也可实现热点参数限流。比如想对某个热点商品限流,实现一个自定义的UrlCleaner接口,
里面获取到热点商品id参数,返回带上商品id的特定URL,这样生成新的资源,结合控制台就可以单独设置该URL的限流规则
如:普通商品详情页的URL为:/product/detail,热点商品详情页URL为:/product/detail?id=xxx
然后对两个URL设置普通流控规则就好。
因为热点商品是单独的资源了,也可设置其它规则,比如降级规则。

zengzsys

zengzsys2#

我对这个问题的看法是:对于 SphU#entry 方法的调用是否可以用 protected 方法取代,在 AbstractSentinelInterceptor 中实现默认的方法,使其子类可以覆盖这个默认方法,在这个 protected 中传入 interceptor 的 pre 方法的入参,这样子类决定怎么处理参数和怎么调用 SphU#entry,我是准备在项目中重写 AbstractSentinelInterceptor 这个类。

2fjabf4q

2fjabf4q3#

这个建议是直接fork出springmvc的adapter进行自定义来实现(改为自己的package),或者使用注解方式针对某几个方法来启用热点相关的流控。

因为参数多样,且影响一定性能,这个可能较难作为通用需求(filter模式)

hl0ma9xz

hl0ma9xz4#

我觉得这只需要支持常用的一两种就可以,比如支持get/post,就已经满足90%的场景了。
其他的场景开放扩展给使用者自己实现转换即可。

相关问题