流控效果和降级规则,热点规则,授权规则以及sentinel规则持久化

Sentinel 支持通过 @SentinelResource 注解定义资源并配置 blockHandler 和 fallback 函数来进行限流之后的处理。

@SentinelResource 注解是 Sentinel 提供的最重要的注解之一,它还包含了多个属性,如下表:

配置流控效果

l 快速失败(默认): 直接失败,抛出异常,不做任何额外的处理,是最简单的效果

l Warm Up:它从开始阈值到最大QPS阈值会有一个缓冲阶段,一开始的阈值是最大QPS阈值的1/3,然后慢慢.增长,直到最大阈值,适用于将突然增大的流量转换为缓步增长的场景。

设置阈值为 10,预热时间是 5 秒,逐渐增加到阈值上限,所以会有一个初始阈值

初始阈值 = 阈值上限 / coldFactor, coldFactor 是冷加载因子,默认为3

上面这个配置的效果就是:在 5 秒内最大阈值是 3(10/codeFactor),超过5秒,最大阈值为10

l 排队等待:让请求以均匀的速度通过,单机阈值为每秒通过数量,其余的排队等待; 它还会让设置一个超时时间,当请求超过超时间时间还未处理,则会被丢弃。

排队等待方式会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。

注意:匀速排队,让请求以匀速通过,阈值类型必须设置为QPS,否则无效,匀速排队模式暂时不支持 QPS > 1000 的场景

当阈值设为 2 的时候,则代表一秒匀速的通过 2 个请求,也就是每个请求平均间隔恒定为 1000 / 2 = 500 ms,每一个请求的最长等待时间(maxQueueingTimeMs)为 1s 。

@GetMapping("message2")
public String message2(){
    System.out.println(Thread.currentThread().getName()+"===="+System.currentTimeMillis());
    return "message2!!";
}

降级规则

RT:平均响应时间 (DEGRADE_GRADE_RT);当 1s 内持续进入 5 个请求,对应时刻的平均响应时间(秒级)均超过阈值(count,以 ms 为单位),那么在接下来的时间窗口(DegradeRule 中的 timeWindow,以 s 为单位)之内,对这个方法的调用都会自动地熔断(抛出 DegradeException)。

注意 Sentinel 默认统计的 RT 上限是 4900 ms,超出此阈值的都会算作 4900 ms

降级规则就是设置当满足什么条件的时候,对服务进行降级。Sentinel提供了三个衡量条件:

l 平均响应时间 :当资源的平均响应时间超过阈值(以 ms 为单位)之后,资源进入准降级状态。如果接下来 1s 内持续进入 5 个请求,它们的 RT都持续超过这个阈值,那么在接下的时间窗口(以 s 为单位)之内,就会对这个方法进行服务降级 。

@RequestMapping("test")
@RestController
public class TestControler {
    @GetMapping
    public String aaa(){
        try {
            Thread.sleep(60);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return  aaa();
    }
}

降级成功

异常比例

l 异常比例:当资源的每秒请求量>=5,并且每秒异常总数占通过量的比值超过阈值之后,资源进入降级状态,即在接下的时间窗口智能,对这个方法的调用都会自动地返回。异常比率的阈值范围是[0.0,1.0],代表0%~100%

异常数

异常数 :当资源近 1 分钟的异常数目超过阈值之后会进行服务降级。注意由于统计时间窗口是分钟级别的,若时间窗口小于 60s,则结束熔断状态后仍可能再进入熔断状态。

热点规则

不加注解热点规则不生效

不加注解热点规则不生效

不加注解热点规则不生效

添加例外

热点参数流控规则是一种更细粒度的流控规则, 它允许将规则具体到参数上。

热点规则简单使用

第1步: 编写代码

@GetMapping("/test2")
@SentinelResource(value = "test2")
    public String bbb(String name,Integer age){
        return name+"---------------"+age;
    }

第3步: 分别用两个参数访问,会发现只对第一个参数限流了

热点规则增强使用

参数例外项允许对一个参数的具体值进行流控编辑刚才定义的规则,增加参数例外项

此时参数xiaowu运行无误,换成其他无法运行

授权规则:

很多时候,我们需要根据调用来源来判断该次请求是否允许放行,这时候可以使用 Sentinel 的来源 访问控制的功能。来源访问控制根据资源的请求来源(origin)限制资源是否通过: 若配置白名单,则只有请求来源位于白名单内时才可通过; 若配置黑名单,则请求来源位于黑名单时不通过,其余的请求通过

流控应用怎么填写呢?

其实这个位置要填写的是来源标识,Sentinel提供了 RequestOriginParser 接口来处理来源。 只要Sentinel保护的接口资源被访问,Sentinel就会调用 RequestOriginParser 的实现类去解析 访问来源。

第1步: 自定义来源处理规则

import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
@Component
public class MyRequestOriginParser implements RequestOriginParser {
    @Override
    public String parseOrigin(HttpServletRequest request) {
        //解析来源

        //定义 流控的应用的参数名字 是servicename
        String servicename = request.getParameter("servicename");
        return servicename;
    }

访问 路径?路径后加&serviceName=test(此处为你的流控名)

观察结果

全局异常的返回

package com.yyl.sentinel;
import com.yyl.util.Result;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import java.lang.reflect.UndeclaredThrowableException;
@ControllerAdvice // 全局异常
public class GlobalException {
    @ResponseBody // 以json
    // 抛出的异常{} 代表的就是一个集合
    @ExceptionHandler({UndeclaredThrowableException.class})
    public Result test(){
      return new Result("没有授权!!!");
    }
}

Sentinel规则持久化

通过前面的讲解,我们已经知道,可以通过Dashboard来为每个Sentinel客户端设置各种各样的规则,但是这里有一个问题,就是这些规则默认是存放在内存中,极不稳定,所以需要将其持久化。

方法1:添加到nacos里面

1)在配置文件application中添加以下内容

spring.cloud.sentinel.datasource.ds1.nacos.data-id=${spring.application.name}
spring.cloud.sentinel.datasource.ds1.nacos.data-type=json
spring.cloud.sentinel.datasource.ds1.nacos.server-addr=localhost:8848
spring.cloud.sentinel.datasource.ds1.nacos.group-id=DEFAULT_GROUP
spring.cloud.sentinel.datasource.ds1.nacos.rule-type=flow

2)在nacos中为cloudalibaba-sentinel-service(可以在配置文件自定义)服务添加对应配置。

