Springcloudalibaba之Sentinel服务熔断与限流

一、什么是Sentinel?

  它是分布式系统的流量防卫兵,与Hystrix的作用一样,它能保证在某一个服务出现问题的情况下,不会导致整体服务的联级故障,以提高分布式系统的弹性。它是hystrix的替代品。比起hystrix来说,Sentinel可以通过web界面来进行更加细粒度的配置流控、速率控制、服务熔断、服务降级。Sentinel组件由Java客户端和Dashboard构成。sentinel生态圈和主要功能特性如下

   二、Sentinel使用

  1、安装和启动: 去https://github.com/alibaba/Sentinel/releases下载sentinel-dashboard-1.8.2.jar包,运行前需要安装Java8环境,切换到jar包目录cmd执行 java -jar sentinel-dashboard-1.8.2.jar --server.port=8080即可启动。访问http://localhost:8080即可显示web控制台登录界面(默认账号密码sentinel)。

   2、创建服务模块

    a.引入jar包

< ! --Springcloud ailibaba sentinel -->
<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

    b.修改yml配置文件,配置Sentinel dashboard地址

server:
  port: 8401

spring:
   application:
       name: cloudalibaba-sentinel-service
   cloud:
       nacos:
          discovery:
             server-addr: localhost:8848
       sentinel:
           transport:
               #配置sentinel dashboard地址
               dashboard: localhost:8080
              #默认8719端口,假如被占角会自动从8719开始依次+1扫描,直至找到未被占用的端口
               port: 8719

management:
    endpoints:
       web:
          exposure:
              include: "*"

    c.编写微服务接口Controller,到此sentinel监控搭建完,访问sentinel控制台,即可显示被监控的8848微服务(sentinel懒加载-需要先调用一次8848服务接口才能显示)。界面如下

三、Sentinel流控规则

  Sentinel支持流量控制,它监控应用流量的QPS或并发线程数等指标,当达到指定阈值时对流量进行控制,避免系统被瞬时的流量高峰冲垮,保障应用高可用性。

    1.阈值类型:

      QPS:每秒请求数,当前调用该api的QPS到达阈值的时候进行限流。

            线程数:当调用该api的线程数到达阈值的时候,进行限流。

    2.流控模式:

      直接:当api大达到限流条件时,直接限流

      关联:当关联的资源到达阈值,就限流自己

      链路:只记录指定路上的流量,指定资源从入口资源进来的流量,如果达到阈值,就进行限流,api级别的限流

    3.流控效果:

      快速失败:直接返回失败、抛异常

      预热(WarmUP):当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。

      排队等待:会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。

  以下配置界面:

 四、Sentnel熔断降级

  Sentinel熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛出 DegradeException)。Sentinel降级策略包含平均响应时间RT、异常比例、异常数。

  平均响应时间(DEGRADE_GRADE_RT):当1s内持续进入5个请求,对应时刻的平均响应时间(秒级)均超过阈值( count,以ms为单位),那么在接下的时间窗口(以s为单位)之内,对这个方法的调用都会自动地熔断(抛出DegradeException )。注意Sentinel默认统计的RT上限是4900 ms,超出此阈值的都会算作4900ms,若需要变更此上限可以通过启动配置项-Dcsp.sentinel.statistic.max.rt=xx来配置。

  异常比例( DEGRADE_GRADE_EXCEPTION_RATIo ):当资源的每秒请求量>=5,并且每秒异常总数占通过量的比值超过阈值( DegradeRule 中的 count)之后,资源进入降级状态,即在接下的时间窗口( DegradeRule中的 timewindow,以s为单位)之内,对这个方法的调用都会自动地返回。异常比率的阈值范围是[0.0,1.0],代表0% - 100%。

  异常数( DEGRADE_GRADE_EXCEPTION_coUNT ):当资源近1分钟的异常数目超过阈值之后会进行熔断。注意由于统计时间窗口是分钟级别的,若 timevindow小于60s,则结束熔断状态后仍可能再进入熔断状态。

  以下是配置界面:

 五、热点参数限流

  热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的TopK数据,并对其访问进行限制。比如:·用户ID为参数,针对一段时间内频繁访问的用户ID进行限制。

  热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。

  1、启用热点参数限流功能:

    a.在服务模块中引入如下依赖:

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-parameter-flow-control</artifactId> 
</dependency>

    b.为对应的资源接口配置热点参数限流规则,在调用的时候传入相应的参数,即可使热点参数限流生效。举例如下:

@GetMapping("/getHotKey") 
@SentinelResource(value = "testHotKey" ,blockHandler = "deal_testHotKey")  //blockHandler指定兜底方法,value指定资源名
public string getHotKey(@RequestParam(value = "p1") string p1,@RequestParam(value = "p2") string p2) 
{  
  return "------testHotKey" ; 
}
public string deal_testHotKey (string p1,string p2,BlockException exception)
{
  return "------deal_testHotKey,o(T-T)o" ;
}

     结合以上代码和配置规则,表示:当请求http://localhost:8401/getHotKey?p1=xxxx&p2=xxx资源接口的时候,如果该方法第一个参数每秒的QPS超过1次,就马上降级调用兜底方法deal_testHotKey 。(如果不配置blockHandler,会使用系统默认的兜底方法返回Blocked by Sentinel (flow limiting)或将异常显示到前台,不推荐这样做)

   2、限流规则中参数例外项:在1中,当热点参数是某个特殊值的时候,我们要求不降级限流怎么办?配置规则里提供了参数例外项来解决这个问题,具体如下,通过添加规则组来对每个特殊值添加不同的阈值。 

