Sentinel 流控规则详解(上)

简介: 在前面两篇文章给大家介绍了 Sentinel 的功能和基本使用。现在我们继续来学习 Sentinel 控制台的基本使用,以及一些规则配置的说明。让大家能够在工作中使用 Sentinel 得心应手 (大部分理论和描述来源于官方文档和网络)。

在前面两篇文章给大家介绍了 Sentinel 的功能和基本使用。现在我们继续来学习 Sentinel 控制台的基本使用,以及一些规则配置的说明。让大家能够在工作中使用 Sentinel 得心应手 (大部分理论和描述来源于官方文档和网络)。


在正文开始之前,我先说一下我的基本环境信息


  • jdk 1.8


  • sentinel 1.8.0


  • spring-boot 2.3.5.RELEASE


  • spring-cloud Hoxton.SR8


  • spring-cloud-alibaba 2.2.5.RELEASE


控制台简介


Sentinel 提供一个轻量级的开源控制台,它提供机器发现以及健康情况管理、监控(单机和集群),规则管理和推送的功能。这里,我们将会详细讲述如何通过简单的步骤就可以使用这些功能。


Sentinel 控制台包含如下功能:


  • 查看机器列表以及健康情况:收集 Sentinel 客户端发送的心跳包,用于判断机器是否在线。


  • 监控 (单机和集群聚合):通过 Sentinel 客户端暴露的监控 API,定期拉取并且聚合应用监控信息,最终可以实现秒级的实时监控。


  • 规则管理和推送:统一管理推送规则。


  • 鉴权:生产环境中鉴权非常重要。这里每个开发者需要根据自己的实际情况进行定制。


注意:Sentinel 控制台目前仅支持单机部署。Sentinel 控制台项目提供 Sentinel 功能全集示例,不作为开箱即用的生产环境控制台,若希望在生产环境使用需要自行定制和改造


Alibaba 提供了企业版本的 Sentinel 我们可以在 aliyun.com 上面购买 AHAS  Sentinel


查看机器列表以及健康情况


如果我们正确的接入 Sentinel 之后我们可以在 Sentinel 控制台的 机器列表 菜单中来查看我们服务节点的健康情况


image.png


如果 Sentinel 接入不成功,可以查阅 Sentinel 官方文档或者 FAQ 来对应排查


服务监控


1. 实时监控


同时,同一个服务下的所有机器的簇点信息会被汇总,并且秒级地展示在"实时监控"下。


注意: 实时监控仅存储 5 分钟以内的数据,如果需要持久化,需要通过调用实时监控接口来定制。


image.png


注意:请确保 Sentinel 控制台所在的机器时间与自己应用的机器时间保持一致,否则会导致拉不到实时的监控数据。


2. 簇点链路


簇点链路(单机调用链路)页面实时的去拉取指定客户端资源的运行情况。它一共提供两种展示模式:一种用树状结构展示资源的调用链路,另外一种则不区分调用链路展示资源的实时情况。


注意: 簇点链路监控是内存态的信息,它仅展示启动后调用过的资源。


image.png


注意:请确保 Sentinel 控制台所在的机器时间与自己应用的机器时间保持一致,否则会导致拉不到实时的监控数据。


3 流控规则


流量控制(flow control),其原理是监控应用流量的 QPS 或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。


FlowSlot 会根据预设的规则,结合 NodeSelectorSlotClusterBuilderSlotStatisticSlot 统计出来的实时信息进行流量控制。


image.png


限流的直接表现是在执行 Entry nodeA = SphU.entry(resourceName) 的时候抛出 FlowException 异常。FlowExceptionBlockException 的子类,您可以捕捉 BlockException 来自定义被限流之后的处理逻辑。


Sentinel 在触发规则保护时,返回的异常页面是一样的。不好区分是因为哪种规则导致的异常。所以需要自定义异常返回信息,明确是触发了哪种类型的规则。