[
    {
        "resource": "/rateLimit/customerBlockHandler",#/rateLimit/customerBlockHandler
        "limitApp": "default",
        "grade": 1,
        "count": 1,
        "strategy": 0,
        "controlBehavior": 0,
        "clusterMode": false    
    }
]

resource: 资源名称;

imitApp: 来源应用;

grade: 阈值类型,0表示线程数,1表示QPS;

count: 单机阈值;

strategy: 流控模式,0表示直接,1表示关联,2表示链路;

controlBehavior: 流控效果,0表示快速失败,1表示。Warm Up,2表示排队等待。

clusterMode: 是否集群。

2.方法2

将这个配置文件使用

在对应的微服务下面的resources里面创建一个目录

META-INF/services

并在目录下面写一个文件

com.alibaba.csp.sentinel.init.InitFunc

文件里面写的是刚才的配置类的包名加类名 :com.pro.config.FilePersistence

使用文件

import com.alibaba.csp.sentinel.command.handler.ModifyParamFlowRulesCommandHandler;
import com.alibaba.csp.sentinel.datasource.*;
import com.alibaba.csp.sentinel.init.InitFunc;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleManager;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
import com.alibaba.csp.sentinel.transport.util.WritableDataSourceRegistry;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import org.springframework.beans.factory.annotation.Value;
import java.io.File;
import java.io.IOException;
import java.util.List;
public class FilePersistence implements InitFunc {
    @Value("${spring.application.name}")
    private String appcationName;
    @Override
    public void init() throws Exception {
        String ruleDir = System.getProperty("user.home") + "/sentinel-rules/" + appcationName;
        String flowRulePath = ruleDir + "/flow-rule.json";
        String degradeRulePath = ruleDir + "/degrade-rule.json";
        String systemRulePath = ruleDir + "/system-rule.json";
        String authorityRulePath = ruleDir + "/authority-rule.json";
        String paramFlowRulePath = ruleDir + "/param-flow-rule.json";
        this.mkdirIfNotExits(ruleDir);
        this.createFileIfNotExits(flowRulePath);
        this.createFileIfNotExits(degradeRulePath);
        this.createFileIfNotExits(systemRulePath);
        this.createFileIfNotExits(authorityRulePath);
        this.createFileIfNotExits(paramFlowRulePath);
        // 流控规则
        ReadableDataSource<String, List<FlowRule>> flowRuleRDS = new FileRefreshableDataSource<>(
                flowRulePath,
                flowRuleListParser
        );
        FlowRuleManager.register2Property(flowRuleRDS.getProperty());
        WritableDataSource<List<FlowRule>> flowRuleWDS = new FileWritableDataSource<>(
                flowRulePath,
                this::encodeJson
        );
        WritableDataSourceRegistry.registerFlowDataSource(flowRuleWDS);
        // 降级规则
        ReadableDataSource<String, List<DegradeRule>> degradeRuleRDS = new FileRefreshableDataSource<>(
                degradeRulePath,
                degradeRuleListParser
        );
        DegradeRuleManager.register2Property(degradeRuleRDS.getProperty());
        WritableDataSource<List<DegradeRule>> degradeRuleWDS = new FileWritableDataSource<>(
                degradeRulePath,
                this::encodeJson
        );
        WritableDataSourceRegistry.registerDegradeDataSource(degradeRuleWDS);
        // 系统规则
        ReadableDataSource<String, List<SystemRule>> systemRuleRDS = new FileRefreshableDataSource<>(
                systemRulePath,
                systemRuleListParser
        );
        SystemRuleManager.register2Property(systemRuleRDS.getProperty());
        WritableDataSource<List<SystemRule>> systemRuleWDS = new FileWritableDataSource<>(
                systemRulePath,
                this::encodeJson
        );
        WritableDataSourceRegistry.registerSystemDataSource(systemRuleWDS);
        // 授权规则
        ReadableDataSource<String, List<AuthorityRule>> authorityRuleRDS = new FileRefreshableDataSource<>(
                authorityRulePath,
                authorityRuleListParser
        );
        AuthorityRuleManager.register2Property(authorityRuleRDS.getProperty());
        WritableDataSource<List<AuthorityRule>> authorityRuleWDS = new FileWritableDataSource<>(
                authorityRulePath,
                this::encodeJson
        );
        WritableDataSourceRegistry.registerAuthorityDataSource(authorityRuleWDS);
        // 热点参数规则
        ReadableDataSource<String, List<ParamFlowRule>> paramFlowRuleRDS = new FileRefreshableDataSource<>(
                paramFlowRulePath,
                paramFlowRuleListParser
        );
        ParamFlowRuleManager.register2Property(paramFlowRuleRDS.getProperty());
        WritableDataSource<List<ParamFlowRule>> paramFlowRuleWDS = new FileWritableDataSource<>(
                paramFlowRulePath,
                this::encodeJson
        );
        ModifyParamFlowRulesCommandHandler.setWritableDataSource(paramFlowRuleWDS);
    }
    private Converter<String, List<FlowRule>> flowRuleListParser = source -> JSON.parseObject(
            source,
            new TypeReference<List<FlowRule>>() {
            }
    );
    private Converter<String, List<DegradeRule>> degradeRuleListParser = source -> JSON.parseObject(
            source,
            new TypeReference<List<DegradeRule>>() {
            }
    );
    private Converter<String, List<SystemRule>> systemRuleListParser = source -> JSON.parseObject(
            source,
            new TypeReference<List<SystemRule>>() {
            }
    );
    private Converter<String, List<AuthorityRule>> authorityRuleListParser = source -> JSON.parseObject(
            source,
            new TypeReference<List<AuthorityRule>>() {
            }
    );

