• Sentinel-高可用流量管理框架


    Sentinel

    Sentinel 是阿里巴巴开源的,面向分布式服务架构的高可用防护组件,主要以流量为切入点,从限流,流量整形、熔断降级、系统负载保护、热点防护等多个维度保护服务的稳定性
    官方文档地址

    启动 Sentinel 控制台

    下载链接:https://github.com/alibaba/Sentinel/releases
    在这里插入图片描述
    如果要修改Sentinel的默认端口、账户、密码,可以通过下列配置:

    配置项默认值说明
    server.port8080服务端口
    sentinel.dashboard.auth.usernamesentinel默认用户名
    sentinel.dashboard.auth.passwordsentinel默认密码

    启动控制台

    nohup java -Dserver.port=8858 -jar sentinel-dashboard-1.8.1.jar
    
    • 1

    其中 -Dserver.port=8858 用于指定 Sentinel 控制台端口为 8858。

    控制台地址:http://localhost:8858/
    在这里插入图片描述
    需要输入账号和密码,默认都是:sentinel

    首次登录什么都没有:是因为还没有与微服务整合
    在这里插入图片描述

    整合springcloud alibaba

    1. 引入依赖
    <!--sentinel启动器-->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. 配置控制台,修改application.yaml文件
    server:
      port: 8821
    spring:
      application:
        name: order-sentinel
      cloud:
        sentinel:
          transport:
            dashboard: localhost:8858
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    1. 访问本地服务的任意端点
      打开浏览器,访问http://localhost:8088/xxx,这样才能触发sentinel的监控。
      然后再访问sentinel的控制台 http://localhost:8858/#/dashboard

    流量控制

    概述:
    同一个资源可以对应多条限流规则。FlowSlot 会对该资源的所有限流规则依次遍历,直到有规则触发限流或者所有规则遍历完毕。

    一条限流规则主要由下面几个因素组成,我们可以组合这些元素来实现不同的限流效果:

    • resource:资源名,即限流规则的作用对象
    • count: 限流阈值
    • grade: 限流阈值类型,QPS 或线程数
    • strategy: 根据调用关系选择策略
    基于QPS/并发数的流量控制

    流控规则:

    Field说明默认值
    resource资源名,资源名是限流规则的作用对象
    count限流阈值
    grade限流阈值类型,QPS模式(1)或并发线程模式(0)QPS模式
    limitApp流控针对的调用来源default,代表不区分调用来源
    strategy调用关系限流策略:直接、链路、关联根据资源本身(直接)
    controlBehavior流控效果(快速失败,WarmUp冷启动,排队等待) 不支持按调用关系限流直接拒绝
    clusterMode是否集群限流

    WarmUp-----解决:激增流量
    排队等待-----解决:脉冲流量

    1. QPS流量控制
    2. 并发线程数流量控制
    基于调用关系的流量控制
    1. 根据调用方限流
    2. 根据调用链路入口限流:链路限流
    3. 具有关系的资源流量控制:关联流量控制

    熔断降级

    概述:
    除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。一个服务常常会调用别的模块,可能是另外的一个远程服务、数据库,或者第三方 API 等。

    熔断策略

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

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

    熔断降级规则(DegradeRule)包含下面几个重要的属性:

    Field说明默认值
    resource资源名,即规则的作用对象
    grade熔断策略,支持慢调用比例/异常比例/异常数策略慢调用比例
    count慢调用比例模式下为慢调用临界 RT(超出该值计为慢调用);异常比例/异常数模式下为对应的阈值
    timeWindow熔断时长,单位为 s
    minRequestAmount熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断(1.7.0 引入)5
    statIntervalMs统计时长(单位为 ms),如 60*1000 代表分钟级(1.8.0 引入)1000 ms
    slowRatioThreshold慢调用比例阈值,仅慢调用比例模式有效(1.8.0 引入)

    sentinel整合openfeign降级

    1. 依赖引入
    <dependencies>
      <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-web</artifactId>
         </dependency>
    
         <!--nacos服务注册发现-->
         <dependency>
             <groupId>com.alibaba.cloud</groupId>
             <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
         </dependency>
    
         <!--1.添加openfeign依赖-->
         <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-starter-openfeign</artifactId>
         </dependency>
    
         <!--sentinel依赖-->
         <dependency>
             <groupId>com.alibaba.cloud</groupId>
             <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
         </dependency>
     </dependencies>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    1. application.yml
    server:
      port: 8041
    # 应用名称(nacos会将该名称当做服务名称)
    spring:
      application:
        name: order-service
      cloud:
        nacos:
          server-addr: 127.0.0.1:8848
          discovery:
            username: nacos
            password: nacos
            namespace: public
    feign:
      sentinel:
        # openfeign整合sentinel
        enabled: true
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    1. openfeign接口
    /**
     * 添加feign接口和方法
     * name  指定调用rest接口所对应的服务名
     * path  指定调用rest接口所在的StockController指定的@RequestMapping
     */
    @FeignClient(name = "stock-service", path = "/stock", fallback = StockFeignServiceFallback.class)
    public interface StockFeignService {
    
        /**
         * 声明需要调用的rest接口对应的方法
         * @return
         */
        @RequestMapping("/reduct2")
        String reduct2();
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    1. openfeign的fallback实现类
    @Component
    public class StockFeignServiceFallback implements StockFeignService{
    
        @Override
        public String reduct2() {
            return "降级了~~~~~";
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    系统自适应保护

    概述:
    Sentinel 系统自适应保护从整体维度对应用入口流量进行控制,结合应用的 Load、总体平均 RT、入口 QPS 和线程数等几个维度的监控指标,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。

    系统规则
    • Load(仅对 Linux/Unix-like 机器生效):当系统 load1 超过阈值,且系统当前的并发线程数超过系统容量时才会触发系统保护。系统容量由系统的 maxQps * minRt 计算得出。设定参考值一般是 CPU cores * 2.5。
    • CPU usage(1.5.0+ 版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0)。
    • RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
    • 线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
    • 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。

    异常处理

    单个接口异常处理使用 @SentinelResource

    package com.example.order.controller;
    
    import com.alibaba.csp.sentinel.annotation.SentinelResource;
    import com.alibaba.csp.sentinel.slots.block.BlockException;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.concurrent.TimeUnit;
    
    @RestController
    @RequestMapping("/order")
    public class OrderController {
    
        @RequestMapping("/add")
        public String add(){
            System.out.println("下单成功");
            return "Hello World ";
        }
    
        @RequestMapping("/flow")
        @SentinelResource(value = "flow",blockHandler = "flowBlockHandler")
        public String flow(){
            return "正常访问";
        }
    
        public String flowBlockHandler(BlockException e){
            return "被流控了";
        }
    
        @RequestMapping("/flowThread")
        @SentinelResource(value = "flowThread",blockHandler = "flowBlockHandler")
        public String flowThread() throws InterruptedException {
            TimeUnit.SECONDS.sleep(5);
            return "正常访问";
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    设置统一异常处理

    设置统一异常处理适合对BlockException返回的信息处理是一样的,如果不一样则还是需要使用@SentinelResource

    package com.example.order.domain;
    
    public class Result<T> {
        private Integer code;
        private String msg;
        private T data;
    
        public Result(Integer code, String msg, T data) {
            this.code = code;
            this.msg = msg;
            this.data = data;
        }
    
        public Result(Integer code, String msg) {
            this.code = code;
            this.msg = msg;
        }
    
        public Integer getCode() {
            return code;
        }
    
        public void setCode(Integer code) {
            this.code = code;
        }
    
        public String getMsg() {
            return msg;
        }
    
        public void setMsg(String msg) {
            this.msg = msg;
        }
    
        public T getData() {
            return data;
        }
    
        public void setData(T data) {
            this.data = data;
        }
    
        public static Result error(Integer code,String msg){
            return new Result(code,msg);
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    package com.example.order.exception;
    
    import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
    import com.alibaba.csp.sentinel.slots.block.BlockException;
    import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
    import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
    import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
    import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
    import com.alibaba.fastjson.JSON;
    import com.example.order.domain.Result;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.http.MediaType;
    import org.springframework.stereotype.Component;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.PrintWriter;
    
    @Component
    public class MyBlockExceptionHandler implements BlockExceptionHandler {
    
        Logger log = LoggerFactory.getLogger(this.getClass());
    
        public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {
            //getRule返回资源、规则的详细信息
            log.info("BlockExceptionHandler BlockException================"+e.getRule());
    
            Result r = null;
            if(e instanceof FlowException){
                r = Result.error(100,"接口被限流了");
            }else if (e instanceof DegradeException){
                r = Result.error(101,"服务降级了");
            }else if (e instanceof ParamFlowException){
                r = Result.error(102,"热点参数限流了");
            }else if (e instanceof AuthorityException){
                r = Result.error(104,"授权规则不通过");
            }
    
            //返回Json数据
            httpServletResponse.setStatus(500);
            httpServletResponse.setCharacterEncoding("UTF-8");
            httpServletResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
            PrintWriter writer=null;
            try {
                writer=httpServletResponse.getWriter();
                writer.write(JSON.toJSONString(r));
                writer.flush();
            } catch (IOException ioException) {
                log.error("异常:{}",ioException);
            }finally {
                if(writer!=null) {
                    writer.close();
                }
            }
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    sentinel规则持久化

    onlineRateService.getClassSingleSubjectLaunch(examId, schoolId, classroomName, subjectCode, UserInfoUtil.getUserId())

    实现push模式

    push模式实现依赖于nacos,并且需要修改Sentinel控制台。整体步骤如下:

    1. 修改order-service服务,使其监听Nacos配置中心
    2. 修改Sentinel-dashboard源码,配置nacos数据源
    3. 修改Sentinel-dashboard源码,修改前端页面
    4. 重新编译、打包-dashboard源码

    详细配置步骤:https://download.csdn.net/download/AliEnCheng/87805720

  • 相关阅读:
    js 作用域理解(查找变量)
    【Android】android.view.WindowManager$BadTokenException 异常fix 解决
    一个有关sizeof的题目
    实践总结:一篇搞懂链表——单链表和双指针技巧
    自绘 控件
    我是如何一步步获取房东的WiFi后台管理密码的【社工思路】
    个人设计和公司设计,哪个更适合你?
    树模型(三)决策树
    Python语法
    模型融合——stacking原理与实现
  • 原文地址:https://blog.csdn.net/AliEnCheng/article/details/126505588