@Component
public class SentinelBlockHandler implements BlockExceptionHandler {
    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
                       BlockException e) throws Exception {
        CommonResult<Void> result = new CommonResult<>();
        if (e instanceof FlowException) {
            result = CommonResult.error(101, "接口限流了");
        } else if (e instanceof DegradeException) {
            result = CommonResult.error(102, "服务降级了");
        } else if (e instanceof ParamFlowException) {
            result = CommonResult.error(103, "热点参数限流了");
        } else if (e instanceof SystemBlockException) {
            result = CommonResult.error(104, "系统规则(负载/...不满足要求)");
        } else if (e instanceof AuthorityException) {
            result = CommonResult.error(105, "授权规则不通过");
        }
        // http状态码
        httpServletResponse.setStatus(500);
        httpServletResponse.setCharacterEncoding("utf-8");
        httpServletResponse.setHeader("Content-Type", "application/json;charset=utf-8");
        httpServletResponse.setContentType("application/json;charset=utf-8");
        // spring mvc自带的json操作工具,叫jackson
        new ObjectMapper().writeValue(httpServletResponse.getWriter(), result);
    }
}


效果如下:


➜ curl http://127.0.0.1:8088/getStockDetail
{"code":1,"message":"this is a success message","data":{"id":1,"code":"STOCK==>1000"}}%                                                       ➜ curl http://127.0.0.1:8088/getStockDetail
{"code":1,"message":"this is a success message","data":{"id":1,"code":"STOCK==>1000"}}%                                                        ➜ curl http://127.0.0.1:8088/getStockDetail
{"code":101,"message":"接口限流了","data":null}%        


阈值类型


线程数


并发数控制用于保护业务线程池不被慢调用耗尽。例如,当应用所依赖的下游应用由于某种原因导致服务不稳定、响应延迟增加,对于调用者来说,意味着吞吐量下降和更多的线程数占用,极端情况下甚至导致线程池耗尽。为应对太多线程占用的情况,业内有使用隔离的方案,比如通过不同业务逻辑使用不同线程池来隔离业务自身之间的资源争抢(线程池隔离)。这种隔离方案虽然隔离性比较好,但是代价就是线程数目太多,线程上下文切换的 overhead 比较大,特别是对低延时的调用有比较大的影响。Sentinel 并发控制不负责创建和管理线程池,而是简单统计当前请求上下文的线程数目(正在执行的调用数目),如果超出阈值,新的请求会被立即拒绝,效果类似于信号量隔离。并发数控制通常在调用端进行配置。


image.png


可以通过线程池模拟客户端调用, 也可以通过  Jmeter 模拟,触发流控的结果如下:


➜  ~ curl http://127.0.0.1:8088/getStockDetail
{"code":101,"message":"接口限流了","data":null}%    


流控模式


调用关系包括调用方、被调用方;一个方法又可能会调用其它方法,形成一个调用链路的层次关系。


直接


当资源触发流控规则过后直接,抛出异常信息


➜  ~ curl http://127.0.0.1:8088/getStockDetail
{"code":101,"message":"接口限流了","data":null}%


关联


当两个资源之间具有资源争抢或者依赖关系的时候,这两个资源便具有了关联。比如对数据库同一个字段的读操作和写操作存在争抢,读的速度过高会影响写得速度,写的速度过高会影响读的速度。如果放任读写操作争抢资源,则争抢本身带来的开销会降低整体的吞吐量。可使用关联限流来避免具有关联关系的资源之间过度的争抢,举例来说,read_dbwrite_db 这两个资源分别代表数据库读写,我们可以给 read_db 设置限流规则来达到写优先的目的:设置 strategyRuleConstant.STRATEGY_RELATE 同时设置 refResourcewrite_db。这样当写库操作过于频繁时,读数据的请求会被限流。


image.png


如果配置流控规则为关联模式,那么当 /hello 接口超过阈值过后,就会对 /getStockDetail 接口触发流控规则。


链路


NodeSelectorSlot 中记录了资源之间的调用链路,这些资源通过调用关系,相互之间构成一棵调用树。这棵树的根节点是一个名字为 machine-root 的虚拟节点,调用链的入口都是这个虚节点的子节点。


一棵典型的调用树如下图所示:


machine-root
                    /       \
                   /         \
             Entrance1     Entrance2
                /             \
               /               \
      DefaultNode(nodeA)   DefaultNode(nodeA)


