分布式微服务流量控制Sentinel由浅入深

2024-03-06 10:30

本文主要是介绍分布式微服务流量控制Sentinel由浅入深,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Sentinel简介

1.1 流量控制&熔断降级介绍

1.1.1 流量控制

举个例子,故宫每天限制有个八万人,超过八万人就买不到票,因为如果人数太多会影响景点的正常开放。这种只卖N张票的操作就是流量控制。

流量控制在网络中是一个常用的概念,它用于调整网络包的发送数据,在网络传输时,任意时间到来的请求往往时随机不可控的,而系统的处理能力是有限的,我们需要根据系统的处理能力对流量进行控制。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CN2DONcr-1626340668105)(C:\Users\dell\AppData\Roaming\Typora\typora-user-images\1625469096656.png)]

1.1.2 熔断降级简介

在调用系统的时候,如果调用链路中某个资源出现问题,最终会导致请求发生堆积

在这里插入图片描述

而熔断降级就可以解决这个问题,所谓的熔断降级就是当检测到调用链路中某个资源出现问题,例如请求时间过长,则对这个资源的调用进行限制,让请求快速失败,避免影响到其他资源而导致级联故障。

1.1.3 流量控制&熔断降级的实现方案

  • Hystrix:在分布式环境中,许多服务依赖项中的一些必然会失败。Hystrix是一个库,通过添加延迟容忍和容错逻辑,帮助你控制这些分布式服务之间的交互。Hystrix通过隔离服务之间的访问点、停止级联失败和提供回退选项来实现这一点,所有这些都可以提高系统的整体弹性。
  • Resilience4j :Resilience4j是一个轻量级容错框架,设计灵感来源于Netflix 的Hystrix框架,为函数式编程所设计。Resilience4j 提供了一组高阶函数(装饰器),包括断路器,限流器,重试,隔离,可以对任何的函数式接口,lambda表达式,或方法的引用进行增强,并且这些装饰器可以进行叠加。这样做的好处是,你可以根据需要选择特定的装饰器进行组合。在使用时,你不需要引入所有和Resilience4j相关的包,只需要引入所需要的即可。
  • Sentinel :Sentinel 是面向分布式服务架构的高可用流量防护组件,主要以流量为切入点,从限流、流量整形、熔断降级、系统负载保护、热点防护等多个维度来帮助开发者保障微服务的稳定性。

对比

SentinelHystrixResilience4j
隔离策略信号量隔离线程池隔离/信号量隔离信号量隔离
熔断降级策略基于响应时间,异常比例,异常数基于异常比例基于响应时间,异常比例
实时统计实现滑动窗口滑动窗口Ring Bit Buffer
动态规则配置支持多种数据源支持多种数据源有限支持
扩展性多个扩展点插件的形式接口的形式
基于注解的支持支持支持支持
限流基于QPS,支持调用关系的限流有限的支持Rate Limiter
流量整形支持预热模式、匀速器模式、预热排队模式不支持简单的Rate Limiter模式
系统自适应保护支持不支持不支持
控制台提供开箱即用控制台,可配置规则,查看秒级监控,机器发现等简单的监控查看不提供控制台

1.2 Sentinel介绍

1.2.1 Sentinel简介

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

  • Sentinel组成
    • 核心库:主要指java客户端,不依赖任何框架/库,能运行java 7及以上的版本的运行时环境,同时对Dubbo/Spring Cloud等框架也有较好的支持
    • 控制台:控制台主要负责管理推送规则、监控、集群限流分配管理、机器发现等

1.2.2 Sentinel特征

  • 丰富的应用场景:承接10年双十一大促场景,例如:秒杀、消息的削峰填谷、集群流量控制
  • 完备的实时监控:提供实时监控功能,在控制台可查看接入的单台机器的秒级数据
  • 广泛的开源生态:提供开箱即用的与其他开源框架整合模块
  • 完善的SPI扩展点:提供简单易用、完善的SPI扩展接口,可以通过实现接口快速定制逻辑

1.2.3 Sentinel特性

在这里插入图片描述

1.2.4 Sentinel开源生态

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kkWb1ov1-1626340668112)(C:\Users\dell\AppData\Roaming\Typora\typora-user-images\1625472651871.png)]

