SpringCloud(13) Sentinel 1.8.2 控制台使用

一、前言

官网文档 https://sentinelguard.io/zh-cn/index.html

二、Sentinel安装

tips: 通过docker-compose方式安装

# 环境准备
git clone https://gitee.com/zhengqingya/docker-compose.git
cd docker-compose/Liunx

# 运行
docker-compose -f docker-compose-sentinel.yml -p sentinel up -d

在这里插入图片描述

三、Sentinel使用说明

在这里插入图片描述

1、实时监控

秒级展示

在这里插入图片描述

2、簇点链路

仅展示服务启动后调用过的资源

在这里插入图片描述

3、流控规则

在这里插入图片描述

QPS:每秒查询率,一台服务器每秒能够响应的请求次数
并发线程数:访问该资源的并发线程数

流控模式
  1. 直接:直接操作, 对当前资源限流
    在这里插入图片描述

  2. 关联:当关联资源达到阈值时限流自己 ( ex: 设置关联资源B, 当B达到阈值, 对A做限流 )
    在这里插入图片描述

  3. 链路:只统计从指定资源进入当前资源的请求,是针对请求来源的限流
    A -> common
    B -> common
    仅限流通过入口B访问的common,A随意访问不受影响
    ( tips: 如果B每次都能正常请求到common的话,效果和直接流控一样,如果未正常请求common则相当于未限流处理 )
    在这里插入图片描述

tips: 链路测试需配置 spring.cloud.sentinel.web-context-unify: false 关闭调用链路收敛 => 实现链路流控

流控效果
  1. 快速失败:达到阈值后,新的请求就会被立即拒绝
  2. Warm Up:预热/冷启动方式,让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮
  3. 排队等待:面对突发的流量,排队匀速通过,例如消息队列,对应的是漏桶算法,选择排队只能使用QPS(不能用并发线程数),当到达超时间就失败
    在这里插入图片描述

4、熔断规则

慢调用比例

当单位统计时长内,请求数超过3 & 最大RT(响应时间)超过10毫秒的有10%,则对请求进行熔断,熔断时长为3秒,3秒后的一个请求响应时间<RT则结束熔断恢复正常
在这里插入图片描述


异常降级仅针对业务异常,对 Sentinel 限流降级本身的异常(BlockException)不生效。为了统计异常比例或异常数,需要通过 Tracer.trace(ex) 记录业务异常。
在这里插入图片描述

异常比例

当单位统计时长内,请求数超过3 & 异常的比例大于阈值10%之后会自动进行熔断,若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。
在这里插入图片描述

异常数

当单位统计时长内,请求数超过3 & 异常数大于阈值10%之后会自动进行熔断,若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。
在这里插入图片描述

5、热点规则

a、方法上加上注解@SentinelResource("xxx")

b、控制台新增热点规则

仅对包含热点参数的资源调用生效

参数索引:0代表第一个参数,1代表第二个参数。
当单位统计窗口时长1s内,请求次数超过单机阈值1时生效
在这里插入图片描述

6、系统规则

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

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

在这里插入图片描述

7、授权规则

a、实现RequestOriginParser类获取流控应用值

@Component
public class SentinelRequestOriginParser implements RequestOriginParser {
    
    

    @Override
    public String parseOrigin(HttpServletRequest request) {
    
    
        // 这里怎么去取值可自定义
        String origin = request.getParameter("origin");
        if (StringUtils.isBlank(origin)) {
    
    
            origin = " ";
        }
        return origin;
    }

}

b、控制台新增授权规则

白名单内的服务可正常访问,黑名单内的拒绝访问
在这里插入图片描述

8、集群流控

部署方式:

  1. 独立模式:Token Server 单独运行
    在这里插入图片描述

  2. 嵌入模式:Token Server 与服务在同一进程中启动,无需单独部署
    在这里插入图片描述

  • Token Client:集群流控客户端,用于向所属 Token Server 通信请求 token。集群限流服务端会返回给客户端结果,决定是否限流。Sentinel 集群流控的通信底层采用 Netty 实现。
  • Token Server:集群流控服务端,处理来自 Token Client 的请求,根据配置的集群规则判断是否应该发放 token(是否允许通过)。