    private Converter<String, List<ParamFlowRule>> paramFlowRuleListParser = source -> JSON.parseObject(
            source,
            new TypeReference<List<ParamFlowRule>>() {
            }
    );

    private void mkdirIfNotExits(String filePath) throws IOException {
        File file = new File(filePath);
        if (!file.exists()) {
            file.mkdirs();
        }
    }
    private void createFileIfNotExits(String filePath) throws IOException {
        File file = new File(filePath);
        if (!file.exists()) {
            file.createNewFile();
        }
    }
    private <T> String encodeJson(T t) {
        return JSON.toJSONString(t);
    }
}

  • 12
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Sentinel支持多种持久化方式,包括本地文件、Nacos、Zookeeper等。以下是其中一种本地文件的持久化方式的配置示例: 1. 首先,在pom.xml文件中添加以下依赖: ``` <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-file</artifactId> <version>x.y.z</version> </dependency> ``` 其中,`x.y.z`为Sentinel版本号。 2. 在应用程序的配置文件中,添加以下配置项: ``` spring.cloud.sentinel.datasource.ds1.file.data-type=json spring.cloud.sentinel.datasource.ds1.file.data-source=file:${user.home}/sentinel-rules.json ``` 其中,`ds1`为数据源名称,`data-type`表示持久化文件的格式,这里使用了JSON格式。`data-source`表示持久化文件的路径,这里使用了`${user.home}`表示用户的家目录,`sentinel-rules.json`为规则文件的名称。 3. 在规则文件中添加流控规则规则文件的默认位置为`${user.home}/sentinel-rules.json`: ``` [ { "resource": "com.example.demo.DemoController:helloSentinel", // 资源名 "limitApp": "default", // 流控针对的调用来源,若为default则不区分调用来源 "grade": 1, // 限流阈值类型,0表示线程数,1表示QPS "count": 10, // 限流阈值 "strategy": 0, // 限流控制行为,0表示直接拒绝,1表示Warm Up,2表示排队等待 "controlBehavior": 0, // 流控效果,0表示快速失败,1表示Warm Up,2表示排队等待 "clusterMode": false // 是否集群限流 } ] ``` 以上就是一个简单的Sentinel流控规则持久化配置示例。需要注意的是,在实际应用中,可以根据实际需求选择不同的持久化方式。同时,还需要根据实际业务场景设置合理的流控规则,以保证系统的稳定性和可靠性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值