草庐IT

Sentinel用法解析

Mr Tang 2024-07-03 原文

目录

一.Sentinel概述

1.Sentinel介绍

2.Sentinel核心组件

3.Sentinel基本概念

二.Sentinel核心功能

1.流量控制

2.熔断降级

三.SpringBoot整合Sentinel

1.gateway引入依赖

2.sentinel控制台搭建

3.gateway配置文件修改

4.启动gateway服务查看sentinel控制台

四.Sentinel使用

1.@SentinelResource注解

2.Sentinel的规则

3.OpenFeign支持

4.gateway规则配置

五.Sentinel控制台使用

1.实时监控

2.流控规则

 3.降级规则

4.热点数据


一.Sentinel概述

1.Sentinel介绍

        https://github.com/alibaba/Sentinel/wiki/%E4%B8%BB%E9%A1%B5

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

2.Sentinel核心组件

(1)核心库(Java 客户端):不依赖任何框架/库,能够运行于 Java 7 及以上的版本的运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。

(2)控制台(Dashboard):控制台主要负责管理推送规则、监控、集群限流分配管理、机器发现等。

3.Sentinel基本概念

        <1> 资源:资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源名来标示资源。

        <2> 规则:围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整。

二.Sentinel核心功能

1.流量控制

        Sentinel作为一个调配器,可以根据需要把随机的请求调整成合适的形状,如图

2.熔断降级

         当检测到调用链路中某个资源出现不稳定的表现,例如请求响应时间长或异常比例升高的时候,则对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联故障。

三.SpringBoot整合Sentinel

1.gateway引入依赖

<!--sentinel依赖-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    <version>2.2.5.RELEASE</version>
</dependency>

2.sentinel控制台搭建

(1)下载Sentinel控制台jar包地址:https://github.com/alibaba/Sentinel/releases

 源码地址:https://github.com/alibaba/Sentinel/releases

(2)启动:java -jar sentinel-dashboard-1.8.3.jar 启动,默认端口是8080

(3)登录:http://localhost:8080/     用户名密码都是:sentinel

3.gateway配置文件修改

spring:
  cloud:
    sentinel:
      transport:
        port: 8179
        dashboard: 127.0.0.1:8080

注意:

(1)这里的 spring.cloud.sentinel.transport.port 端口配置会在应用对应的机器上启动一个 Http Server,该 Server 会与 Sentinel 控制台做交互,比如限流规则拉取。

(2)配置信息现在是存储到nacos中,到nacos进行配置更改。

4.启动gateway服务查看sentinel控制台

四.Sentinel使用

1.@SentinelResource注解

@SentinelResource 用于定义资源,并提供可选的异常处理和 fallback 配置项。

注意该注解只能作用在实现类,不能作用在接口上面

@SentinelResource注解包含一下属性:

(1)vale

        资源名称,必需项,因为需要通过resource name找到对应的规则,这个是必须配置的。 ​ 定义资源名,该名称将会显示在控制台中,并且在定义流控以及熔断降级规则时,指定资源名称。

(2)entryType

        入口类型,可选项: EntryType.IN和EntryType.OUT(默认为 EntryType.OUT)

public enum EntryType {
    IN("IN"),
    OUT("OUT");
}

(3)blockHandler

        对应处理 BlockException 的函数名称,可选项。

(4)blockHandlerClass

        ​ blockHandler 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 blockHandlerClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。

(5)fallback

        函数名称,可选项,仅针对降级功能生效(DegradeException)。fallback 函数的访问范围需要是 public,参数类型和返回类型都需要与原方法相匹配,并且需要和原方法在同一个类中。业务异常不会进入 fallback 逻辑。

(6)fallbackClass

        fallbackClass的应用和blockHandlerClass类似,fallback 函数默认需要和原方法在同一个类中。 ​ 若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。

(7)defaultFallback

        如果没有配置defaultFallback方法,默认都会走到这里来,默认的 fallback 函数名称,可选项,通常用于通用的 fallback 逻辑,默认 fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理,若同时配置了 fallback 和 defaultFallback,则只有 fallback 会生效。

(8)exceptionsToIgnore

        用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。

2.Sentinel的规则
 

(1)流量控制规则

(2)熔断降级规则

(3)系统保护规则

(4)访问控制规则

(5)热点规则

3.OpenFeign支持

Sentinel 适配了 Feign 组件,使用步骤如下

(1)需要在服务调用方加入依赖

<!--sentinel-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    <version>2.2.5.RELEASE</version>
</dependency>
<!--Openfeign api模块中已存在也可不引入-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

(2)服务调用方配置文件中开启Feign支持 sentinel