1.2.5 Sentinel 的相关概念

  • 资源:资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。在接下来的文档中,我们都会用资源来描述代码块。只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源名来标示资源。
  • 规则:围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整。

1.2.6 Sentinel的优势

  • 友好的控制面板
  • 支持实时监控
  • 支持多种限流,支持QPS\线程数等多种限流策略
  • 支持多种降级模式,平均返回时间降级、异常率降级
  • 方便扩展开发
  • 支持链路的关联,可实现链路统计限流、系统保护、热门资源保护等

Sentinel入门

2.1 Sentinel本地应用构建

  • 创建本地应用

    • 创建项目

    • 引入依赖

      <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
      </dependency><dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-core</artifactId><version>1.8.2</version>
      </dependency>
      
    • 定义限流规则

      @RequestMapping(value = "/test")
      public String test(){//SphU.entry 启用限流try (Entry Entry = SphU.entry("Test")){return "你好,Sentinel";}catch (Exception e){return "系统繁忙!";}
      }//定义限流规则
      @PostConstruct
      public void initFlowRules(){//创建集合存放限流规则List<FlowRule> rules = new ArrayList<>();//创建限流规则FlowRule rule = new FlowRule();rule.setResource("Test"); //定义资源rule.setGrade(RuleConstant.FLOW_GRADE_QPS); //定义限流规则类型rule.setCount(1); //每秒可通过的请求个数//存入集合rules.add(rule);//Sentinel加载集合FlowRuleManager.loadRules(rules);
      }
      
  • 搭建本地Sentinel控制台

    • 下载Sentinel控制台jar包:下载地址

    • 运行jar包

      java -Dserver.port=8088 -jar [jarname.jar]
      
    • 访问测试: http://localhost:8088

  • 本地应用接入本地Sentinel控制台

    • 引入依赖

      <dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-transport-simple-http</artifactId><version>1.8.2</version> <!-- 需要注意版本号 -->
      </dependency>
      
    • 配置本地应用的JVM参数

      -Dcsp.sentinel.dashboard.server=localhost:8088 -Dproject.name=SentinelDemo
      

    在这里插入图片描述

2.2 限流规则

Sentinel提供了两套设置限流规则的方式

  • 在应用中使用代码编写流控规则(之前案例展示)

    //定义限流规则
    @PostConstruct
    public void initFlowRules(){//创建集合存放限流规则List<FlowRule> rules = new ArrayList<>();//创建限流规则FlowRule rule = new FlowRule();rule.setResource("Test"); //定义资源rule.setGrade(RuleConstant.FLOW_GRADE_QPS); //定义限流规则类型rule.setCount(1); //每秒可通过的请求个数//存入集合rules.add(rule);//Sentinel加载集合FlowRuleManager.loadRules(rules);
    }
    
  • 在Sentinel控制台设置流控规则

    在这里插入图片描述

2.3 Sentinel定义资源的方式

sentinel提供的定义资源的方式

  • 抛出异常的方式定义资源
  • 返回布尔值方式定义资源
  • 异步调用支持
  • 注解方式定义资源
  • 主流框架的默认适配

2.3.1 抛出异常的方式定义资源

Sentinel中的SphU包含了try-catch风格的API,用这种方式,当资源发生了限流之后会抛出BlockException。这个时候可以捕捉异常,进行限流之后的逻辑处理,关键代码如下:

@RequestMapping(value = "/test")
public String test(){//SphU.entry 启用限流try (Entry Entry = SphU.entry("Test")){return "你好,Sentinel";}catch (Exception e){return "系统繁忙!";}
}

2.3.2 返回布尔值方式定义资源

Sentinel中的SphO提供if-else风格的API,用这种方式,当资源发生限流之后会返回false这个时候可以根据返回值,进行限流之后的逻辑处理。

