SpringCloud整合Sentinel

1、熔断降级限流

什么是熔断
A服务调用B服务的某个功能,由于网络不稳定问题,或者B服务卡机,导致功能时间超长。如果这样子的次数太多。我们就可以直接将B断路了(A不再请求B接口) ,凡是调用B的直接返回降级数据,不必等待B的超长执行。这样B的故障问题,就不会级联影响到A。

什么是降级
整个网站处于流量高峰期,服务器压力剧增,根据当前业务情况及流量,对一些服务和页面进行有策略的降级停止服务,所有的调用直接返回降级数据。以此缓解服务器资源的的压力,以保证核心业务的正常运行,同时也保持了客户和大部分客户的得到正确的相应。

异同:
相同点:
1、为了保证集群大部分服务的可用性和可靠性,防止崩溃,牺牲小我
2、用户最终都是体验到某个功能不可用
不同点:
1、熔断是被调用方故障,触发的系统主动规则
2、降级是基于全局考虑,停止一些正常服务,释放资源

什么是限流
对打入服务的请求流量进行控制,使服务能够承担不超过自己能力的流量压力,也就是将服务集群的入口流量做限制,保证流量不会超过集群的能力,只要是超过集群的的处理能力就直接丢弃!

对比

在这里插入图片描述
这里对比就是告诉我们,Sentinel很牛逼就行了!
这里额外讲一点,在隔离策略上的信号量和线程池的区别;
线程池隔离:
如现在有一个hello请求需要限流保护,限流50个,那么Hystrix就会为这个hello请求创建一个线程池,里面50个线程,那么还有其他的请求如还有一个world请求也需要限流保护,那么这时Hystrix又会为world请求创建一个对应的线程池!每个需要限流保护的请求都需要创建对应的线程池 缺点: 这样整个系统需要保护的请求多了,开辟的线程池也就多了,会极大的影响消耗服务器的性能!优点: 隔离比较彻底,每个需要保护的请求都有直接的独立线程池,单个请求的池子炸了不会影响到其他请求

信号量隔离:
同样50个请求进来需要限流保护,每一个需要限流保护的请求都自己的semaphore,50个请求进来后,semaphore发现50个流量消费完了,优点: 其他的请求直接挡回去,其他多余的请求也不会从新创建线程,直接使用信号量来扣减。缺点: 如果某些请求隔离炸了,会影响整个服务!

这里也不过多介绍了,官方稳定已经很详细了,我就不画蛇添足了alibaba/Sentinel
在这里插入图片描述

Sentinel控制台安装

在这里插入图片描述
在这里插入图片描述
结合项目导入的版本!
在这里插入图片描述
下载对应客户端
在这里插入图片描述
下载速度慢可以参看这篇文章GitHub下载提速
在这里插入图片描述
启动客户端
在这里插入图片描述

java -jar .\sentinel-dashboard-1.6.3.jar --server.port=9999

指定日志存放目录

java -Dlogging.file=/log/sentinel-dashboard.log -Dcsp.sentinel.log.dir=/log/ -Dserver.port=9999 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.0.jar

如果嫌每次启动都需要敲这么长的命令可以将命令做成脚本,创建.sh文件,将上面命令复制出来,赋予这个脚本可执行权限

chmod +x sentinel-start.sh

然后每次直接运行这个脚本即可

默认存放目录
在这里插入图片描述

启动成功!

登录控制台
在这里插入图片描述
账号密码都是sentinel,这个控制台式懒加载的,没有请求时不显示任何数据!
在这里插入图片描述

SpringCloud整合Sentinel

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
1.导入相关依赖

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

2.查看版本Sentinel
这里是core包1.6.3-也对应控制台的版本
在这里插入图片描述
3.编写配置文件

//Sentinel 控制台地址
spring.cloud.sentinel.transport.dashboard=localhost:9999
//与 Sentinel 控制台做交互。比如 Sentinel 控制台添加了一个限流规则,会把规则数据 push 给这个 Http Server 接收,Http Server 再将规则注册到 Sentinel 中。
spring.cloud.sentinel.transport.port=8719
spring.cloud.sentinel.transport.client-ip=启动服务机器ip //防止sentinel抓取虚拟ip

注意: 如果sentinel服务端出现如下异常,且控制台上不显示服务的实时监控数据的话,请加上client-ip

