SpringCloud-Alibaba-Sentinel-服务降级-热点限流-服务熔断

x33g5p2x  于2021-12-18 转载在 其他  
字(5.9k)|赞(0)|评价(0)|浏览(385)

前言:
除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。一个服务常常会调用别的模块,可能是另外的一个远程服务、数据库,或者第三方 API 等。例如,支付的时候,可能需要远程调用银联提供的 API;查询某个商品的价格,可能需要进行数据库查询。然而,这个被依赖服务的稳定性是不能保证的。如果依赖的服务出现了不稳定的情况,请求的响应时间变长,那么调用服务的方法的响应时间也会变长,线程会产生堆积,最终可能耗尽业务自身的线程池,服务本身也变得不可用

熔断策略
Sentinel 提供以下几种熔断策略:

慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。
异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断、

慢调用比例:
最大 RT:200意思是 在200毫秒处理完这个请求
比例阀值:1 意思是是 在200毫秒处理一个请求 你设置几就就200毫秒处理几个

熔断时长:1意思是一秒内不可用
最小请求数:5 意思是 一秒5次请求

异常比例:
比例阀值:官网:(异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%)0.3意思错误的达到了百分之30的时候 触发熔断

熔断时间:1的意思是一秒之间不可用
最小请求数:5一秒5个

异常数
异常数:3意思是超过3个异常,就是第4次进入熔断服务降级,当第五次请求是对的就会恢复
熔断时长:1秒

热点参数限流
何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:

商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制
热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。

示例:
这里有两个 参数一个是A 一个是B热点限流是根据设置参数的下标设置的,下表是从0开始的,
@SentinelResource注解设置要限流的id, blockHandler设置返回可预知的响应体

@GetMapping(value = "select/test")
 @SentinelResource(value = "test",blockHandler = "teat1")
 public String test(@RequestParam(value = "a",required = false) Integer a,@RequestParam(value = "b",required = false) Integer b){

     return "我是:Sentinel";

 }

设置的可预知的响应体这个的BlockException是必须的参数

public String teat1(@RequestParam(value = "a",required = false) Integer a,@RequestParam(value = "b",required = false)Integer b, BlockException e){

     return "没错我就是我了";

 }

配置
test是@SentinelResource(value = "test",blockHandler = "teat1")
参数索引:0就是0下标
单机阀值:1处理的个数
统计窗口时长 1是一秒处理完成


高级选项

参数类型:选择参数的数据类型
参数值:1就参数如果等于1就限流
限流阀: 3就是3次

这些可以自己测试

服务熔断

Sentinel 提供了 @SentinelResource 注解用于定义资源,并提供了 AspectJ 的扩展用于自动定义资源、处理 BlockException 等。

@SentinelResource 注解

@SentinelResource 用于定义资源,并提供可选的异常处理和 fallback 配置项。 @SentinelResource 注解包含以下属性:

value:资源名称,必需项(不能为空)
entryType:entry 类型,可选项(默认为 EntryType.OUT)
blockHandler / blockHandlerClass: blockHandler 对应处理 BlockException 的函数名称,可选项。blockHandler 函数访问范围需要是 public,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException。blockHandler 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 blockHandlerClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
fallback / fallbackClass:fallback 函数名称,可选项,用于在抛出异常的时候提供 fallback 处理逻辑。fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。fallback 函数签名和位置要求:
返回值类型必须与原函数返回值类型一致;
方法参数列表需要和原函数一致,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。
fallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
defaultFallback(since 1.6.0):默认的 fallback 函数名称,可选项,通常用于通用的 fallback 逻辑(即可以用于很多服务或方法)。默认 fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。若同时配置了 fallback 和 defaultFallback,则只有 fallback 会生效。defaultFallback 函数签名要求:
返回值类型必须与原函数返回值类型一致;
方法参数列表需要为空,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。
defaultFallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
exceptionsToIgnore(since 1.6.0):用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。
1.8.0 版本开始,defaultFallback 支持在类级别进行配置。

注:1.6.0 之前的版本 fallback 函数只针对降级异常(DegradeException)进行处理,不能针对业务异常进行处理。

特别地,若 blockHandler 和 fallback 都进行了配置,则被限流降级而抛出 BlockException 时只会进入 blockHandler 处理逻辑。若未配置 blockHandler、fallback 和 defaultFallback,则被限流降级时会将 BlockException 直接抛出(若方法本身未定义 throws BlockException 则会被 JVM 包装一层 UndeclaredThrowableException)。

示例:

1,fallback处理java异常

@SentinelResource(value = "select",fallback = "ErrorFallback")

代码

@GetMapping(value = "select/{id}")
    @SentinelResource(value = "select",fallback = "ErrorFallback")
    public CommonResult getid(@PathVariable Long id){

          if(id>3) {
              throw new NullPointerException(id+"没有记录");
          }else {
              return restTemplate.getForObject(URL + "/select/" + id, CommonResult.class);
          }

    }

fallback 处理方法

public CommonResult  ErrorFallback(@PathVariable Long id,Throwable e){

        return new CommonResult<>(500,"不好意,没有此记录");
    }

处理结果

blockHandler  处理sentinel配置异常 java的异常无法处理
@SentinelResource(value = "select",blockHandler = "ErrorFallback")
public CommonResult  ErrorFallback(@PathVariable Long id, BlockException e){

        return new CommonResult<>(500,"不好意,没有此记录"+e.getMessage());
    }

测试
这设置的是异常比例 异常达到百分之30进行熔断

两个注解同时用

@SentinelResource(value = "select",blockHandler = "ErrorFallback",fallback = "ErrorFallback1")
public CommonResult  ErrorFallback1(@PathVariable Long id, Throwable e){

        return new CommonResult<>(500,"fallback:不好意,没有此记录"+e.getMessage());
    }
    public CommonResult  ErrorFallback(@PathVariable Long id, BlockException e){

        return new CommonResult<>(500,"blockHandler:不好意,没有此记录"+e.getMessage());
    }

但是 要是blockHandler 和fallback 同时配置则被限流降级抛出异常BlockException 处理

exceptionsToIgnore
@SentinelResource(value = "select",blockHandler = "ErrorFallback",fallback = "ErrorFallback1"
                      ,exceptionsToIgnore = {IllegalAccessException.class})
blockHandlerClass=定义返回统一返回方法.class

业务

@GetMapping(value = "select/test")
 @SentinelResource(value = "test",blockHandlerClass= MySentinel.class,blockHandler = "a")
 public String test(@RequestParam(value = "a",required = false) Integer a,@RequestParam(value = "b",required = false) Integer b){

     return "我是:Sentinel";

 }

熔断降级

package com.tang.cloud.mysentinel;

import com.alibaba.csp.sentinel.slots.block.BlockException;
import jdk.nashorn.internal.ir.Block;
import org.bouncycastle.crypto.engines.BlowfishEngine;
import org.springframework.web.bind.annotation.RequestParam;

/** * 统一返回降级处理 */
public class MySentinel {

   //返回的的类型和调用的方法的类型一致,参数的类型和个数相同
   public static  String a(@RequestParam(value = "a",required = false) Integer a, @RequestParam(value = "b",required = false) Integer b, BlockException excep){

       return "我在在另一个类中定义的方法";
   }
   }

相关文章