springcloud Alibaba 笔记15 spring Sentinel-1

1. Sentinel 简介

官方文档:

https://sentinelguard.io/zh-cn/docs/introduction.html

1.1 与Hystrix 的区别:

NO.HystrixSentinel
1程序员自己手工搭建平台单独一个组件,可以独立出来
2没有一套web组件可以给我们进行更加细粒度化的配置。流量控制、速率控制、服务熔断、服务降级界面化的细粒度统一配置

约定 > 配置 > 编码
Sentinel 的配置可以写在代码中,但是还是建议使用配置和注解的方式,少编码。

1.2 是什么?

阿里巴巴版的Hystrix。
如何使用: https://github.com/alibaba/Sentinel/wiki/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8

1.3 主要特性:

在这里插入图片描述

2. Sentinel 安装与配置

2.1 下载

下载地址

https://github.com/alibaba/Sentinel/releases/tag/1.8.2 (1.8.2 版本)

sentinel组件由2部分组成
后台:
前台8080:

2.2 安装搭建

本次使用128 的机器安装 Sentinel
Linux安装配置JDK1.8

https://www.oracle.com/java/technologies/downloads/#java8
https://blog.youkuaiyun.com/pdsu161530247/article/details/81582980
https://www.cnblogs.com/lzw123-/p/9908748.html
https://www.cnblogs.com/imyalost/p/8745137.html

参考 Linux 搭建 Sentinel 方法:

https://blog.youkuaiyun.com/zhuocailing3390/article/details/123222875

128 的机器上 linux 启动脚本:

cd usr/local/sentinel
java -jar sentinel-dashboard-1.8.2.jar 
或者: java -jar /usr/local/sentinel/sentinel-dashboard-1.8.2.jar 
官方命令行:
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar

启动完成之后放开防火墙端口:

firewall-cmd --zone=public --add-port=8080/tcp --permanent
firewall-cmd --reload

附上 docker 启动脚本:128 机器

docker run -d -p 8088:8088 --name mySentinel bladex/sentinel-dsahboard

测试登录结果:

http://192.168.226.128:8080/#/dashboard

3. 新建调用sentinel的微服务

cloudalibaba-sentinel-service8403

3.1 pom

       <dependencies>
        <!--     SpringCloud Alibaba nacos  -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!-- springcloud alibaba sentinel-datasource-nacos 后续作持久化用到-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
        <!-- springcloud alibaba sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <!-- openfeign -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>com.pyh.springcloud</groupId>
            <artifactId>cloud-api-common</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies> 

3.2 yaml

server:
  port: 8403
spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    nacos:
      discovery:
        # nacos 服务注册中心地址,需开启129 机器的 nginx + keepalived + nacos 集群
        server-addr: 192.168.226.200:1111
    sentinel:
      transport:
        # Sentinel dashboard 地址
        dashboard: 192.168.226.128:8080
        # 默认 8719 端口,假如被占用,会自动从8719开始依次+1扫描,直到找到未被占用的端口
        port: 8719
        client-ip: # Sentinel 安装在docker 上面时,需要添加该配置 
management:
  endpoints:
    web:
      exposure:
        include: "*"  # 暴露监控端点

3.3 主程序类

@SpringBootApplication
@EnableDiscoveryClient
public class SentinelMainApp8403 {
    public static void main(String[] args) {
        SpringApplication.run(SentinelMainApp8403.class,args);
    }
}

3.4 controller

@RestController
public class FlowLimitController {
    @GetMapping("/testA")
    public String testA(){
        return "------TestA";
    }
    @GetMapping("/testB")
    public String testB(){
        return "------TestB";
    }
}

3.5 结果

Sentinel采用懒加载,所以即使启动了服务,还是没有看到任何东西

http://192.168.226.128:8080/

在这里插入图片描述
需要做的,是调用几次服务,再刷新
http://localhost:8403/testA
http://localhost:8403/testB
在这里插入图片描述

4. 功能-流控规则