上图中来自入口 Entrance1Entrance2 的请求都调用到了资源 NodeA,Sentinel 允许只根据某个入口的统计信息对资源限流。比如我们可以设置 strategyRuleConstant.STRATEGY_CHAIN,同时设置 refResourceEntrance1 来表示只有从入口 Entrance1 的调用才会记录到 NodeA 的限流统计当中,而不关心经 Entrance2 到来的调用。


调用链的入口(上下文)是通过 API 方法 ContextUtil.enter(contextName) 定义的,其中 contextName 即对应调用链路入口名称。详情可以参考 ContextUtil 文档。]


image.png


测试会发现 链路 不会生效


从1.6.3版本开始,Sentinel Web filter默认收敛所有URL的入口context,因此链路限流不生效。1.7.0版本开始(对应SCA 2.1.1.RELEASE),我们在CommonFilter引入了WEB_CONTEXT_UNIFY这个init parameter,用于控制是否收敛context。将其配置为false即可根据不同的URL进行链路限流。 参考:github.com/alibaba/sen…


解决方案:


1.7.0 版本开始(对应Spring Cloud Alibaba的2.1.1.RELEASE) 需要新增依赖


@Configuration
public class FilterContextConfig {
    @Bean
    public FilterRegistrationBean sentinelFilterRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new CommonFilter());
        registration.addUrlPatterns("/*");
        // 入口资源关闭聚合
        registration.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY, "false");
        registration.setName("sentinelFilter");
        registration.setOrder(1);
        return registration;
    }
}


然后我们再尝试触发流控规则, 对 /getStockDetail 进行访问,这里返回了

FlowException


image.png


默认情况会返回


image.png


如果我们使用 OpenFeign 不添加 fallbackFactory 就会返回500 , 如果我们添加了就可以避免这个问题。


// Controller
@Autowired
private StockFeign stockFeign;
@GetMapping("/getStockDetail")
public CommonResult<StockModel> getStockDetail() {
  CommonResult<StockModel> result = stockFeign.getStockDetail();
  if (result.getCode() != 1) {
    return CommonResult.error(null, result.getCode(), result.getMessage());
  }
  return result;
}
// FeignClient
@FeignClient(name = "stock-service")
        //, fallbackFactory = StockFeignFallbackFactory.class)
public interface StockFeign {
    @GetMapping("/getStockDetail")
    CommonResult<StockModel> getStockDetail();
}


Sentinel 部分源码:


image.png


所以,我们在设置链路流控规则的时候一定要设置 fallbackFactory。 不然无法处理 FlowExecption 异常信息,造成系统出错。对于个人而言,Sentinel 的链路规则比不是特别的好用,无特殊要求,不建议使用,或者选择Sentinel 的收费版本 AHAS


相关文章
|
存储 JSON SpringCloudAlibaba
Sentinel使用及规则配置
Sentinel使用及规则配置
1255 0
Sentinel使用及规则配置
|
3月前
|
监控 测试技术 数据安全/隐私保护
如何集成Sentinel实现流控、降级、热点规则、授权规则总结
如何集成Sentinel实现流控、降级、热点规则、授权规则总结
78 0
|
4月前
|
消息中间件 Java API
一文带你速通Sentinel限流规则(流控)解读
一文带你速通Sentinel限流规则(流控)解读
|
5月前
|
监控 Java 数据安全/隐私保护
sentinel流控降级与熔断
sentinel流控降级与熔断
52 0
|
9月前
|
监控 Dubbo Java
Alibaba Sentinel | 流控规则设置
Alibaba Sentinel | 流控规则设置
|
9月前
|
Dubbo 应用服务中间件 API
Alibaba Sentinel | 熔断规则详解
Alibaba Sentinel | 熔断规则详解
|
Java 开发者 Sentinel
Sentinel 手动实现限流规则 | 学习笔记
快速学习 Sentinel 手动实现限流规则
205 0
|
监控 数据库 数据安全/隐私保护
【Sentinel】流控模式
【Sentinel】流控模式
149 0
【Sentinel】流控模式
|
监控 Sentinel 微服务
【Sentinel】流控效果与热点参数限流
【Sentinel】流控效果与热点参数限流
305 0
【Sentinel】流控效果与热点参数限流
|
Java 测试技术 开发者
流控规则-流控效果|学习笔记
快速学习流控规则-流控效果
154 0
流控规则-流控效果|学习笔记