集群流控后面有时间再研究吧^_^

9、机器列表

客户端实例监控

如果健康状态为失联则需要自己选择性移除
在这里插入图片描述

在这里插入图片描述

四、sentinel 统一异常处理

@Component
public class MySentinelExceptionHandler implements BlockExceptionHandler {
    
    

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, BlockException ex) throws Exception {
    
    
        String msg = null;
        if (ex instanceof FlowException) {
    
    
            msg = "访问频繁,请稍候再试";
        } else if (ex instanceof DegradeException) {
    
    
            msg = "系统降级";
        } else if (ex instanceof ParamFlowException) {
    
    
            msg = "热点参数限流";
        } else if (ex instanceof SystemBlockException) {
    
    
            msg = "系统规则限流或降级";
        } else if (ex instanceof AuthorityException) {
    
    
            msg = "授权规则不通过";
        } else {
    
    
            msg = "未知限流降级";
        }

        // http状态码
        response.setStatus(500);
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-Type", "application/json;charset=utf-8");
        response.setContentType("application/json;charset=utf-8");
        response.getWriter().write(JSON.toJSONString(ApiResult.fail(msg)));
    }

}

五、本文测试api代码

可查看 https://gitee.com/zhengqingya/small-tools

@Slf4j
@RestController
@RequestMapping("/sentinel")
@Api(tags = "sentinel")
public class SentinelController extends BaseController {
    
    

    @Resource
    private ISentinelService iSentinelService;

    @Resource
    private IDemoClient iDemoClient;

    private Long num = 0L;

    private Long requestCommon() {
    
    
        return this.iDemoClient.flowCommon();
    }

    /**
     * http://127.0.0.1:20040/sentinel/flow/A
     */
    @SneakyThrows(Exception.class)
    @GetMapping("flow/A")
    @ApiOperation("A")
    public Long flowA() {
    
    
        this.num++;
        if (this.num > 6) {
    
    
            return this.num;
        }
        // 只有正常请求common,才能启动链路限流规则
        this.requestCommon();
        return RandomUtil.randomLong();
    }

    /**
     * http://127.0.0.1:20040/sentinel/flow/B
     */
    @SneakyThrows(Exception.class)
    @GetMapping("flow/B")
    @ApiOperation("B")
    public Long flowB() {
    
    
        this.requestCommon();
        return RandomUtil.randomLong();
    }

    /**
     * http://127.0.0.1:20040/sentinel/flow/C
     */
    @SneakyThrows(Exception.class)
    @GetMapping("flow/C")
    @ApiOperation("C")
    public Long flowC() {
    
    
        TimeUnit.MILLISECONDS.sleep(200);
        return RandomUtil.randomLong();
    }

    /**
     * http://127.0.0.1:20040/sentinel/flow/D
     */
    @SneakyThrows(Exception.class)
    @GetMapping("flow/D")
    @ApiOperation("D")
    public Long flowD() {
    
    
        try {
    
    
            int a = 1 / 0;
        } catch (Exception e) {
    
    
            if (!BlockException.isBlockException(e)) {
    
    
                Tracer.trace(e);
            }
            throw e;
        }
        return RandomUtil.randomLong();
    }

    /**
     * http://127.0.0.1:20040/sentinel/flow/E?paramA=1&paramB=2
     */
    @SentinelResource("/sentinel/flow/EE")
    @SneakyThrows(Exception.class)
    @GetMapping("flow/E")
    @ApiOperation("E")
    public Long flowE(@RequestParam(required = false) String paramA,
                      @RequestParam(required = false) String paramB) {
    
    
        // paramA in index 0, paramB in index 1.
        return RandomUtil.randomLong();
    }

    /**
     * http://127.0.0.1:20040/sentinel/F
     */
    @SneakyThrows(Exception.class)
    @GetMapping("F")
    @ApiOperation("F")
    public Long F() {
    
    
        return RandomUtil.randomLong();
    }

}

今日分享语句:
其实所有的努力,都不是给别人看的。这些努力是否有意义,在于它是否丰厚了你的学识,加固了你的基础,转变成了你的能力。努力需要有成效,而不是看上去的忙碌辛苦。

猜你喜欢

转载自blog.csdn.net/qq_38225558/article/details/124844499