六、系统规则

  系统保护规则是从应用级别的入口流量进行控制,从单台机器的load、CPU使用率、平均RT、入口QPS和并发线程数等几个维度监控应用指标,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量( EntryType.IN ),比如Web服务或Dubbo服务端接收的请求,都属于入口流量。系统规则支持以下模式:

  1、Load自适应(仅对 Linux/Unix-like机器生效):系统的load1作为启发指标,进行自适应系统保护。当系统load1超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR阶段)。系统容量由系统的 maxQps * minRt估算得出。设定参考值一般是CPu cores * 2.5。

  2、CPU使用率(1.5.0+版本)︰当系统CPU使用率超过阈值即触发系统保护(取值范围0.0-1.0) ,比较灵敏。

  3、平均RT:当单台机器上所有入口流量的平均RT达到阈值即触发系统保护,单位是毫秒。

  4、并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。

  5、入口QPS:当单台机器上所有入口流量的QPS达到阈值即触发系统保护。

  规则配置如图:

 七、自定义限流处理逻辑

  在编码过程中,我们通常需要将业务逻辑与异常处理代码分离,实现解耦。在上面的例子中业务逻辑代码和兜底方法在同一个类中,显然不合适,sentinel提供的注解@SentinelResource注解提供了一个blockHandelClass特性能够方便我们进行代码分离。实现过程如下:

  1、创建一个专门的兜底方法类CustomerBlockHandler

public class  CustomerBlockHandler
{
public static CommonResult handleException(BlockException exception)
{
return new CommonResult( code: 200,message:"自定义的限流处理信息");
}
public static commonResult handleException2(BlockException exception)
{
return new CommonResult( code: 200,message:"自定义的限流处理信息2");
}
}

  2、在资源接口方法上增加注解@SentinelResource(value = "customerBlockHandler",blockHandlerclass= CustomerBlockHandler.class,blockHandler = "handleException”)

@GetMapping("/rateLimit/customerBlockHandler")
@SentinelResource(value = "customerBlockHandler", blockHandlerclass = customerBlockHandler.class, //指定兜底类
blockHandler= "handlerException") //指定兜底类中的兜底方法 public commonResult customerBlockHandler()
{
return new CommonResult( code: 200,message:"按客户自定义" , new Payment(id: 2020L,serial:."serial003"));
}

 八、资源接口逻辑异常处理

  前面的@SentinelResource的blockHandler指定方法只用于不满足sentinel控制台配置规则时的兜底,本身并不处理资源接口的异常,该注解提供了另外一个特性fallback,用于指定资源接口内部异常时要执行的兜底方法。例如

@sentinelResource(value = "fallback" ,fallback = "handlerFallback")  //fallback只负责业务异常
public commonResult<Payment> fallback(@Pathvariable Long id)
{
      CommonResult<Payment> result =restTemplate.getForobject(url:SERVICE_URL + "/paymentsQL/"+id ,commonResult.class,id);
    if (id == 4) 
    {
         throw new IllegalArgumentException ("IllegalArgumentException,非法参数异常....");
    }
    return result;
}

//业务逻辑异常时执行
public CommonResult handlerFallback(@Pathvariable Long id, Throwable e) { Payment payment = new Payment(id, serial: "nu1l"); return new CommonResult<>( code: 44, message:"兜底异常FandlerFallback,exception内容"+t .getMessage(), payment); }

  异常忽略:sentinel提供了一个特性exceptionsToIgnore = {illegalArgumentException.class}用于忽略资源接口异常,表示如果触发该类型的异常,就不再用fallback兜底,不会触发降级,让其自行处理后续。

九、Sentinel规则持久化

  前面的规则配置在微服务重启后会丢失,也就是说他们的配置是临时的,我们需要对这些业务规则进行持久化。我们将限流规则持久化进nacos,只要刷新微服务,就可以看到之前配置的规则。实现方式如下:

  1、在微服务中引入jar包

<! --Springcloud ailibaba sentinel-datasource-nacos做持久化用到-->

<dependency>
   <groupId>com.alibaba.csp</groupId>
   <artifactId>sentinel-datasource-nacos</artifactId>
   <version>2.0.0-alpha</version>
</dependency>

  2、yml配置文件中增加nacos数据源配置

spring:
   cloud:
      sentinel:
         transport:
             port:8719
          datasource:
               ds1:
                   nacos:
                      server-addr: localhost:8848
                      dataId: ${spring.application.name}-sentinel-flow-rules.json
groupId: DEFAULT_GROUP
data
-type: json
rule
-type: flow

  3、登录nacos控制台配置流控规则:配置列表文件下新增配置${spring.application.name}-sentinel-flow-rules.json,选json格式,填入如下json示例代码

[ 
  {
    "resource":"/rateLimit/byUrl",
    "limitApp": "default",
    "grade": 1,
     "count": 1,
     "clusterMode": false
   }
]

  json中内容表示配规则,其中,resource表示资源名,limitApp表示来源应用,grade表示阈值类型-0线程数1QPS,count表示单机阈值,strategy表示流控模式-0直接1关联2链路,controBehavior表示流控效果-0快速失败1Warmup2排队等待,clusterMode表示是否集群。

 
posted @ 2021-10-17 15:44  我若安好,便是晴天  阅读(397)  评论(0编辑  收藏  举报