SpringCloud Alibaba入门教程三——容错保护

Sentinel API

Sentinel API(手动try-catch)

Sentinel不光可以保护SpringMVC层面的接口,还可以保护其他的接口API

spring:
  cloud:
    sentinel:
      filter:
        enabled: false  #关闭对SpringMVC端点的保护

上面是关闭了SpringMVC的保护,下方是对其他资源的保护。

@GetMapping("/sentinel-api")
public String testSentinelAPI(){
  //创建一个sentinel保护的资源端点
  Entry entry = null;
  try{
    SphU.entry("sentinel-api");
    //下方代码就是要被保护的业务逻辑
  }catch(BlockException e){
  //如果被保护的资源被限流或者被降级了,就会抛出该异常
  }finally{
    entry.exit();
  }
}

ContentUtil.enter(“资源名称”,“表明用什么服务去访问”);
Tracer.trace(e) 统计其他异常发生的次数以及占比。放在非BlockException中。

Sentinel Resource

@GetMapping("/sentinel-api")
@SentinelResource(value="sentinel-api",
                  blockHandler="block",
                  fallback="fallback")
public String testSentinelAPI(@RequestParam("a") String a){
  //这里可以直接写业务逻辑代码
  
}

public String block(String a, BlockException e){
	//这里是处理BlockException的地方
}

public String fallback(String a,Throwable e){
	//这里是处理其他异常的地方
}

Sentinel对RestTemplate的支持

在RestTemplate的声明类上添加@SentinelRestTemplate注解,就可以让Sentinel监控到这个RestTemplate,从而实现对该RestTemplate下的所有请求的监控。@SentinelRestTemplate也支持上文的SentinelResource属性,支持其返回函数。

以下是配置文件配置

resttemplate:
  sentinel:
    #关闭SentinelRestTemplate
    enable: false

Feign整合Sentinel

feign:
  sentinel:
    #为Feign支持Sentinel
    enabled: true

指定FeignClient(value = “”, fallback = “XXXX.class” , fallbackFactory=“xxxx.class”),这两个参数只能指定其中一个,其中fallback指定的类要实现FeignClient规定的接口,如果出现流控或者降级,会实现在fallback指定类实现的对应方法。如果指定后者,后者需要实现一个FallbackFactory接口,这个类就可以查看时什么异常导致其进入了流控或者是降级。

规则持久化 (如何在重启微服务中保持最初设定的规则)

拉模式持久化
推模式持久化

错误页的更新(UrlBlockHandler)

实现BlockException接口,通过异常的类型就可以实现不同的错误实现页面。

@Component
public class MyUrlBlockHandler implements UrlBlockHandler {
    @Override
    public void blocked(HttpServletRequest request, HttpServletResponse response, BlockException ex) throws IOException {
        ErrorMsg msg = null;
        if (ex instanceof FlowException) {
            msg = ErrorMsg.builder()
                .status(100)
                .msg("限流了")
                .build();
        } else if (ex instanceof DegradeException) {
            msg = ErrorMsg.builder()
                .status(101)
                .msg("降级了")
                .build();
        } else if (ex instanceof ParamFlowException) {
            msg = ErrorMsg.builder()
                .status(102)
                .msg("热点参数限流")
                .build();
        } else if (ex instanceof SystemBlockException) {
            msg = ErrorMsg.builder()
                .status(103)
                .msg("系统规则(负载/...不满足要求)")
                .build();
        } else if (ex instanceof AuthorityException) {
            msg = ErrorMsg.builder()
                .status(104)
                .msg("授权规则不通过")
                .build();
        }
        // http状态码
        response.setStatus(500);
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-Type", "application/json;charset=utf-8");
        response.setContentType("application/json;charset=utf-8");
        // spring mvc自带的json操作工具,叫jackson
        new ObjectMapper()
            .writeValue(
                response.getWriter(),
                msg
            );
    }
}

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
class ErrorMsg {
    private Integer status;
    private String msg;
}

区分来源(RequestOriginParser)

流控规则与系统规则

//@Component
public class MyRequestOriginParser implements RequestOriginParser {
    @Override
    public String parseOrigin(HttpServletRequest request) {
        // 从请求参数中获取名为 origin 的参数并返回
        // 如果获取不到origin参数,那么就抛异常
		// 这个origin参数就是控制台里面指定的那个
        String origin = request.getParameter("origin");
        if (StringUtils.isBlank(origin)) {
            throw new IllegalArgumentException("origin must be specified");
        }
        return origin;
    }
}

RestURL支持(UrlCleaner)

@Component
@Slf4j
public class MyUrlCleaner implements UrlCleaner {
    @Override
    public String clean(String originUrl) {
        // 让 /shares/1 与 /shares/2 的返回值相同
        // 返回/shares/{number}

        String[] split = originUrl.split("/");

        return Arrays.stream(split)
            .map(string -> {
                if (NumberUtils.isNumber(string)) {
                    return "{number}";
                }
                return string;
            })
            .reduce((a, b) -> a + "/" + b)
            .orElse("");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值