微服务保护-Sentinel框架

Sentinel

初识Sentinel

雪崩问题及解决方案

  • 雪崩问题↓


  • 雪崩问题解决方案↓

image-20230928160133084


QPS:每秒请求数

image-20230928160551766

服务保护技术对比

image-20230928173235889

Sentinel介绍和安装

安装Sentinel控制台

  1. 从github下载jar包
  2. 将其拷贝到一个非中文目录,控制台进入到该目录,然后运行命令:java -jar jar包名字
  3. 访问localhost:8080即可看到控制台页面,默认账户和密码都是sentinel
  • 可以修改Sentinel控制台配置↓

image-20230928174646871

  • ↑更多配置在Sentinel的github上可以找到

微服务整合Sentinel

引入cloud-demo项目

image-20230928175238981

  • 要修改数据库配置,并启动nacos服务(进入bin目录的cmd:startup.cmd -m standalone

  • 启动cloud-demo中的三个项目

  • 访问服务测试是否启动成功↓

image-20230928201625147

image-20230928201705995

微服务整合Sentinel

在order-service中整合Sentinel,并且连接Sentinel的控制台

  • 引入依赖并配置控制台地址然后重启order-service服务↓

image-20230928203748209

  • 访问微服务的任意端点(springMVC的任意一个Controller接口都是一个端点),触发Sentinel监控↓

image-20230928203317430

限流规则

限流的作用是降低服务的负载,从而预防服务因为过高并发而导致故障,服务不出现故障就不会将故障传递给其他服务,从而避免级联失败

快速入门

image-20230930105230665

  • 流控规则入门案例↓
    • 需求:给/order/{orderId}这个资源设置流控规则,QPS不能超过5,然后利用jemeter测试

image-20230930113142676

image-20230930112504742

image-20230930112632153

image-20230930113404365

image-20230930113611140

流控模式

image-20230930113939647

关联模式

image-20230930114740953

image-20230930115146522

image-20230930120029650

image-20230930120440990

链路模式

image-20230930121125700

image-20230930121322590

  1. Sentinel默认只会监控controller中的端点,如果要标记其他方法,需要利用@SentinelResource注解

    1. @SentinelResource("goods")
          public void queryGoods() {
              System.err.println("查询商品");
          }
      
  2. Sentinel默认会将Controller方法作context整合,导致链路模式的流控失效,需要修改application.yml

    1. spring:
        datasource:
          url: jdbc:mysql://localhost:3306/test1?useSSL=false
          username: root
          password: 123456
          driver-class-name: com.mysql.cj.jdbc.Driver
        application:
          name: orderservice
        cloud:
          sentinel:
            transport:
              dashboard: localhost:8080
            web-context-unify: false # 关闭context整合
      

image-20230930145920270

  • 现在同时向order/query和order/save发请求,QPS均为4

image-20230930150429152

  • ↑可知query -> goods链路被流控QPS为2,两个请求QPS均为4,其中update的4个请求均通过,query的请求2个通过,2个被senitnel流控给拦截了

流控效果

image-20230930152536406

warm-up预热模式
  • 服务器不能刚启动时就把QPS打满

image-20230930152802127

  • 案例
    • 需求:给order/{orderId}这个资源设置限流,最大QPS为10,利用warm-up效果,预热时长为5秒

image-20230930153254799

image-20230930153530254

排队等待

image-20230930153927563

  • 案例
    • 需求:给order/{orderId}这个资源设置限流,最大QPS为10,利用排队的流控效果,超过时长设置为5s

image-20230930154240125

image-20230930154610173

热点参数限流

热点参数限流是细腻度更高的限流,精确到了参数级别

image-20230930155335985

  • ↑参数索引就是第几个参数

image-20230930155400206

image-20230930155521394

  • 注意:热点参数限流队默认的SpringMVC资源无效,只用通过@SentinelResource配置的资源才可以进行热点参数限流
@SentinelResource("hot")
    @GetMapping("{orderId}")
    public Order queryOrderByUserId(@PathVariable("orderId") Long orderId) {
        // 根据id查询订单并返回
        return orderService.queryOrderById(orderId);
    }

image-20230930160329433

image-20230930160649807

  • 发送三个请求,QPS均为5,参数分别是101、102、103

image-20230930161025635

  • ↑三个请求的QPS均为5,101阈值是2拒绝了3个,102阈值是4拒绝了1个,103阈值是10全部通过,所以每秒一共通过11个拒绝4个

隔离和降级

一旦服务已经出现故障,就很容易将故障传递给其他依赖于它的服务,就很容易产生雪崩,所以要使用线程隔离、熔断降级这些手段去避免避免级联失败和雪崩

image-20230930162856492

FeignClient整合Sentinel

image-20230930163643634

image-20230930164438275

  1. 在feign-api项目中定义类,实现FallbackFactory

    • @Slf4j
      public class UserClientFallbackFactory implements FallbackFactory<UserClient> {
          @Override
          public UserClient create(Throwable throwable) {
              return new UserClient() {
                  @Override
                  public User findById(Long id) {
                      log.error("查询用户异常", throwable);
                      return new User();
                  }
              };
          }
      }
      
  2. 在feign-api项目中的DefaultFeignConfiguration类中将UserClientFallbackFactory注册为一个Bean

    • image-20230930173538935
  3. 在feign-api项目中的UserClient接口中使用UserClientFallbackFactory

    • image-20230930173702306

image-20230930174011319

线程隔离(舱壁模式)

image-20230930174509634

image-20230930174758179

比如网关适合高扇出的场景,当请求进入网关后网关并不处理,而是将请求代理到其他服务,因此网关适合采用信号量隔离的模式。

image-20231001095656133

  • 案例
    • 需求:给UserClient的查询用户接口设置流控规则,线程数不能超过2,然后利用jemeter测试

image-20231001100128173

  • jemeter发出的请求的并发线程数是10

image-20231001100504251

熔断降级

  • 要配置的有:熔断持续时间、失败阈值(熔断策略)

熔断策略-慢调用

image-20231001101305780

  • 案例
    • 需求:给UserClient的查询用户接口设置降级规则,慢调用的RT阈值为50ms,统计时间为1秒,最小请求数量为5,失败阈值比例为0.4,熔断时长为5
    • 提示:为了触发慢调用,修改了UserService中的业务,为id为1的请求增加业务耗时

image-20231001102530925

  • 当快速刷新localhost:8080/order/101五次之后再次刷新就访问不到user信息了↓

image-20231001102942142

image-20231001103004523

熔断策略-异常比例、异常数

image-20231001103219080

授权规则及规则持久化

系统规则是对当前应用的服务器的一种保护,且只对Linux系统有效

授权规则

image-20231001190914008

image-20231001191107448

image-20231001191222413

@Component
public class HeaderOriginParser implements RequestOriginParser {
    @Override
    public String parseOrigin(HttpServletRequest httpServletRequest) {
        // TODO [hobbit,2023/10/1 19:15]:获取请求头
        String origin = httpServletRequest.getHeader("origin");
        // TODO [hobbit,2023/10/1 19:15]:非空判断
        if (StringUtils.isEmpty(origin)) {
            origin = "blank";
        }
        return origin;
    }
}

image-20231001191909550

image-20231001192200349

image-20231001192351667

image-20231001192500748

自定义异常结果

image-20231001192921445

image-20231001193002919

@Component
public class SentinelExceptionHandler implements BlockExceptionHandler {
    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {
        String msg = "未知异常";
        int status = 429;
        if (e instanceof FlowException) {
            msg = "请求被限流了";
        } else if (e instanceof ParamFlowException) {
            msg = "请求被热点参数限流";
        } else if (e instanceof DegradeException) {
            msg = "请求被降级了";
        } else if (e instanceof AuthorityException) {
            msg = "没有访问权限";
            status = 401;
        }
        httpServletResponse.setContentType("application/json;charset=utf-8");
        httpServletResponse.setStatus(status);
        httpServletResponse.getWriter().println("{\"msg\":" + msg + ",\"status\":" + status + "}");
    }
}

image-20231001194053411

image-20231001194134665

image-20231001194251894

image-20231001194325627

规则持久化

规则管理模式

image-20231001194622413

image-20231001194851905

image-20231001194957354

image-20231001195015068

实现push模式

image-20231001195143354

  • Sentinel规则持久化笔记↓

image-20231001195719081

posted @ 2023-09-27 19:06  hobbit_donglin  阅读(34)  评论(0)    收藏  举报