feign:
    #开启Sentinel对Feign的支持
    sentinel:
        enabled: true

(3)远程调用代码如下

调用方

@RestController
@RequestMapping("server1")
@Slf4j
public class DemoServer1Controller {

    @Autowired
    private Server2Feign server2Feign;

    @RequestMapping("/demo1")
    public String demo1(){
        String server2Result = server2Feign.demo2("promote msg from server1");
        return server2Result;
    }
}

公共调用Feign接口

@FeignClient(name = "demo-server2")
public interface Server2Feign {

    @GetMapping("/server2/demo2/{param}")
    public String demo2(@PathVariable(value = "param") String param);
}

被调用方

@RestController
@RequestMapping("server2")
@Slf4j
public class DemoServer2Controller {

    @RequestMapping("/demo2/{param}")
    public String demo2(@PathVariable(value = "param") String param){
        if (param.startsWith("promote")){
            throw new RuntimeException("信息不存在");
        }
        return "收到server1的msg:"+param;
    }
}

在被调用方,人为制造异常,访问接口返回如下

注意:服务出现异常,可以再被调用方降级,也可以在调用方降级

下面介绍在调用方进行降级

fallback

(1)在demo-api中创建公共Feign接口的实现类

@Component
public class FallbackServer2Feign implements Server2Feign {
    @Override
    public String demo2(String param) {
        return "系统繁忙,走降级逻辑~";
    }
}

(2)在接口的注解上指定降级处理类

@FeignClient(name = "demo-server2",fallback = FallbackServer2Feign.class)
public interface Server2Feign {

    @GetMapping("/server2/demo2/{param}")
    public String demo2(@PathVariable(value = "param") String param);
}

(3)再次测试,看是否走到降级逻辑

fallbackFactory

我们可以为 DriverFeign 接口创建一个降级处理的工厂对象,在工厂对象中处理程序异常降级处理方法,用工厂对象处理可以拿到异常信息,代码如下

(1)创建工厂对象

@Component
public class Server2FallbackFactory implements FallbackFactory<Server2Feign> {
    @Override
    public Server2Feign create(Throwable throwable) {
        return new Server2Feign() {
            @Override
            public String demo2(String param) {
                return "系统繁忙,走fallbackFactory降级逻辑~";
            }
        };
    }
}

(2)在接口注解上指定工厂类

@FeignClient(name = "demo-server2",fallbackFactory = Server2FallbackFactory.class)
public interface Server2Feign {

    @GetMapping("/server2/demo2/{param}")
    public String demo2(@PathVariable(value = "param") String param);
}

(3)重新启动测试,看是否走到工厂类降级逻辑

4.gateway规则配置

(1)新增gateway配置类,配置规则信息

@Configuration
public class GatewayConfiguration {

    private final List<ViewResolver> viewResolvers;
    private final ServerCodecConfigurer serverCodecConfigurer;