功能列表:
在这里插入图片描述
具体的功能如下:

- 资源名: 唯一名称,默认请求路径
- 针对来源: Sentinel可以针对调用者进行限流,填写微服务名,默认default(不区分来源)
- 阈值类型/单机阈值:
	* QPS(每秒钟的请求数量):当调用该api的QPS达到阈值的时候,进行限流
	* 线程数: 当调用该api的线程数达到阈值的时候,进行限流
- 是否集群:这里没有集群
- 流控模式:
	* 直接: api达到限流条件时,直接限流
	* 关联:当关联的资源达到阈值时,就限流自己
	* 链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)【api级别的针对来源】
- 流控效果:
	* 快速失败: 直接失败,抛异常 	
	* Warm Up:根据codeFactor(冷加载因子,默认3)的值,从阈值/codeFactor,经过预热时长,才达到设置的QPS阈值 	排队等待:
	* 匀速排队,让请求以匀速的速度通过,阈值类型必须设置为QPS,否则无效

4.1 流控规则

在这里插入图片描述

4.1.1 流控模式:直接

在这里插入图片描述
当访问频率超过上面设置的条件时(每秒1次),直接失败
在这里插入图片描述
另附:当阈值类型指定为 “线程数” 时,若单机阈值等于1,意思是同时只能允许一个线程在处理某个接口,超过一个时,如果前一个调用还未执行完毕,则报错。

4.1.2 流控模式:关联

说明: 当关联的资源达到阈值时,就限流自己
即: 当与A关联的资源B达到阈值后,就限流自己(B惹事,A挂了)
配置:
在这里插入图片描述

4.1.3 流控模式:链路

参考: https://www.freesion.com/article/96621141601/

从1.6.3 版本开始,Sentinel Web fifilter默认收敛所有URL的入口context,因此链路限流不生效。

1.7.0 版本开始(对应SCA的2.1.1.RELEASE),官方在CommonFilter 引入了WEB_CONTEXT_UNIFY 参数,用于控制是否收敛context。将其配置为 false 即可根据不同的URL 进行链路限流。

SCA 2.1.1.RELEASE之后的版本,可以通过配置spring.cloud.sentinel.web-context-unify=false即可关闭收敛我们当前使用的版本是SpringCloud Alibaba 2.1.0.RELEASE,无法实现链路限流。

目前官方还未发布SCA 2.1.2.RELEASE,所以我们只能使用2.1.1.RELEASE,需要写代码的形式实现

在这里插入图片描述
目前测试使用的是2.1.0版本,无法使用链路限流

4.2 流控效果

4.2.1 流控效果:直接->快速失败

默认的处理效果

4.2.2 流控效果:预热 warmup

说明:

公式:阈值除以coldFactor(默认值为3),经过预热时长后才会达到阈值

源码:
com.alibaba.csp.sentinel.slots.block.flow.controller.WarmUpController
在这里插入图片描述
warmup 配置:
在这里插入图片描述

4.2.3 流控效果:排队等待

说明:
在这里插入图片描述
官网说明:
在这里插入图片描述
源码:

com.alibaba.csp.sentinel.slots.block.flow.controller.RateLimiterController

5. 功能-熔断规则

官网:

https://sentinelguard.io/zh-cn/docs/circuit-breaking.html

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

慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。

