SpringCloud高级(三) ——SpringCloud Alibaba Sentinel篇四

定义资源

默认对Web请求进行流量控制,如何自定义的去保护一个资源呢?

方式一:主流框架的默认适配
方式二:抛出异常的方式定义资源
方式三:返回布尔值方式定义资源
方式四:注解方式定义资源
方式五:异步调用支持

一、注解方式定义资源 - @SentinelResource

按资源名称限流+后续处理

启动Nacos成功,启动Sentinel成功。
业务类:

@RestController
public class RateLimitController {
    @GetMapping("/byResource")
    @SentinelResource(value = "byResource", blockHandler = "handleException")
    public CommonResult byResource() {

        return new CommonResult(200, "按资源名称限流测试OK", new Payment(2020L, "serial001"));
    }

    public CommonResult handleException(BlockException exception) {
        return new CommonResult(444, exception.getClass().getCanonicalName() + "\t 服务不可用");
    }
}

启动项目。
配置流控规则:
在这里插入图片描述
在这里插入图片描述
访问接口:http://localhost:8401/byResource 测试规则是否生效。
测试完后,把项目停了。
发现,规则没了!!
在这里插入图片描述
Sentinel控制台,流控规则是临时的!

按照Url地址限流+后续处理

0在这里插入图片描述

上面兜底方法面临的问题

在这里插入图片描述

客户自定义限流处理逻辑

解决上述问题。
自定义限流处理类:

public class CustomerBlockHandler {
    public static CommonResult handleException1(BlockException exception) {
        return new CommonResult(2020, "自定义限流处理信息....CustomerBlockHandler....1");
    }
    public static CommonResult handleException2(BlockException exception) {
        return new CommonResult(2020, "自定义限流处理信息....CustomerBlockHandler....2");
    }
}

业务代码:

@GetMapping("/rateLimit/customerBlockHandler")
@SentinelResource(value = "customerBlockHandler", //资源名
        blockHandlerClass = CustomerBlockHandler.class, //自定义限流处理类
        blockHandler = "handleException2")   //使用自定义限流处理类中的哪一个方法
public CommonResult customerBlockHandler()
{
    return new CommonResult(200,"按客戶自定义",new Payment(2020L,"serial003"));
}

启动微服务后,先调用一次:触发一下懒加载。

http://localhost:8401/rateLimit/customerBlockHandler

添加流控规则:
在这里插入图片描述
快速访问:http://localhost:8401/rateLimit/customerBlockHandler
在这里插入图片描述

更多注解属性说明

在这里插入图片描述
Sentinel其实可以通过代码的方式去配置各种规则,不过不推荐
Sentinel主要有三个核心API

  1. SphU定义资源
  2. Tracer定义统计
  3. ContextUtil定义了上下文

二、抛出异常的方式定义资源

// 1.5.0 版本开始可以利用 try-with-resources 特性(使用有限制)
// 资源名可使用任意有业务语义的字符串,比如方法名、接口名或其它可唯一标识的字符串。
try (Entry entry = SphU.entry("resourceName")) {
  // 被保护的业务逻辑
  // do something here...
} catch (BlockException ex) {
  // 资源访问阻止,被限流或被降级
  // 在此处进行相应的处理操作
}

注意:若 entry 的时候传入了热点参数,那么 exit 的时候也一定要带上对应的参数(exit(count, args)),否则可能会有统计错误。这个时候不能使用 try-with-resources 的方式。另外通过 Tracer.trace(ex) 来统计异常信息时,由于 try-with-resources 语法中 catch 调用顺序的问题,会导致无法正确统计异常数,因此统计异常信息时也不能在 try-with-resources 的 catch 块中调用 Tracer.trace(ex)。

Entry entry = null;
// 务必保证 finally 会被执行
try {
  // 资源名可使用任意有业务语义的字符串,注意数目不能太多(超过 1K),超出几千请作为参数传入而不要直接作为资源名
  // EntryType 代表流量类型(inbound/outbound),其中系统规则只对 IN 类型的埋点生效
  entry = SphU.entry("自定义资源名");
  // 被保护的业务逻辑
  // do something...
} catch (BlockException ex) {
  // 资源访问阻止,被限流或被降级
  // 进行相应的处理操作
} catch (Exception ex) {
  // 若需要配置降级规则,需要通过这种方式记录业务异常
  Tracer.traceEntry(ex, entry);
} finally {
  // 务必保证 exit,务必保证每个 entry 与 exit 配对
  if (entry != null) {
    entry.exit();
  }
}

热点参数埋点示例:

Entry entry = null;
try {
    // 若需要配置例外项,则传入的参数只支持基本类型。
    // EntryType 代表流量类型,其中系统规则只对 IN 类型的埋点生效
    // count 大多数情况都填 1,代表统计为一次调用。
    entry = SphU.entry(resourceName, EntryType.IN, 1, paramA, paramB);
    // Your logic here.
} catch (BlockException ex) {
    // Handle request rejection.
} finally {
    // 注意:exit 的时候也一定要带上对应的参数,否则可能会有统计错误。
    if (entry != null) {
        entry.exit(1, paramA, paramB);
    }
}

在这里插入图片描述

网关流控

在网关模块里,依赖:

<!--sentinel与gateway的自动配置-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
    <version>2.2.0.RELEASE</version>
</dependency>

1.7.1会有一个API管理,1.7.2没有
在这里插入图片描述
网关路由的id就是上面的API名称
在这里插入图片描述

一、添加流控规则

在这里插入图片描述

  • 间隔表示统计的时间窗口,单位是秒,至少是1秒。上面的表示2秒统计一次
  • burst:应对突发请求时额外允许的请求数量。

针对请求属性设置流控规则:
在这里插入图片描述
在这里插入图片描述

二、自定义网关流控响应

@Configuration
public class SentinelGatewayConfig {
    public SentinelGatewayConfig(){
        GatewayCallbackManager.setBlockHandler(new BlockRequestHandler() {
            /**
             * 网关限流了请求,就会调用此回调
             * @param serverWebExchange
             * @param throwable
             * @return
             */
            @Override
            public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
                R error = R.error(BizCodeEnum.TOO_MANY_REQUEST.getCode(), BizCodeEnum.TOO_MANY_REQUEST.getMessage());
                String string = JSON.toJSONString(error);
                return ServerResponse.ok().body(Mono.just(string), String.class);
            }
        });
    }
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_42412601/article/details/107307975