    public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,
                                ServerCodecConfigurer serverCodecConfigurer) {
        this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
        this.serverCodecConfigurer = serverCodecConfigurer;
    }

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
        // Register the block exception handler for Spring Cloud Gateway.
        return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
    }

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public GlobalFilter sentinelGatewayFilter() {
        return new SentinelGatewayFilter();
    }


    @PostConstruct
    public void doInit() {
        // 自定义 api 分组
        initCustomizedApis();
        // 初始化网关流控规则
        initGatewayRules();
    }



    private void initCustomizedApis() {
        Set<ApiDefinition> definitions = new HashSet<>();
        ApiDefinition api1 = new ApiDefinition("customer_api")
                .setPredicateItems(new HashSet<ApiPredicateItem>() {{
                    add(new ApiPathPredicateItem().setPattern("/order/**")
                            /**
                             * 匹配策略:
                             * URL_MATCH_STRATEGY_EXACT:url精确匹配
                             * URL_MATCH_STRATEGY_PREFIX:url前缀匹配
                             * URL_MATCH_STRATEGY_REGEX:url正则匹配
                             */
                            .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
                }});
        definitions.add(api1);
        GatewayApiDefinitionManager.loadApiDefinitions(definitions);
    }

    private void initGatewayRules() {
        Set<GatewayFlowRule> rules = new HashSet<>();

        rules.add(new GatewayFlowRule("hailtaxi-driver") // 资源名称,可以是网关中的 routeid或者用户自定义的 API分组名称
                .setCount(2) // 限流阈值
                .setIntervalSec(10) // 统计时间窗口默认1s
                .setGrade(RuleConstant.FLOW_GRADE_QPS) // 限流模式
                /**
                 * 限流行为:
                 * CONTROL_BEHAVIOR_RATE_LIMITER 匀速排队
                 * CONTROL_BEHAVIOR_DEFAULT 快速失败(默认)
                 * CONTROL_BEHAVIOR_WARM_UP:
                 * CONTROL_BEHAVIOR_WARM_UP_RATE_LIMITER:
                 */
                .setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)
                //匀速排队模式下的最长排队时间,单位是毫秒,仅在匀速排队模式下生效
                .setMaxQueueingTimeoutMs(1000)
                /**
                 * 热点参数限流配置
                 * 若不设置,该网关规则将会被转换成普通流控规则;否则会转换成热点规则
                 */
                .setParamItem(new GatewayParamFlowItem()
                        /**
                         * 从请求中提取参数的策略:
                         * PARAM_PARSE_STRATEGY_CLIENT_IP
                         * PARAM_PARSE_STRATEGY_HOST
                         * PARAM_PARSE_STRATEGY_HEADER
                         * PARAM_PARSE_STRATEGY_URL_PARAM
                         */
                        .setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_URL_PARAM)
                        /**
                         * 若提取策略选择 Header 模式或 URL 参数模式,
                         * 则需要指定对应的 header 名称或 URL 参数名称。
                         */
                        .setFieldName("token")
                        /**
                         * 参数的匹配策略:
                         * PARAM_MATCH_STRATEGY_EXACT
                         * PARAM_MATCH_STRATEGY_PREFIX
                         * PARAM_MATCH_STRATEGY_REGEX
                         * PARAM_MATCH_STRATEGY_CONTAINS
                         */
                        .setMatchStrategy(SentinelGatewayConstants.PARAM_MATCH_STRATEGY_EXACT)
                        //参数值的匹配模式,只有匹配该模式的请求属性值会纳入统计和流控
                        .setPattern("123456") // token=123456 10s内qps达到2次会被限流
                )
        );

        rules.add(new GatewayFlowRule("customer_api")
                /**
                 * 规则是针对 API Gateway 的 route(RESOURCE_MODE_ROUTE_ID)
                 * 还是用户在 Sentinel 中定义的 API 分组(RESOURCE_MODE_CUSTOM_API_NAME),默认是 route。
                 */
                .setResourceMode(SentinelGatewayConstants.RESOURCE_MODE_CUSTOM_API_NAME)
                .setCount(2)
                .setIntervalSec(1)
                .setGrade(RuleConstant.FLOW_GRADE_QPS)
        );
        GatewayRuleManager.loadRules(rules);
    }


}

(2)启动测试

        接口一10秒内请求超过2次会 被限流

        接口二1秒内qps达到2次会被限流

五.Sentinel控制台使用

1.实时监控

        同一个服务下的所有机器的簇点信息会被汇总,并且秒级地展示在"实时监控"下。

        注意:实时监控仅存储 5 分钟以内的数据,如果需要持久化,需要通过调用实时监控接口来定制。 

实时监控接口文档参照如下连接编写

https://github.com/alibaba/Sentinel/wiki/%E5%AE%9E%E6%97%B6%E7%9B%91%E6%8E%A7

通过接口拿到的数据如下图所示:

2.流控规则

我们可以在【流控规则】页面中新增,点击【流控规则】进入页面新增页面,如下图:

资源名:可以和请求路径保持一致,

流控模式为QPS,触发流控执行阈值为1

通过上面的留空规则配置,下面的接口访问1次就被限流了。

http://localhost:8000/server1/demo1接口访问一次后被限流如下图

 3.降级规则

我们可以选择 降级规则>新增降级规则 ,如下图:

 降级规则的熔断策略有3种,分别是慢调用比例、异常比例、异常数,和程序中是一样的。

4.热点数据

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

