spring cloud Alibaba 容错服务-Sentinel学习笔记七

墨蓝 2022-12-18 01:57 285阅读 0赞

容错服务-Sentinel

  • 一、雪崩效应
  • 二、Sentinel实现容错
  • 三、容错规则
    • sentinel配置规则
    • 代码配置规则
  • 四、sentinel与控制台通信原理剖析
  • 五、控制台相关配置项
  • 六、sentinel API详解(自定义异常提示)
  • 七、sentinel Resource注解详解(自定义异常提示)
  • 八、Template整合sentinel
  • 九 、feign整合sentinel
  • 十、规则持久化
  • 十一、集群流控
  • 十二、sentinel扩展
  • 十三、[Alibaba Sentinel 配置项总结](https://www.imooc.com/article/289562)

一、雪崩效应

英文名为cascading failure,也叫级联失效,级联故障;每个微服务并不是100%可用,网络也有可能出问题,如有一个高并发的微服务系统,如下图,包含四个微服务,开始都为正常,在某个时间点,当A挂了,而此系统为高并发系统,B服务疯狂调用A服务,而A挂了,B发往A的请求就会强制等待,知道请求超时,在java程序中,一次请求往往对应一个线程,请求强制等待,线程就会强制阻塞,一直等到线程超时,才会被释放,在高并发情况下,阻塞线程越来越多,而线程对应的又是服务器计算资源,如不做任务处理,随着积累,B服务将无法创建线程,B服务也挂了,同理,C、D也疯狂请求B,C、D也会因为同样原因而不可用,这就是雪崩效应;导致雪崩效应的原因就是服务消费者未做好容错措施
在这里插入图片描述
1、业界常用容错方案

  • 设置请求超时时间
  • 设置限流,根据最大qbs,限流,超出后不再接受请求
  • 仓壁模式:如ShareController有一个thread-pool-1独立线程池,coreSize=10;TestController也有一个thread-pool-x线程池;当线程池1满了,将拒绝访问请求,不会影响线程x运行
  • 断路器模式:
    ① 现实中例子:监控+开关,实时监控电路状态,当发现某段时间电流过大,认为电路短路,将会自动跳闸,保证电路不被烧毁
    ② 代码例子:某服务接口5秒以内请求错误率、错误次数达到阈值,就跳闸;而该接口又恢复正常,该怎么办?断路器模式巧妙设计了一种半开状态,如下图
    在这里插入图片描述
    当请求错误率达到阈值,断路器打开,然后会有一个短暂的窗口期,允许服务请求一次,若失败,则拒绝服务;果断时间又打开窗口,允许服务请求一次,成功,则断路器关闭,允许请求,达到自我修复

PS:四种方案思想,超时,释放够快,就不那么容易死;限流,只有一碗饭量,哪怕给三碗,也只吃一碗;仓壁模式,不把鸡蛋放一个篮子里,你有你的线程池,我有我的线程池;断路器模式,监控+开关,当监控API达到一定预值,就跳闸

二、Sentinel实现容错

轻量级的流量控制、熔断降级java库

1、整合sentinel

  • 加依赖:通过 /actuator/sentinel 暴露端点进行容错启用验证


    org.springframework.cloud
    spring-cloud-starter-alibaba-sentinel
    0.2.0.RELEASE



    org.springframework.boot
    spring-boot-starter-actuator

actuator配置,将隐藏的端点暴露出来
在这里插入图片描述

  • 加注解
  • 写配置

2、Sentinel控制台

  • 选择最新的jar包下载到本地,然后用java -jar xxx.jar启动控制台 控制台下载地址
  • 为内容中心整合控制台:
    在这里插入图片描述
    访问localhost:8080,发现列表为空,因为sentinel是懒加载,内容中心发送请求后,列表就会显示内容中心微服务信息

三、容错规则

sentinel配置规则

1、流控规则
在这里插入图片描述

  • 关联:用于保护资源,如资源为查询,关联资源为修改,若修改过于频繁,就会限制查询,是保护关联资源的一种设计
  • 链路:细粒度配置,直接、关联都是微服务级别,链路则细分至API级别

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2、降级规则(断路器模式)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
3、热点规则(特殊的流控规则):可对参数限流,亦或是对参数的值进行限流;适用于某些参数传递频繁,但有希望提高接口可靠性的场景;热点参数必须是基本类型或者String,否则不会生效

在这里插入图片描述
4、系统规则-阈值类型

在这里插入图片描述
在这里插入图片描述
5、授权规则:对消费者进行授权控制,白名单,则是允许test微服务访问内容中心 /shares/1 API,黑名单则是不允许访问
在这里插入图片描述

代码配置规则

Alibaba Sentinel 规则参数总结

四、sentinel与控制台通信原理剖析

控制台是如何获取到微服务的监控信息?用控制台配置规则时,控制台是如何将规则发送到各个微服务?

  • sentinel 与 控制台通信:sentinel实现了一套服务发现机制
    在这里插入图片描述
  • 监控信息:通过调用API实现
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

五、控制台相关配置项

  • 应用端连接控制台配置项
    在这里插入图片描述
  • 控制台配置项
    在这里插入图片描述
    在这里插入图片描述
    配置使用

在这里插入图片描述

六、sentinel API详解(自定义异常提示)

在这里插入图片描述

  • SphU:定义资源,让资源受到监控,并且可以保护资源
  • Tracer:对想要的异常进行统计
  • ContextUtil:可以实现调用来源,还可以标记调入

PS:代码示例

  1. @GetMapping("/test-sentinel-api")
  2. public String testSentinelApi(@RequestParam String a){
  3. //定义一个sentinel保护资源,名称为test-sentinel-api
  4. String resourceName = "test-sentinel-api";
  5. //标记资源
  6. ContextUtil.enter(resourceName,"test-wfw");
  7. Entry entry = null;
  8. try {
  9. entry = SphU.entry(resourceName);
  10. if(StringUtils.isBlank(a)){
  11. throw new IllegalArgumentException("a不能为空!");
  12. }
  13. return a;
  14. } catch (BlockException e) {
  15. e.printStackTrace();
  16. return "限流或者降级了";
  17. }catch (IllegalArgumentException e2){
  18. Tracer.trace(e2);
  19. return "非法参数";
  20. }finally {
  21. if(entry != null){
  22. entry.exit();
  23. }
  24. ContextUtil.exit();
  25. }
  26. }

七、sentinel Resource注解详解(自定义异常提示)

PS:让代码更加优雅,参考手记

PS:代码示例

  1. /** * sentinel 注解 * @param a * @return */
  2. @GetMapping("/testSentinelResource")
  3. @SentinelResource(
  4. value = "test-sentinel-resource",
  5. blockHandler = "block",
  6. blockHandlerClass = TestControllerBlockHandler.class,
  7. fallback = "fallback",
  8. defaultFallback = "defaultFallback",
  9. fallbackClass = TestControllerFallback.class
  10. )
  11. public String testSentinelResource(@RequestParam String a){
  12. if(a.equals("0")){
  13. throw new IllegalArgumentException("a不能为0!");
  14. }
  15. return a;
  16. }
  17. public class TestControllerFallback {
  18. public static String defaultFallback(String a,Throwable throwable){
  19. return "降级,或者其他异常:" + throwable.getMessage();
  20. }
  21. public static String fallback(String a,Throwable throwable){
  22. return "指定异常:" + throwable.getMessage();
  23. }
  24. }
  25. public class TestControllerBlockHandler {
  26. public static String block(String a, BlockException e){
  27. return "限流或者降级了,block";
  28. }
  29. }

在这里插入图片描述

八、Template整合sentinel

  • 加注解

    //在spring容器中,创建一个对象,类型RestTemplate,名称/id为方法名
    //相当于传统
    @Bean
    @LoadBalanced
    @SentinelRestTemplate(

    1. blockHandler = "block",
    2. blockHandlerClass = TestControllerBlockHandler.class,
    3. fallback = "fallback",
    4. fallbackClass = TestControllerFallback.class

    )
    public RestTemplate restTemplate(){

    1. return new RestTemplate();

    }

  • 开关

    Template整合sentinel 开关

    resttemplate:
    sentinel:

    1. enabled: true
  • 相关源码:涉及Spring生命周期、反射、拦截器,其中不懂的知识点可以重新复习
    在这里插入图片描述

九 、feign整合sentinel

  • 加注解
    在这里插入图片描述
  • 限流降级发生时,如何定义自己的处理逻辑
    ① 在用户中心 feign客户端进行fallback配置
    在这里插入图片描述
    ② 新建类实现 feign客户端接口

    package com.hzb2i.contentcenter.feignClient;
    import com.hzb2i.feignapi.domain.dto.user.UserDto;
    import org.springframework.stereotype.Component;

    @Component
    public class UserCenterFeignClientFallback implements UserCenterFeignClient{

    1. @Override
    2. public UserDto findById(Integer id) {
    3. UserDto userDto = new UserDto();
    4. userDto.setWxNickname("默认用户");
    5. return userDto;
    6. }
    7. @Override
    8. public UserDto query(Integer id, String userName) {
    9. UserDto userDto = new UserDto();
    10. userDto.setWxNickname("默认用户");
    11. return userDto;
    12. }

    }

  • 如何获取异常
    ① 在用户中心 feign客户端进行fallbackFactory配置
    在这里插入图片描述
    ② 实现FallbackFactory类

    package com.hzb2i.contentcenter.feignClient;

    import com.hzb2i.feignapi.domain.dto.user.UserDto;
    import feign.hystrix.FallbackFactory;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.stereotype.Component;

    @Slf4j
    @Component
    public class UserCenterFeignClientFallbackFactory implements FallbackFactory {

    1. @Override
    2. public UserCenterFeignClient create(Throwable throwable) {
    3. return new UserCenterFeignClient() {
    4. @Override
    5. public UserDto findById(Integer id) {
    6. log.error("限流或降级:" + throwable);
    7. UserDto userDto = new UserDto();
    8. userDto.setWxNickname("默认用户");
    9. return userDto;
    10. }
    11. @Override
    12. public UserDto query(Integer id, String userName) {
    13. log.error("限流或降级:" + throwable);
    14. UserDto userDto = new UserDto();
    15. userDto.setWxNickname("默认用户");
    16. return userDto;
    17. }
    18. };
    19. }

    }

PS:sentinel小结在这里插入图片描述

十、规则持久化

从测试反馈,微服务每次重启,规则就消失了,每次都需要重新配置,不适用于生产,需进行规则持久化

  • 拉模型:Alibaba Sentinel规则持久化-拉模式-手把手教程【基于文件】
  • 推模式:Alibaba Sentinel规则持久化-推模式-手把手教程【基于Nacos】

PS:生产环境使用sentinel

  • 推拉模式持久化规则:推模式更佳
  • AHAS:开通地址

十一、集群流控

在这里插入图片描述

十二、sentinel扩展

  • 错误页提示优化:对异常进行细分(衔接六 sentinelAPI和七 sentinel Resource注解)
    ① 打开spring MVC端点保护
    在这里插入图片描述
    默认错误提示:
    在这里插入图片描述
    ② 实现BlockExceptionHandler,对异常提示进行优化:

    @Component
    public class MyUrlBlockHandler implements BlockExceptionHandler {

    1. @Override
    2. public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {
    3. ErrMsg msg = null;
    4. if(e instanceof FlowException){ //限流异常
    5. msg = ErrMsg.builder().status("100").msg("限流了").build();
    6. }
    7. else if(e instanceof DegradeException){ //降级异常
    8. msg = ErrMsg.builder().status("101").msg("降级了").build();
    9. }
    10. else if(e instanceof ParamFlowException){ //热点异常
    11. msg = ErrMsg.builder().status("102").msg("热点参数限流").build();
    12. }
    13. else if(e instanceof SystemBlockException){ //系统异常
    14. msg = ErrMsg.builder().status("100").msg("系统规则不满足").build();
    15. }
    16. else if(e instanceof AuthorityException){ //权限异常
    17. msg = ErrMsg.builder().status("100").msg("授权规则不通过").build();
    18. }
    19. //http状态码
    20. httpServletResponse.setStatus(500);
    21. httpServletResponse.setCharacterEncoding("utf-8");
    22. httpServletResponse.setHeader("Content-type","application/json;charset=utf-8");
    23. httpServletResponse.setContentType("application/json;charset=utf-8");
    24. new ObjectMapper().writeValue(
    25. httpServletResponse.getWriter(),
    26. msg
    27. );
    28. }

    }

    @Data
    @Builder
    @AllArgsConstructor
    class ErrMsg{

    1. private String status;
    2. private String msg;

    }

优化后提示:
在这里插入图片描述

  • 区分来源,异常提示优化

    @Component
    public class MyRequestOriginParser implements RequestOriginParser {

    1. @Override
    2. public String parseOrigin(HttpServletRequest httpServletRequest) {
    3. String origin = httpServletRequest.getParameter("origin");
    4. if(StringUtils.isBlank(origin)){
    5. throw new IllegalArgumentException("origin must be special!");
    6. }
    7. return origin;
    8. }

    }

测试:针对browser进行流控,访问地址参数带?origin=browser则会被限流,其他传值则不会限流
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
PS:不建议将origin参数放在url地址中,可放在header头部里

  • restfulUrl支持,实现URLCleaner接口,通过处理返回相同的url路径

处理前:
在这里插入图片描述
处理后:
在这里插入图片描述

  1. @Slf4j
  2. @Component
  3. public class MyUrlCleaner implements UrlCleaner {
  4. @Override
  5. public String clean(String s) {
  6. log.info(s);
  7. String[] split = s.split("/");
  8. return Arrays.stream(split).map(string -> {
  9. if(StringUtils.equals(string,"{shareId}")){
  10. //if(NumberUtils.isNumber(string)){
  11. return "{number}";
  12. }
  13. return string;
  14. }).reduce((a,b) -> a + "/" + b).orElse("");
  15. }
  16. }

PS:透过现象看本质,核心是CommonFilter过滤器
在这里插入图片描述

十三、Alibaba Sentinel 配置项总结

发表评论

表情:
评论列表 (有 0 条评论,285人围观)

还没有评论,来说两句吧...

相关阅读