2021-05-01 21:22:46 [pool-2-thread-1] ERROR c.a.c.s.d.metric.MetricFetcher - Failed to fetch metric from <http://192.168.184.1:8720/metric?startTime=1619875224000&endTime=1619875230000&refetch=false> (ConnectionException: 连接超时)

4.启动服务器
在这里插入图片描述
启动成功!

5.控制台查看
由于Sentinel是懒加载模式,需要发送请求才能监控得到!
在这里插入图片描述

下面测试使用Jmeter来发送并发请求Jmeter测试工具实战测试

流控测试

1.添加接口

@Slf4j
@RestController
public class Test {
    @Autowired
    TestService testService;

    @GetMapping("/test1")
    public String finish() {
        log.debug("test1");
        testService.test1();
        return "ok";
    }
}


	@Override
    public String test1() {
       log.info("TestImpl-test1");
       return null;
    }


2.添加流控
在这里插入图片描述
可以在流控规则查看刚才添加的流控
在这里插入图片描述
在这里插入图片描述
这里官网介绍的很详细流量控制
在这里插入图片描述
在这里插入图片描述

3.查看实际效果
这里限流每秒test1接口请求1次,使用Jmeter发送5条请求
在这里插入图片描述

在这里插入图片描述
发送请求5个

在这里插入图片描述
5个请求都发送成功了,查看服务端日志输出
在这里插入图片描述
服务端日志值打印一次请求,看看Jmeter其他请求的响应结果
在这里插入图片描述
Jmeter右边响应结果框中并不是我们服务端接口中的ok,这个响应的内容是Sentinel限流后默认返回,这里控制台上限流一个配置成功!下面修改Sentinel默认限流返回

4.流控指定以返回
添加配置类

/**
* @description: 流控自定义返回
* @author TAO
* @date 2020/8/22 14:40
*/
@Configuration
public class SeckillSentinelConfig {

    /**
     * 可能因为版本冲突导致无法引入 WebCallbackManager
     */
    public SeckillSentinelConfig() {
        WebCallbackManager.setUrlBlockHandler((request, response, ex) -> {
            R error = R.error(BizCodeEnume.TOO_MANY_REQUESTS.getCode(), BizCodeEnume.TOO_MANY_REQUESTS.getMsg());
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/json");
            response.getWriter().write(JSON.toJSONString(error));
        });
    }

}

上面我是整合1.6.1的版本,当我后来切换到1.7.x版本时发现不起作用了!切换到下面即可

@Slf4j
@Component
public class SeckillSentinelConfig  implements BlockExceptionHandler {

    /**
     * 需前置导入sentinel-web-servlet
     */
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, BlockException ex) throws Exception {
        log.info("===>流控自定义返回");
        response.setContentType("application/json;charset=utf-8");
        R res = null;
        if (ex instanceof FlowException) {
            res = R.failed("流控规则被触发");
        } else if (ex instanceof DegradeException) {
            res = R.failed("降级规则被触发");
        } else if (ex instanceof AuthorityException) {
            res = R.failed("授权规则被触发");
        } else if (ex instanceof ParamFlowException) {
            res = R.failed("热点规则被触发");
        } else if (ex instanceof SystemBlockException) {
            res = R.failed("系统规则被触发");
        }
        response.setStatus(200);
        response.getWriter().write(JSON.toJSONString(res));
    }
}

重启服务器,配置限流,并请求测试,这里注意,Sentinel的数据默认是存储在启动服务器的内存中,服务器重启也意味着配置、监控数据的丢失,后面会演示持久化!
在这里插入图片描述
自定义限流结果完成!

Sentinel熔断降级

在微服务集群环境下服务见调用比较多,一旦调用链中某个被调用方服务不可用,那么会导致整个系统就会崩溃,这里可以使用Sentinel来做熔断保护!降级!Sentinel熔断降级官网
在这里插入图片描述
Sentinel的服务熔断和Hystrix的服务熔断是差不多的

服务熔断
服务熔断不是这里的重点,而且比较简单,这里就不过多演示,在之前有篇文章中有提到过熔断保护