有关Sentinel用法解析的更多相关文章

  1. Ruby 解析字符串 - 2

    我有一个字符串input="maybe(thisis|thatwas)some((nice|ugly)(day|night)|(strange(weather|time)))"Ruby中解析该字符串的最佳方法是什么?我的意思是脚本应该能够像这样构建句子:maybethisissomeuglynightmaybethatwassomenicenightmaybethiswassomestrangetime等等,你明白了......我应该一个字符一个字符地读取字符串并构建一个带有堆栈的状态机来存储括号值以供以后计算,还是有更好的方法?也许为此目的准备了一个开箱即用的库?

  2. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  3. ruby - 用逗号、双引号和编码解析 csv - 2

    我正在使用ruby​​1.9解析以下带有MacRoman字符的csv文件#encoding:ISO-8859-1#csv_parse.csvName,main-dialogue"Marceu","Giveittohimóhe,hiswife."我做了以下解析。require'csv'input_string=File.read("../csv_parse.rb").force_encoding("ISO-8859-1").encode("UTF-8")#=>"Name,main-dialogue\r\n\"Marceu\",\"Giveittohim\x97he,hiswife.\"\

  4. ruby-on-rails - 我更新了 ruby​​ gems,现在到处都收到解析树错误和弃用警告! - 2

    简而言之错误:NOTE:Gem::SourceIndex#add_specisdeprecated,useSpecification.add_spec.Itwillberemovedonorafter2011-11-01.Gem::SourceIndex#add_speccalledfrom/opt/local/lib/ruby/site_ruby/1.8/rubygems/source_index.rb:91./opt/local/lib/ruby/gems/1.8/gems/rails-2.3.8/lib/rails/gem_dependency.rb:275:in`==':und

  5. ruby - 用 YAML.load 解析 json 安全吗? - 2

    我正在使用ruby2.1.0我有一个json文件。例如:test.json{"item":[{"apple":1},{"banana":2}]}用YAML.load加载这个文件安全吗?YAML.load(File.read('test.json'))我正在尝试加载一个json或yaml格式的文件。 最佳答案 YAML可以加载JSONYAML.load('{"something":"test","other":4}')=>{"something"=>"test","other"=>4}JSON将无法加载YAML。JSON.load("

  6. ruby - 如何使用 Nokogiri 解析纯 HTML 表格? - 2

    我想用Nokogiri解析HTML页面。页面的一部分有一个表,它没有使用任何特定的ID。是否可以提取如下内容:Today,3,455,34Today,1,1300,3664Today,10,100000,3444,Yesterday,3454,5656,3Yesterday,3545,1000,10Yesterday,3411,36223,15来自这个HTML:TodayYesterdayQntySizeLengthLengthSizeQnty345534345456563113003664354510001010100000344434113622315

  7. python - 帮我找到合适的 ruby​​/python 解析器生成器 - 2

    我使用的第一个解析器生成器是Parse::RecDescent,它的指南/教程很棒,但它最有用的功能是它的调试工具,特别是tracing功能(通过将$RD_TRACE设置为1来激活)。我正在寻找可以帮助您调试其规则的解析器生成器。问题是,它必须用python或ruby​​编写,并且具有详细模式/跟踪模式或非常有用的调试技术。有人知道这样的解析器生成器吗?编辑:当我说调试时,我并不是指调试python或ruby​​。我指的是调试解析器生成器,查看它在每一步都在做什么,查看它正在读取的每个字符,它试图匹配的规则。希望你明白这一点。赏金编辑:要赢得赏金,请展示一个解析器生成器框架,并说明它的

  8. ruby - 如何用 Nokogiri 解析连续的标签? - 2

    我有这样的HTML代码:Label1Value1Label2Value2...我的代码不起作用。doc.css("first").eachdo|item|label=item.css("dt")value=item.css("dd")end显示所有首先标记,然后标记标签,我需要“标签:值” 最佳答案 首先,您的HTML应该有和中的元素:Label1Value1Label2Value2...但这不会改变您解析它的方式。你想找到s并遍历它们,然后在每个你可以使用next_element得到;像这样:doc=Nokogiri::HTML(

  9. ruby - 有人可以解释一下在 Ruby 中注入(inject)的真实、通俗易懂的用法吗? - 2

    我正在学习Ruby,遇到了inject。我正处于理解它的风口浪尖,但当我是那种需要真实世界的例子来学习一些东西的人时。我遇到的最常见的例子是人们使用inject来添加一个(1..10)范围的总和,我不太关心这个。这是一个任意的例子。在实际程序中我会用它做什么?我正在学习,所以我可以继续使用Rails,但我不必有一个以Web为中心的示例。我只需要一些我可以全神贯注的目标。谢谢大家。 最佳答案 inject有时可以通过它的“其他”名称reduce更好地理解。它是一个对Enumerable进行操作(迭代一次)并返回单个值的函数。它有许多有

  10. ruby-on-rails - 如何在 Rails 3 中禁用 XML 解析 - 2

    我想禁用HTTP参数的自动XML解析。但我发现命令仅适用于Rails2.x,它们都不适用于3.0:config.action_controller.param_parsers.deleteMime::XML(application.rb)ActionController::Base.param_parsers.deleteMime::XMLRails3.0中的等价物是什么? 最佳答案 根据CVE-2013-0156的最新安全公告你可以将它用于Rails3.0。3.1和3.2ActionDispatch::ParamsParser::

随机推荐