@RequestMapping(value = "/testBoo")public String test(){//SphO.entry 启用限流if(SphO.entry("TestBoo")){ //不存在限流try {return "你好,Sentinel";}finally { //保证SphO.entry需要和SphO.exit成对出现//SphO.entry需要和SphO.exit成对出现,//否则会影响到调用链记录,抛出异常SphO.exit();}}else{ //存在限流return "系统繁忙!";}}

2.3.3 异步调用支持

Sentinel支持异步调用链路的统计,在异步调用中,需要通过SphU.asyncEntry方法定义资源,并通常需要在异步的回调函数中调用exit方法

  • 开启异步支持

    @EnableAsync
    @SpringBootApplication
    public class SentinelApplication {public static void main(String[] args) {SpringApplication.run(SentinelApplication.class, args);}}
    
  • 创建异步方法

    @Async
    public void hello(){System.out.println("异步开始");try {Thread.sleep(500);} catch (InterruptedException e) {System.out.println(e.getMessage());}System.out.println("异步结束");
    }
    
  • 限流实现

    @Autowired
    private TestService testService;@RequestMapping(value = "/testAsync")
    public void test(){AsyncEntry asyncEntry = null;try {asyncEntry = SphU.asyncEntry("TestAsync"); //限流入口testService.hello(); //调用异步方法} catch (BlockException e) {System.out.println("系统繁忙!");} finally {if(null != asyncEntry)asyncEntry.exit(); //限流出口}
    }
    

2.3.4 注解方式定义资源

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

  • 引入依赖

    <dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-annotation-aspectj</artifactId><version>1.8.2</version>
    </dependency>
    
  • 创建AspectJ的配置类

    @Configuration
    public class SentinelAspectConfig {@Beanpublic SentinelResourceAspect sentinelResourceAspect(){return new SentinelResourceAspect();}}
    
  • 实现流控

    @SentinelResource(value = "testRes",blockHandler = "exHandler")
    @RequestMapping("/testAspect")
    public String hello(){return "hello,Sentinel";
    }public String exHandler(BlockException e){System.out.println(e.getMessage());return "系统繁忙!";
    }
    

Sentinel高级

3.1 Spring Cloud整合Sentinel

  • 引入依赖

    <!-- Spring Cloud整合Sentinel -->
    <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId><version>2.2.1.RELEASE</version>
    </dependency>
    
  • 创建测试用例

    @SentinelResource(value = "testRes",blockHandler = "exHandler")
    @RequestMapping("/testAspect")
    public String hello(){return "hello,Sentinel";
    }public String exHandler(BlockException e){System.out.println(e.getMessage());return "系统繁忙!";
    }
    
  • 修改配置文件,配置接入的控制台

    #配置
    spring:application:name: SentinelDemo #项目名称cloud:sentinel:transport:dashboard: localhost:8088 #本地控制台
    

3.2 Feign整合Sentinel

  • 新建feign客户端

  • 引入依赖

    <!-- feign -->
    <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId><version>3.0.2</version>
    </dependency><!-- Feign整合Sentinel -->
    <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId><version>2.2.1.RELEASE</version>
    </dependency>
    
  • 配置feign支持sentinel

    #配置
    spring:application:name: shop-feign-clientcloud:#配置Sentinelsentinel:transport:dashboard: localhost:8088#Feign开启Sentinel
    feign:sentinel:enabled: true#eureka注册中心配置
    eureka:client:service-url:defaultZone: http://localhost:10000/eureka/
  • 编写限流处理类

    @Component
    public class ProductServiceHandler implements ProductService {@Overridepublic Object queryProduct() {return "系统繁忙!";}}
    
    @FeignClient(value = "shop-product-server",fallback = ProductServiceHandler.class)
    public interface ProductService {@GetMapping("/product/query")public Object queryProduct();}
    
  • 配置限流规则

    在配置中心配置限流规则,Feign配置限流资源名需要满足格式http请求方式:协议:服务器:路径及参数。例如 GET:http://localhost:8089/queryProduct

3.3 Spring Cloud Gateway整合Sentinel

  • 创建Gateway项目

  • 引入依赖

    <!-- 集成Sentinel实现Sentinel限流 -->
    <dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-spring-cloud-gateway-adapter</artifactId><version>1.8.1</version>
    </dependency>
    <!-- eureka -->
    <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <!-- gateway -->
    <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    <!-- 监控依赖 -->
    <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    
  • 配置路由

    spring:application:name: shop-gateway-server#配置gateway的路由cloud:gateway:routes:#路由ID\URI\断言- id: product-api#使用注册中心;格式需满足 lb:// 注册中心获取微服务的名称uri: lb://shop-product-server predicates:- Path=/product-service/**filters: #配置过滤器,实现路径重写转发- RewritePath=/product-service/(?<segment>.*), /$\{segment} 
    #eureka注册中心配置
    eureka:client:service-url:defaultZone: http://localhost:10000/eureka/
    
  • 编写Sentinel限流配置类

    @Configuration
    public class MySentinelConfig {private final List<ViewResolver> viewResolvers;private final ServerCodecConfigurer serverCodecConfigurer;public MySentinelConfig(ObjectProvider<List<ViewResolver>> viewResolversProvider, ServerCodecConfigurer serverCodecConfigurer) {this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);this.serverCodecConfigurer = serverCodecConfigurer;}@Bean@Order(Ordered.HIGHEST_PRECEDENCE)public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler(){return new SentinelGatewayBlockExceptionHandler(viewResolvers,serverCodecConfigurer);}@Bean@Order(Ordered.HIGHEST_PRECEDENCE)public GlobalFilter sentinelGatewayFilter(){return new SentinelGatewayFilter();}@PostConstructprivate void initGatewayRules(){Set<GatewayFlowRule> rules = new HashSet<>();//服务ID限流
    //        rules.add(new GatewayFlowRule("product-api") //资源名称,这里为路由router的ID
    //                //路由模式
    //                .setResourceMode(SentinelGatewayConstants.RESOURCE_MODE_ROUTE_ID)
    //                .setCount(1) //QPS即每秒钟允许的调用次数
    //                .setIntervalSec(1)); //每隔多少时间统计一次汇总数据//配置分组限流rules.add(new GatewayFlowRule("product-api") //分组名称.setCount(1) //QPS即每秒钟允许的调用次数.setIntervalSec(1)); //每隔多少时间统计一次汇总数据rules.add(new GatewayFlowRule("order-api") //分组名称.setCount(1) //QPS即每秒钟允许的调用次数.setIntervalSec(1)); //每隔多少时间统计一次汇总数据GatewayRuleManager.loadRules(rules);}//自定义分组限流,基于API@PostConstructprivate void initCustomizedApis(){Set<ApiDefinition> apiDefinitions = new HashSet<>();ApiDefinition api1 = new ApiDefinition("product-api") //分组名称.setPredicateItems(new HashSet<ApiPredicateItem>(){{add(new ApiPathPredicateItem().setPattern("/product-service/product/**")); //配置匹配的连接API(模糊匹配)}});ApiDefinition api2 = new ApiDefinition("order-api").setPredicateItems(new HashSet<ApiPredicateItem>(){{add(new ApiPathPredicateItem().setPattern("/product-service/order")); //配置匹配的连接API(完全匹配)}});apiDefinitions.add(api1);apiDefinitions.add(api2);GatewayApiDefinitionManager.loadApiDefinitions(apiDefinitions);}@PostConstructpublic void initBlockHandlers(){//声明自定义异常信息BlockRequestHandler handler = new BlockRequestHandler() {@Overridepublic Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {Map<String,String> result = new HashMap<>();result.put("code","403");result.put("message","对不起,请稍后再试");return ServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON_UTF8).body(BodyInserters.fromObject(result));}};GatewayCallbackManager.setBlockHandler(handler); //设置自定义异常信息}
    }
    

3.4 Sentinel流控规则实现

流量控制(Flow Control)其原理是监控应用流量的QPS或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。

流量控制主要有两种方式

  • 并发线程数:并发线程数限流保护业务线程数不被耗尽
  • QPS:当QPS超过阈值,采取措施进行流量控制

一条限流规则主要由下面几个因素组成,通过组合实现不同的限流效果:

  • resource:资源名,即限流规则的作用对象
  • count:限流阈值
  • grade:限流阈值类型(QPS或并发线程数)
  • limitApp:流控针对的调用来源,若为default则不区分调用来源
  • strategy:调用关系限流策略
  • controlBehavior:流量控制效果(直接拒绝、Warm Up、匀速排队)

同一资源可以同时配置多个限流规则,按顺序执行

3.5 Sentinel熔断降级规则实现

熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它资源而导致级联错误,当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都会自动熔断(默认行为为抛出异常)。

重要属性

属性说明默认值
resource资源名
count阈值
grade熔断策略,支持秒级RT、秒级异常比例、分钟级异常数秒级RT
timeWindow降级的时间,单位S
rtSlowRequestAmountRT模式下1秒内连续多少个请求的平均RT超出阈值方可触发熔断5
minRequestAmount异常熔断的触发最小请求数,请求数小于该值时即使异常比例超出阈值也不会熔断5

同一资源可以同时有多个降级规则。

熔断策略详解:

  • 平均响应时间(DEGRADE_GRADE_RT):当1秒内连续N个请求的平均响应时间均超出阈值,那么在接下来的熔断时间窗口内,对这个方法的调用都会直接熔断。
  • 异常比例(DEGRADE_GRADE_EXCEPTION_RATIO):当资源的每秒请求量>=N,并且每秒异常总数占通过量的比例超出阈值之后,资源降级,之后的时间内对这个资源的访问都会自动返回,异常比例值的范围是[0.01.0],代表0%100%。
  • 异常数(DEGRADE_GRADE_EXCEPTION_COUNT):当资源近1分钟的异常数超出阈值之后会进行熔断,注由于统计时间是分钟级别的,若timeWindow小于60s,则结束熔断状态后仍可能再进入熔断状态。

本地代码实现熔断降级配置:

  • 引入依赖

    <!-- Spring Cloud整合Sentinel -->
    <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId><version>2.2.1.RELEASE</version>
    </dependency>
    
  • 修改配置文件

    spring:application:name: SentinelDemocloud:sentinel:transport:dashboard: localhost:8088
    
  • 配置熔断降级资源

    @SentinelResource(value = "testDegrade",blockHandler = "exHandler")
    @RequestMapping("/testDegrade")
    public String hello(){return "hello,Sentinel";
    }public String exHandler(BlockException e){System.out.println(e.getMessage());return "系统繁忙!";
    }
    
  • 配置熔断降级规则

    //定义熔断降级规则
    @PostConstruct
    public void initDegradeRule(){//创建存放熔断降级规则的集合List<DegradeRule> rules = new ArrayList<>();//创建熔断降级规则DegradeRule rule = new DegradeRule();//定义资源名rule.setResource("testDegrade");//阈值 平均响应时间rule.setCount(0.01);//定义规则类型rule.setGrade(RuleConstant.DEGRADE_GRADE_RT);//定义降级时间,秒级rule.setTimeWindow(2);//加入集合rules.add(rule);//加载熔断降级规则DegradeRuleManager.loadRules(rules);
    }
    

我们也可以通过本地Sentinel控制台实现熔断降级配置。

在这里插入图片描述

3.6 Sentinel系统自适应保护实现

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

系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效,入口流量指的是进入应用的流量、例如web服务接收的请求等

系统规则支持的格式:

  • Load自适应(仅支持Liunx服务器):系统的load作为启发指标,进行自适应系统保护,当系统load超过设定的启发值且系统当前的并发线程数超过估算的系统容量时才会触发系统保护,系统容量由系统的maxQPS *minRT,设定参考值一般是CPU核心数的2.5倍。
  • CPU usage:当系统CPU使用率超过阈值即触发系统保护(取值范围0.0~1.0)
  • 平均RT:当单台机器上所有人入口流量的平均RT达到阈值即触发系统保护,单位毫秒
  • 并发线程数:当单台机器上所有人入口流量的并发线程数达到阈值即触发系统保护
  • 入口QPS:当单台机器上所有人入口流量的QPS达到阈值即触发系统保护

重要的属性:

属性说明默认值
highestSystemLoadload1触发值,用于触发自适应控制阶段-1(不生效)
avgRt所有入口的平均响应时间-1(不生效)
maxThread入口流量的最大并发数-1(不生效)
qps所有入口资源的QPS-1(不生效)
highestCpuUsage当前系统的CPU使用率(0.0~1.0)-1(不生效)

本地代码实现

@SentinelResource(entryType = EntryType.IN)
@RequestMapping("/testSys")
public String hello(){return "hello,Sentinel";
}//定义系统自适应规则
@PostConstruct
public void initSysRule(){//创建存放系统自适应规则的集合List<SystemRule> rules = new ArrayList<>();//创建系统自适应规则SystemRule rule = new SystemRule();//定义资源名rule.setQps(2);//加入集合rules.add(rule);//加载熔断降级规则SystemRuleManager.loadRules(rules);
}

本地控制台实现

在这里插入图片描述

3.7 Sentinel授权控制实现

使用Sentinel的来源访问控制(黑名单白名单控制)判断来源请求是否允许放行,若配置白名单则只有请求来源位于白名单时才可以通过,配置黑名单则请求来源位于黑名单时不通过,其余的请求通过。

重要的属性:

  • resource:资源名,即限流规则的作用对象
  • limitApp:请求来源,对应的黑名单/白名单,多个使用‘,’分隔
  • strategy:限制模式,AUTHORITY_WHITE为白名单模式,AUTHORITY_BLACK为黑名单模式,默认为白名单模式。

本地代码实现:

@SentinelResource(value = "TestWB",blockHandler = "exHandler")
@RequestMapping("/testWB")
public String hello()  {return "hello,Sentinel";
}public String exHandler(BlockException e){System.out.println(e.getMessage());return "系统繁忙!";
}//设置请求来源解析
@PostConstruct
public void init(){WebCallbackManager.setRequestOriginParser(ServletRequest::getRemoteAddr);
}//定义授权规则
@PostConstruct
public void initWhiteRule(){//创建存放授权规则的集合List<AuthorityRule> rules = new ArrayList<>();//创建授权规则AuthorityRule rule = new AuthorityRule();//定义资源名rule.setResource("TestWB");//定义白名单rule.setLimitApp("192.168.222.1,127.0.0.1");//定义授权模式rule.setStrategy(RuleConstant.AUTHORITY_WHITE);//加入集合rules.add(rule);//加载授权规则AuthorityRuleManager.loadRules(rules);
}

本地控制台实现:

在这里插入图片描述

3.8 Sentinel动态规则扩展实现

规则管理中心:

  • Nacos
  • Zookeeper
  • Apollo

规则管理中心的实现方式:

  • 拉取式:客户端主动向某个规则管理中心定期轮巡拉取规则,这个规则管理中心可以是文件,甚至是VCS等,这样做的方式是简单,缺点是无法实时获取变更;实现拉取模式的数据源最简单的方式是继承AutoRefreshDataSource抽象类,然后实现readSource方法,在该方法里从指定数据源读取字符串格式的配置数据。
  • 推送式:规则管理中心同一推送,客户端通过注册监听器的方式时刻监听变化,比如使用ZookeeperApollo等作为规则管理中心,这种方式有更好的实时性和一致性保证,实现那推送模式的数据源最简单的方式是继承AbstractDataSource抽象类,在其构造方法中添加监听器,并实现readSource从指定数据源读取字符串格式的配置数据。

使用Zookeeper实现推送式规则配置:

  • 创建项目sentinel_zookeeper

  • 引入依赖

    <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId><version>2.2.1.RELEASE</version>
    </dependency><dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-datasource-zookeeper</artifactId><version>1.8.2</version>
    </dependency>
    
  • 配置文件

    spring:application:name: SentinelDemocloud:sentinel:transport:dashboard: localhost:8088
    
  • 编写配置类

    @Configuration
    public class ZookeeperSentinelConfig {//连接zookeeper获取规则@PostConstructvoid loadRules(){final String ZOOKEEPER_URL = "127.0.0.1:2181";final String ZOOKEEPER_FILE_PATH = "/sentinel/zookeeper";ReadableDataSource<String, List<FlowRule>> readableDataSource = new ZookeeperDataSource<>(ZOOKEEPER_URL, //zookeeper连接地址ZOOKEEPER_FILE_PATH,  //zookeeper文件路径source -> JSON.parseObject(source,new TypeReference<List<FlowRule>>(){}) //存放的数据类型);//注册数据资源到FlowRuleManagerFlowRuleManager.register2Property(readableDataSource.getProperty());}
    }
    
  • 编写资源流控配置

    @SentinelResource(value = "TestZK", blockHandler = "exHandler")
    @RequestMapping("/testZK")
    public String hello() {return "hello,Sentinel";
    }public String exHandler(BlockException e) {System.out.println(e.getMessage());return "系统繁忙!";
    }
    

原理

Sentinel 功能和设计理念

流量控制

什么是流量控制

流量控制在网络传输中是一个常用的概念,它用于调整网络包的发送数据。然而,从系统稳定性角度考虑,在处理请求的速度上,也有非常多的讲究。任意时间到来的请求往往是随机不可控的,而系统的处理能力是有限的。我们需要根据系统的处理能力对流量进行控制。Sentinel 作为一个调配器,可以根据需要把随机的请求调整成合适的形状,如下图所示:

img

流量控制设计理念

流量控制有以下几个角度:

  • 资源的调用关系,例如资源的调用链路,资源和资源之间的关系;
  • 运行指标,例如 QPS、线程池、系统负载等;
  • 控制的效果,例如直接限流、冷启动、排队等。

Sentinel 的设计理念是让您自由选择控制的角度,并进行灵活组合,从而达到想要的效果。

熔断降级

什么是熔断降级

除了流量控制以外,及时对调用链路中的不稳定因素进行熔断也是 Sentinel 的使命之一。由于调用关系的复杂性,如果调用链路中的某个资源出现了不稳定,可能会导致请求发生堆积,进而导致级联错误。

img

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

熔断降级设计理念

在限制的手段上,Sentinel 和 Hystrix 采取了完全不一样的方法。

Hystrix 通过 线程池隔离 的方式,来对依赖(在 Sentinel 的概念中对应 资源)进行了隔离。这样做的好处是资源和资源之间做到了最彻底的隔离。缺点是除了增加了线程切换的成本(过多的线程池导致线程数目过多),还需要预先给各个资源做线程池大小的分配,并且对于一些使用了 ThreadLocal 的场景来说会有问题(如 Spring 事务)。

Sentinel 对这个问题采取了两种手段:

  • 通过并发线程数进行限制

和资源池隔离的方法不同,Sentinel 通过限制资源并发线程的数量,来减少不稳定资源对其它资源的影响。这样不但没有线程切换的损耗,也不需要您预先分配线程池的大小。当某个资源出现不稳定的情况下,例如响应时间变长,对资源的直接影响就是会造成线程数的逐步堆积。当线程数在特定资源上堆积到一定的数量之后,对该资源的新请求就会被拒绝。堆积的线程完成任务后才开始继续接收请求。

  • 针对慢调用和异常对资源进行降级

除了对并发线程数进行控制以外,Sentinel 还可以根据响应时间和异常等不稳定因素来快速对不稳定的调用进行熔断。当依赖的资源出现响应时间过长后,所有对该资源的访问都会被直接拒绝,直到过了指定的时间窗口之后才重新渐进式地恢复。

系统自适应保护

Sentinel 同时提供系统维度的自适应保护能力。防止雪崩,是系统防护中重要的一环。当系统负载较高的时候,如果还持续让请求进入,可能会导致系统崩溃,无法响应。在集群环境下,网络负载均衡会把本应这台机器承载的流量转发到其它的机器上去。如果这个时候其它的机器也处在一个边缘状态的时候,这个增加的流量就会导致这台机器也崩溃,最后导致整个集群不可用。

针对这个情况,Sentinel 提供了对应的保护机制,让系统的入口流量和系统的负载达到一个平衡,保证系统在能力范围之内处理最多的请求。

Sentinel 是如何工作的

Sentinel 的主要工作机制如下:

  • 对主流框架提供适配或者显示的 API,来定义需要保护的资源,并提供设施对资源进行实时统计和调用链路分析。
  • 根据预设的规则,结合对资源的实时统计信息,对流量进行控制。同时,Sentinel 提供开放的接口,方便您定义及改变规则。
  • Sentinel 提供实时的监控系统,方便您快速了解目前系统的状态。

这篇关于分布式微服务流量控制Sentinel由浅入深的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/779759

相关文章

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

【区块链 + 人才服务】可信教育区块链治理系统 | FISCO BCOS应用案例

伴随着区块链技术的不断完善,其在教育信息化中的应用也在持续发展。利用区块链数据共识、不可篡改的特性, 将与教育相关的数据要素在区块链上进行存证确权,在确保数据可信的前提下,促进教育的公平、透明、开放,为教育教学质量提升赋能,实现教育数据的安全共享、高等教育体系的智慧治理。 可信教育区块链治理系统的顶层治理架构由教育部、高校、企业、学生等多方角色共同参与建设、维护,支撑教育资源共享、教学质量评估、

poj 2135 有流量限制的最小费用最大流

题意: 农场里有n块地,其中约翰的家在1号地,二n号地有个很大的仓库。 农场有M条道路(双向),道路i连接着ai号地和bi号地,长度为ci。 约翰希望按照从家里出发,经过若干块地后到达仓库,然后再返回家中的顺序带朋友参观。 如果要求往返不能经过同一条路两次,求参观路线总长度的最小值。 解析: 如果只考虑去或者回的情况,问题只不过是无向图中两点之间的最短路问题。 但是现在要去要回

【区块链 + 人才服务】区块链集成开发平台 | FISCO BCOS应用案例

随着区块链技术的快速发展,越来越多的企业开始将其应用于实际业务中。然而,区块链技术的专业性使得其集成开发成为一项挑战。针对此,广东中创智慧科技有限公司基于国产开源联盟链 FISCO BCOS 推出了区块链集成开发平台。该平台基于区块链技术,提供一套全面的区块链开发工具和开发环境,支持开发者快速开发和部署区块链应用。此外,该平台还可以提供一套全面的区块链开发教程和文档,帮助开发者快速上手区块链开发。

poj 3422 有流量限制的最小费用流 反用求最大 + 拆点

题意: 给一个n*n(50 * 50) 的数字迷宫,从左上点开始走,走到右下点。 每次只能往右移一格,或者往下移一格。 每个格子,第一次到达时可以获得格子对应的数字作为奖励,再次到达则没有奖励。 问走k次这个迷宫,最大能获得多少奖励。 解析: 拆点,拿样例来说明: 3 2 1 2 3 0 2 1 1 4 2 3*3的数字迷宫,走两次最大能获得多少奖励。 将每个点拆成两个

poj 2195 bfs+有流量限制的最小费用流

题意: 给一张n * m(100 * 100)的图,图中” . " 代表空地, “ M ” 代表人, “ H ” 代表家。 现在,要你安排每个人从他所在的地方移动到家里,每移动一格的消耗是1,求最小的消耗。 人可以移动到家的那一格但是不进去。 解析: 先用bfs搞出每个M与每个H的距离。 然后就是网络流的建图过程了,先抽象出源点s和汇点t。 令源点与每个人相连,容量为1,费用为

poj 3068 有流量限制的最小费用网络流

题意: m条有向边连接了n个仓库,每条边都有一定费用。 将两种危险品从0运到n-1,除了起点和终点外,危险品不能放在一起,也不能走相同的路径。 求最小的费用是多少。 解析: 抽象出一个源点s一个汇点t,源点与0相连,费用为0,容量为2。 汇点与n - 1相连,费用为0,容量为2。 每条边之间也相连,费用为每条边的费用,容量为1。 建图完毕之后,求一条流量为2的最小费用流就行了

Sentinel 高可用流量管理框架

Sentinel 是面向分布式服务架构的高可用流量防护组件,主要以流量为切入点,从限流、流量整形、熔断降级、系统负载保护、热点防护等多个维度来帮助开发者保障微服务的稳定性。 Sentinel 具有以下特性: 丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应

控制反转 的种类

之前对控制反转的定义和解释都不是很清晰。最近翻书发现在《Pro Spring 5》(免费电子版在文章最后)有一段非常不错的解释。记录一下,有道翻译贴出来方便查看。如有请直接跳过中文,看后面的原文。 控制反转的类型 控制反转的类型您可能想知道为什么有两种类型的IoC,以及为什么这些类型被进一步划分为不同的实现。这个问题似乎没有明确的答案;当然,不同的类型提供了一定程度的灵活性,但

基于SpringBoot的宠物服务系统+uniapp小程序+LW参考示例

系列文章目录 1.基于SSM的洗衣房管理系统+原生微信小程序+LW参考示例 2.基于SpringBoot的宠物摄影网站管理系统+LW参考示例 3.基于SpringBoot+Vue的企业人事管理系统+LW参考示例 4.基于SSM的高校实验室管理系统+LW参考示例 5.基于SpringBoot的二手数码回收系统+原生微信小程序+LW参考示例 6.基于SSM的民宿预订管理系统+LW参考示例 7.基于