服务降级
在A服务调用B服务是,会形成调用链,在这个调用链上可以设置被调用方的降级策略
在这里插入图片描述
RT(平均响应时间,秒级),平均响应时间,超出阈值且在时间窗口内通过的请求>=5两个条件同时满足后触发降级,窗口期过后关闭断路器,RT最大是4900(更大的需要通过-Dcsp.sentinel.statistic.max.rt=xxx才能生效)
异常比例数(秒级) QPS>=5且异常比例(秒级统计)超过阈值时,触发降级;时间窗口结束后,关闭降级!
异常数(分钟级) 异常数超时阈值时,触发降级;时间窗口结束后关闭降级!

sentinel熔断降级会在调用链路中某个资源出现不稳定状态是(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其他的资源导致级联错误。当资源被降级后,在接下来的时间窗口之内,对该资源的调用都自动熔断,(默认行为是抛出DegradeException)。Sentinel的断路器是没有半开状态的,半开的状态系统自动去检查是否请求有异常,没有异常就关闭断路器恢复使用,有异常则继续打开断路器不可用,具体可以参考hystrix

这里我就不架设多个服务间的调用了,假设左边的小框中是调用链路,右边的框中是调用方对被调用方的降级设置,
被调用方响应毫秒数,时间窗口是下次嗲用远程服务的间隔时间!

例如:A服务调用B服务,B服务响应时间超过1毫秒时就会触发服务熔断,然后间隔10秒后重试,

熔断降级

Sentinel自定义资源保护

Sentinel于主流框架是默认适配的,例如 Web Servlet、Dubbo、Spring Cloud、gRPC、Spring WebFlux、Reactor 等都做了适配。只需要引入对应的依赖即可方便地整合 Sentinel主流框架的适配

1.抛出异常的方式定义资源

//修改业务层test1代码
    @Override
    public String test1() {
       log.info("TestImpl-test1");
       //资源名可使用任意有业务语义的字符串,比如方法名、接口名或其它可唯一标识的字符串。
         try(Entry entry= SphU.entry("t1")) {//抛出异常的方式定义限流资源名-t1
          	// 被保护的业务逻辑
  		  	// do something here...
            log.debug("111");
        }catch (BlockException ex){
             // 资源访问阻止,被限流或被降级
			  // 在此处进行相应的处理操作
            log.debug("资源被限流");
        }
       return null;
    }

重启服务器,发送请求,查看控制台!
在这里插入图片描述
这里多了一个t1的资源,限流等其他操作和普通的接口一样

2.注解方式定义资源

    /**
     * @SentinelResource 用于定义资源,并提供可选的异常处理和 fallback 配置项。 @SentinelResource 注解包含以下属性:
     *
     * value:资源名称,必需项(不能为空)
     * entryType:entry 类型,可选项(默认为 EntryType.OUT)
     * blockHandler / blockHandlerClass: blockHandler 对应处理 BlockException 的函数名称,可选项。blockHandler 函数访问范围需要是 public,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException。blockHandler 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 blockHandlerClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
     * fallback / fallbackClass:fallback 函数名称,可选项,用于在抛出异常的时候提供 fallback 处理逻辑。fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。fallback 函数签名和位置要求:
     * 返回值类型必须与原函数返回值类型一致;
     * 方法参数列表需要和原函数一致,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。
     * fallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
     * defaultFallback(since 1.6.0):默认的 fallback 函数名称,可选项,通常用于通用的 fallback 逻辑(即可以用于很多服务或方法)。默认 fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。若同时配置了 fallback 和 defaultFallback,则只有 fallback 会生效。defaultFallback 函数签名要求:
     * 返回值类型必须与原函数返回值类型一致;
     * 方法参数列表需要为空,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。
     * defaultFallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
     * exceptionsToIgnore(since 1.6.0):用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。
     * @return
     */

    @SentinelResource(value = "t2" ,blockHandler = "blockHandler")
    @Override
    public String test2() {
        log.debug("222");
        return null;
    }


    public String blockHandler(BlockException e){
        log.error("被限流了---blockHandler");
        return null;
    }

发送请求,查看流控资源!
在这里插入图片描述
更多详情注解支持

网关整合Sentinel

官网介绍网关流控
1.网关服务的pom中导入相关依赖

		<dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
            <version>2.2.1.RELEASE</version>
        </dependency>

2.查看控制台
在这里插入图片描述
配置成功!

3.网关路由配置

		- id: test
          uri: lb://test
          predicates:
            - Host=test.gg.com

4.访问测试
在这里插入图片描述
5.添加网关流控
在这里插入图片描述
GatewayFlowRule:网关限流规则,针对 API Gateway 的场景定制的限流规则,可以针对不同 route 或自定义的 API 分组进行限流,支持针对请求中的参数、Header、来源 IP 等进行定制化的限流。
ApiDefinition:用户自定义的 API 定义分组,可以看做是一些 URL 匹配的组合。比如我们可以定义一个 API 叫 my_api,请求 path 模式为 /foo/** 和 /baz/** 的都归到 my_api 这个 API 分组下面。限流的时候可以针对这个自定义的 API 分组维度进行限流。
其中网关限流规则 GatewayFlowRule 的字段解释如下:

resource:资源名称,可以是网关中的 route 名称或者用户自定义的 API 分组名称。
resourceMode:规则是针对 API Gateway 的 route(RESOURCE_MODE_ROUTE_ID)还是用户在 Sentinel 中定义的 API 分组(RESOURCE_MODE_CUSTOM_API_NAME),默认是 route。
grade:限流指标维度,同限流规则的 grade 字段。
count:限流阈值
intervalSec:统计时间窗口,单位是秒,默认是 1 秒。
controlBehavior:流量整形的控制效果,同限流规则的 controlBehavior 字段,目前支持快速失败和匀速排队两种模式,默认是快速失败。
burst:应对突发请求时额外允许的请求数目。
maxQueueingTimeoutMs:匀速排队模式下的最长排队时间,单位是毫秒,仅在匀速排队模式下生效。
paramItem:参数限流配置。若不提供,则代表不针对参数进行限流,该网关规则将会被转换成普通流控规则;否则会转换成热点规则。其中的字段:
parseStrategy:从请求中提取参数的策略,目前支持提取来源 IP(PARAM_PARSE_STRATEGY_CLIENT_IP)、Host(PARAM_PARSE_STRATEGY_HOST)、任意 Header(PARAM_PARSE_STRATEGY_HEADER)和任意 URL 参数(PARAM_PARSE_STRATEGY_URL_PARAM)四种模式。
fieldName:若提取策略选择 Header 模式或 URL 参数模式,则需要指定对应的 header 名称或 URL 参数名称。
pattern:参数值的匹配模式,只有匹配该模式的请求属性值会纳入统计和流控;若为空则统计该请求属性的所有值。(1.6.2 版本开始支持)
matchStrategy:参数值的匹配策略,目前支持精确匹配(PARAM_MATCH_STRATEGY_EXACT)、子串匹配(PARAM_MATCH_STRATEGY_CONTAINS)和正则匹配(PARAM_MATCH_STRATEGY_REGEX)。(1.6.2 版本开始支持)
用户可以通过 GatewayRuleManager.loadRules(rules) 手动加载网关规则,或通过 GatewayRuleManager.register2Property(property) 注册动态规则源动态推送(推荐方式)。
参数详情
7.查看网关流控结果
在这里插入图片描述
8.控制台输出
在这里插入图片描述
这里网关流控是从整个微服务的入口控制的,限制的流量是无法抵达子服务中的,所以5个请求实际进入test服务的只有两个,这里两个是因为配置了阈值为1还有一个Burst size也是1,Burst size是突发情况先而外允许请求数量,所以test能抵达2个!

8.添加指定参数网关限流
在这里插入图片描述
这里可以设置一些额外参数作为限流条件

9.添加API分组流控
在这里插入图片描述
这里会根据指定API的资源路径作为限流条件

10.自定义网关限流返回

/**
* @description: 网关自定义限流返回
* @author TAO
* @date 2020/8/22 16:00
*/

@Configuration
public class SentinelGatewayConfig {
    public SentinelGatewayConfig(){
        GatewayCallbackManager.setBlockHandler(new BlockRequestHandler() {
            @Override
            public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
                R error = R.error(BizCodeEnume.TOO_MANY_REQUESTS_GATEWAY.getCode(), BizCodeEnume.TOO_MANY_REQUESTS_GATEWAY.getMsg());
                String errJson= JSON.toJSONString(error);
                Mono<ServerResponse> body= ServerResponse.ok().body(Mono.just(errJson),String.class);
                return body;
            }
        });
    }
}

在这里插入图片描述
配置成功!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员劝退师-TAO

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值