sentinel使用与配置

Sentinel 是面向分布式服务架构的高可用流量防护组件,主要以流量为切入点,从限流、流量整形、熔断降级、系统负载保护、热点防护等多个维度来帮助开发者保障微服务的稳定性。
Sentinel 分为两个部分:

核心库(Java 客户端):不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。
控制台(Dashboard):基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器。

Sentinel适配目前多种的主流框架,包括Spring Cloud,Dubbo等。Sentinel的开源丰富了阿里巴巴微服务开源体系,对稳定性组件提供了更多的解决方案。

sentinel使用:

1 控制台下载并启动

控制台下载地址 https://github.com/alibaba/Sentinel/releases

下载完成后用java -jar 运行 即可在本地localhost:8080看到控制台界面如下
登陆的账号密码都是sentinel.

2 核心库引入对服务进行流控

pom文件引入

<!--sentinel核心库-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!--sentinel持久化到nacos用到-->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

启动微服务查看sentinel控制台

并没有看到任何监控服务,但这并不能证明配置有问题,由于sentinel的内部机制就是懒加载,所以我们需要先访问微服务的任意可访问接口初始化加载一次即可。

然后让问sentinel控制台就可以看到被监控的微服务

这里在引入pom依赖时出现了一个错误,使我搞了一天/(ㄒoㄒ)/~~,

在terminal输入下面命令强制更新:即可解决此问题
mvn clean install -e -U

然后重新导入依赖即可。

sentinel流控规则

阈值类型

1 .QPS

新增流控规则,按系统默认规则。

按规则访问访问次数低于1秒1次时,可以正常访问。

当访问频次大于1秒1次时,就会被sentinel流量限制

2. 线程数

可以使用jmeter进行多线程测试,也可以限制低阈值开两个浏览器标签页进行访问,原理和QPS流控方式差不多。

流控规则

流控模式

1. 直接

api达到限流条件时,直接限流

2. 关联

当关联资源达到限流条件时,限流自己。

访问testB后立即访问testA,会被限流。

流控效果

1. 快速失败

之前配置的流控效果都是快速失败,即浏览器报出错误信息。

2. 预热(warn up)

根据codeFactor(冷加载因子,默认是3)的值,从阈值/codeFactor,经过预热时长,才到达设置qps阈值。

如上配置即表示前10秒内单机阈值是3/3=1,过了10秒后,阈值变为3,给系统一个预热的时间。

此种情况适用于秒杀系统,秒杀系统开启的瞬间会有很多流量上来,很有可能把系统打死,预热的方式是为了保护系统,可慢慢的把流量放进来,慢慢的把阈值调整为设定的阈值。

3. 排队等待

流量大的时候,请求按照顺序排队等待。

降级规则

熔断策略

此处降级规则是对服务生效,即对某个监控的微服务生效。

sentinel熔断降级会在调用链路中某个资源出现不稳定状态时,对这个资源进行限制,让请求快速失败,避免影响到其他的资源而导致级联错误。

当资源被降级后,在接下来的降级时间窗口内,对该资源的调用都会自动熔断(默认行为是抛出DegredeException)

RT(平均相应时间,秒级)

平均相应时间超过阈值(RT值)    且   在时间窗口内通过的请求>=5,      两个条件同时满足后触发降级。

异常比例(秒级)

QPS>=5且异常比例超过阈值时,触发降级,时间窗口结束后关闭降级。

异常数(分钟级)

异常数(分钟级)超过阈值时,触发降级,时间窗口结束后关闭降级。

热点规则(热点key)

何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:

商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制
热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。
热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。

到目前为止熔断限流报错都是默认的sentinel报错信息,我们可以将信息提示换成我们自定义的信息。需要用到一个新注解@SentinelResource

测试代码如下:

规则配置如下:资源名可以是限流的value值(即 testHotkey)也可以是限流接口的uri(即 /testHotkey)

低于1秒一次的访问

高于1秒一次的访问

如果没有参数p1,访问频次多高也不会出问题

在配置页面还有一个参数例外项

配置参数例外项的效果就是,正常p1的访问限制是1秒1次,但当p1的值为50时,阈值就可以为200。

还有一点,就是@SentinelResource只负责控制台配置的错误处理,即blockhandler只处理value绑定的问题,但如果程序自己抛异常,他是处理不了的。

系统规则

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

@SentinelResource再深入

目前限流方案存在的问题

1 . 系统默认的,没有体现我们自己的业务要求。

2 . 依照现有条件,我们自定义的处理方法又和业务代码耦合在一块,不直观。

3 . 每个业务方法都要添加一个兜底方法,代码膨胀家具。

4 . 全局统一的处理方法没有体现。