异常比例(ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。

异常数(ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。

5.1 熔断-慢调用熔断

熔断条件(下图):
在1000毫秒,也就是1秒内,如果发送到/testC 的请求数数量大于5,并且在这些请求中,所有请求的响应时长(因为比例与阈值为1,所以是所有的请求响应时长)都大于800毫秒的时候,进入熔断状态。
经过熔断时长5秒后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT(800毫秒)则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
本次测试使用Jmeter测试。

5.1.1 Sentinel 配置

在这里插入图片描述

5.1.2 controller
    @GetMapping("/testC")
    public String testC() throws InterruptedException {
        Thread.sleep(1000);
        return someService.doSth("testC");
    }
5.1.2 Jmeter

在这里插入图片描述

5.2 熔断-异常比例熔断

5.2.1 规则配置

在这里插入图片描述
如图,在1000 毫秒的时间内,最小请求数达到5个,如果发生异常的比例达到0.5 或以上,则进入熔断状态。经过熔断时长(5秒)后熔断器会进入探测恢复状态(HALF-OPEN状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。

5.2.2 controller
    @GetMapping("/testC")
    public String testC() throws InterruptedException {
        int age = 10/0;
        return someService.doSth("testC");
    }
5.2.3 结果

正常调用
在这里插入图片描述
如5.2.1配置,调用数1秒时间内调用数量大于5,且异常数大于2个
在这里插入图片描述

5.3 熔断-异常数熔断

5.3.1 规则配置

在这里插入图片描述
如图,在时间窗口1000毫秒的时间内,最小请求数大于等于5的情况下,如果异常数量为5个,则进入熔断状态。经过熔断时长(5秒)后熔断器会进入探测恢复状态(HALF-OPEN状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。

5.3.2 controller

与5.2.2 相同

5.3.3 结果

与5.2.3 相同

6. 功能-热点规则

6.1 官网

https://sentinelguard.io/zh-cn/docs/parameter-flow-control.html

6.2 热点规则跟 Hystrix比较

兜底方法:
分为系统默认和客户自定义两种。
之前的case,限流出问题后, 都是用sentinel系统默认的提示:Blocked by Sentinel(flow limiting)

而Sentinel,类似Hystrix,某个方法出问题了,就找对应的兜底降级方法:
结论:
从@HystrixCommand 到@SentinelResource
代码:

com.alibaba.csp.sentinel.slots.block.BlockException

6.3 配置热点规则

6.3.1 代码端
@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey",blockHandler = "deal_testHotKey")
// value = "testHotKey" 资源名
// deal_testHotKey 兜底方法
public String testHotKey(@RequestParam(value = "p1", required = false) String p1
            ,@RequestParam(value = "p2", required = false) String p2){
    return "----testHotKey:p1="+p1+";p2="+p2;
}
public String deal_testHotKey(String p1, String p2, BlockException e){
    return "----deal_testHotKey show";  // Sentinel 系统默认的提示, Block by Sentinel (flow limiting)
}

代码端指定了Sentinel的规则资源名"testHotKey";
如果代码端不配置兜底方法 blockHandler,那么当外部调用违背了Sentinel配置的规则的时候,异常会直接返回给外部,不友好

6.3.2 Sentinel 界面端

在这里插入图片描述

配置解读:当资源名请求为testHotKey的调用,第一个参数(参数索引=0,即6.3.1的p1参数),每1秒的请求数量大于1时,则违背了Sentinel的热点规则,那么会调用代码配置的兜底方法,如果没有则直接抛出异常。

6.3.3 参数例外项

如6.3.2图,添加了一个参数值为5,类型为String,限流阈值为20的例外配置。
表示当p1=5时,限流阈值变为20,需要超过20才会触发Sentinel热点规则。
在这里插入图片描述

6.3.4 直接添加异常看看
public String testHotKey(@RequestParam(value = "p1", required = false) String p1
            ,@RequestParam(value = "p2", required = false) String p2){
    int a = 10/0;
    return "----testHotKey:p1="+p1+";p2="+p2;
}

@SentinelResource:
处理的是Sentinel控制台配置的违规情况,有blockHandler方法配置的兜底处理;

@RuntimeException:
int a = 10/0,这个是java运行时报出的运行时异常RunTimeException, @SentinelResource不管

总结:
@SentinelResource 主管配置出错,运行出错该走异常走异常

7. 系统保护规则

7.1 官网:

如何使用:https://github.com/alibaba/Sentinel/wiki/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8#%E7%B3%BB%E7%BB%9F%E4%BF%9D%E6%8A%A4%E8%A7%84%E5%88%99-systemrule

系统自适应限流:https://github.com/alibaba/Sentinel/wiki/%E7%B3%BB%E7%BB%9F%E8%87%AA%E9%80%82%E5%BA%94%E9%99%90%E6%B5%81

系统保护规则是从应用级别的入口流量进行控制,从单台机器的 load、CPU 使用率、平均 RT、入口 QPS 和并发线程数等几个维度监控应用指标,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。

系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量(EntryType.IN),比如 Web 服务或 Dubbo 服务端接收的请求,都属于入口流量。

7.2 系统规则支持以下的模式:

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.3 例子

在这里插入图片描述
如上图,即整个系统的所有入口的QPS 总和为1.

8. SentinelResource 配置

Sentinel也可以代码的方式来实现规则,如下官网:
https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D
但是一般不推荐

8.1 所需代码

8.1.1 pom
        <!-- 引入自定义api通用包,可以使用payment支付entity -->
        <dependency>
            <groupId>com.pyh.springcloud</groupId>
            <artifactId>cloud-api-common</artifactId>
            <version>${project.version}</version>
        </dependency>
8.1.2 controller
package com.pyh.springcloud.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.pyh.springcloud.entities.CommonResult;
import com.pyh.springcloud.entities.Payment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class RateLimitController {
    @GetMapping("/byResource")
    @SentinelResource(value = "byResource",blockHandler = "HandleException")
    public CommonResult byResource(){
        return new CommonResult(200,"按资源名称限流测试OK",new Payment(2020L,"serial001"));
    }
    public CommonResult HandleException(BlockException exception){
        return new CommonResult(444,exception.getClass().getCanonicalName()+"\t 服务不可用 ");
    }
}
8.1.3 附api-common mudule

在这里插入图片描述

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Payment implements Serializable {
    private Long id;
    private String serial;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommonResult<T> {
    // 404  not found
    private Integer code;
    private String message;
    private T data;
//    上面配置了空参和全参, 这里自定义一个只有编码和消息的构造方法
    public CommonResult(Integer code, String message){
        this(code,message,null);
    }
}
8.1.4 新增流控规则 byResource

记得需先调用一次该节点,使其显示在簇点链路上
在这里插入图片描述
此时关闭8403,发现流控规则消失了,说明目前Sentinel的流控规则是临时的

8.2 没有兜底方法

8.2.1 controller
@GetMapping("/rateLimit/byUrl")
@SentinelResource(value = "byUrl")
public CommonResult byUrl(){
    return new CommonResult(200,"按url限流测试OK",new Payment(2020L,"serial002"));
}
8.2.2 Sentinel

在这里插入图片描述

8.2.3 结果:

在这里插入图片描述
没有自定义兜底方法,则返回Sentinel的默认的内容

8.3 客户自定义限流处理逻辑

8.3.1 前面配置带来的问题

1). 系统默认的,没有体现自己的业务要求
2). 依照现有条件,自定义的处理方法和业务代码耦合,不直观
3). 每个业务方法都添加兜底方法,则代码膨胀加剧
4). 全局统一的处理方法没有体现

8.3.2 定义全局兜底方法

在这里插入图片描述
新增 CustomerBlockHandler 类

package com.pyh.springcloud.myhandler;

import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.pyh.springcloud.entities.CommonResult;

public class CustomerBlockHandler {
    public static CommonResult handlerException(BlockException exception){
        return new CommonResult(444,"按客户自定义,global handlerException----1");
    }
    public static CommonResult handlerException2(BlockException exception){
        return new CommonResult(444,"按客户自定义,global handlerException----2");
    }
}

RateLimitController类 添加方法 customerBlockHandler

    @GetMapping("/rateLimit/customerBlockHandler")
    @SentinelResource(value = "customerBlockHandler"
            ,blockHandlerClass = CustomerBlockHandler.class
            ,blockHandler = "handlerException2")
    public CommonResult customerBlockHandler(){
        return new CommonResult(200,"按客户自定义限流测试OK",new Payment(2020L,"serial003"));
    }

配置 Sentinel 规则流控之后实现全局兜底方法控制
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值