我们进行如下操作:

新增流控处理类blockhandler

在流控接口上进行配置,使其关联到自定义规则的相关方法。

当触发流控规则后,会调用自定义的全局流控规则。

之前我们曾提到blockHandler只用于处理流控异常问题。对于程序本身的运行是异常是不做处理的。此处我们就需要调用另一种方法--fallback

当再次访问接口时,就会走 fallbackException 处理运行时异常的问题。

sentinel规则持久化

现在sentinel控制台存在这么一个问题,当重新登录控制台或者关闭服务,控制台的流控规则就消失了。

sentinel持久化有三种模式

 

pull模式

此模式需要编写一点配置代码,将规则持久化到本地文件。

加入依赖

<!--sentinel持久化pull模式到本地文件-->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-extension</artifactId>
</dependency>

编写配置类

package com.dbcenter.service.config;

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 java.io.File;
import java.io.IOException;
import java.util.List;

public class FileDataSourceInit implements InitFunc {
    @Override
    public void init() throws Exception {
// TIPS: 如果你对这个路径不喜欢,可修改为你喜欢的路径
        String ruleDir = System.getProperty("user.home") + "/sentinel/rules";
        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 hotParamFlowRulePath = ruleDir + "/param-flow-rule.json";

        this.mkdirIfNotExits(ruleDir);
        this.createFileIfNotExits(flowRulePath);
        this.createFileIfNotExits(degradeRulePath);
        this.createFileIfNotExits(systemRulePath);
        this.createFileIfNotExits(authorityRulePath);
        this.createFileIfNotExits(hotParamFlowRulePath);
        // 流控规则
        ReadableDataSource<String, List<FlowRule>> flowRuleRDS = new FileRefreshableDataSource<>(
                flowRulePath,
                flowRuleListParser
        );
        // 将可读数据源注册至FlowRuleManager
        // 这样当规则文件发生变化时,就会更新规则到内存
        FlowRuleManager.register2Property(flowRuleRDS.getProperty());
        WritableDataSource<List<FlowRule>> flowRuleWDS = new FileWritableDataSource<>(
                flowRulePath,
                this::encodeJson
        );
        // 将可写数据源注册至transport模块的WritableDataSourceRegistry中
        // 这样收到控制台推送的规则时,Sentinel会先更新到内存,然后将规则写入到文件中
        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<>(
                flowRulePath,
                authorityRuleListParser
        );
        AuthorityRuleManager.register2Property(authorityRuleRDS.getProperty());
        WritableDataSource<List<AuthorityRule>> authorityRuleWDS = new FileWritableDataSource<>(
                authorityRulePath,
                this::encodeJson
        );
        WritableDataSourceRegistry.registerAuthorityDataSource(authorityRuleWDS);

        // 热点参数规则
        ReadableDataSource<String, List<ParamFlowRule>> hotParamFlowRuleRDS = new FileRefreshableDataSource<>(
                hotParamFlowRulePath,
                hotParamFlowRuleListParser
        );
        ParamFlowRuleManager.register2Property(hotParamFlowRuleRDS.getProperty());
        WritableDataSource<List<ParamFlowRule>> paramFlowRuleWDS = new FileWritableDataSource<>(
                hotParamFlowRulePath,
                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>> hotParamFlowRuleListParser = source -> JSON.parseObject(
            source,
            new TypeReference<List<ParamFlowRule>>() {
            }
    );

    /**
     * 创建目录
     *
     * @param filePath
     */
    private void mkdirIfNotExits(String filePath) {
        File file = new File(filePath);
        if (!file.exists()) {
            file.mkdirs();
        }
    }

    /**
     * 创建文件
     *
     * @param filePath
     * @throws IOException
     */
    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);
    }
}

resource下新增配置文件,名字为 com.alibaba.csp.sentinel.init.InitFunc

内容为上面配置类的全类名

重启项目,配置相关限流规则,就可以在对应目录看到相关持久化配置文件了。

由于此种方式是客户端定时从规则中心拉取规则,所以,可能会出现sentinel客户端显示不及时的情况。经过测试,当被配置的微服务重启后,基本上需要10分钟才会再控制台上显示。

但是其实只要服务启动起来,其配置规则还是先生效的,即使控制台不显示配置信息。

然后经过10分钟左右后,信息就会同步到控制台。

push模式

我们可以将流控规则持久化进nacos进行保存。只要刷新微服务的某个rest地址,sentinel控制台的流控规则就能看到,只要nacos里面的配置不删除,针对改微服务的流控规则持续有效。

1. 首先pom添加依赖

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

2. yml添加配置

3. 登录nacos新增配置

4. 重启服务,测试接口

成功。

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值