• Sentinel微服务流量治理组件实战上


    目录

    分布式系统遇到的问题

    解决方案

    Sentinel 是什么?

    Sentinel 工作原理

    Sentinel 功能和设计理念

    流量控制

    熔断降级

    Sentinel工作主流程

    Sentinel快速开始

    Sentinel资源保护的方式

    基于API实现

    @SentinelResource注解实现

    Spring Cloud Alibaba整合Sentinel

    微服务和Sentinel Dashboard通信原理


    分布式系统遇到的问题

            在一个高度服务化的系统中,我们实现的一个业务逻辑通常会依赖多个服务,比如:商品详情展示服务会依赖商品服务, 价格服务, 商品评论服务. 如图所示:

                   

            调用三个依赖服务会共享商品详情服务的线程池. 如果其中的商品评论服务不可用, 就会出现线程池里所有线程都因等待响应而被阻塞, 从而造成服务雪崩. 如图所示:

                       

    服务雪崩效应:因服务提供者的不可用导致服务调用者的不可用,并将不可用逐渐放大的过程,就叫服务雪崩效应。

    导致服务不可用的原因: 程序Bug,大流量请求,硬件故障,缓存击穿。

           在服务提供者不可用的时候,会出现大量重试的情况:用户重试、代码逻辑重试,这些重试最终导致:进一步加大请求流量。所以归根结底导致雪崩效应的最根本原因是:大量请求线程同步等待造成的资源耗尽。当服务调用者使用同步调用时, 会产生大量的等待线程占用系统资源。一旦线程资源被耗尽,服务调用者提供的服务也将处于不可用状态, 于是服务雪崩效应产生了。


    解决方案

    超时机制

           在不做任何处理的情况下,服务提供者不可用会导致消费者请求线程强制等待,而造成系统资源耗尽。加入超时机制,一旦超时,就释放资源。由于释放资源速度较快,一定程度上可以抑制资源耗尽的问题。

    服务限流(资源隔离)

            限制请求核心服务提供者的流量,使大流量拦截在核心服务之外,这样可以更好的保证核心服务提供者不出问题,对于一些出问题的服务可以限制流量访问,只分配固定线程资源访问,这样能使整体的资源不至于被出问题的服务耗尽,进而整个系统雪崩。  

    服务熔断

           远程服务不稳定或网络抖动时暂时关闭,就叫服务熔断。现实世界的断路器大家肯定都很了解,断路器实时监控电路的情况,如果发现电路电流异常,就会跳闸,从而防止电路被烧毁。

           当依赖的服务有大量超时时,在让新的请求去访问根本没有意义,只会无畏的消耗现有资源。比如我们设置了超时时间为1s,如果短时间内有大量请求在1s内都得不到响应,就意味着这个服务出现了异常,此时就没有必要再让其他的请求去访问这个依赖了,这个时候就应该使用断路器避免资源浪费。

    服务降级

           有服务熔断,必然要有服务降级。所谓降级,就是当某个服务熔断之后,服务将不再被调用,此时客户端可以自己准备一个本地的fallback(回退)回调,返回一个缺省值。 例如:(备用接口/缓存/mock数据) 。这样做,虽然服务水平下降,但好歹可用,比直接挂掉要强,当然这也要看适合的业务场景。


    Sentinel 是什么?

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

    Sentinel具有以下特征:

    • 丰富的应用场景: Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、实时熔断下游不可用应用等。
    • 完备的实时监控: Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
    • 广泛的开源生态: Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
    • 完善的 SPI 扩展点: Sentinel 提供简单易用、完善的 SPI 扩展点。您可以通过实现扩展点,快速的定制逻辑。例如定制规则管理、适配数据源等。

    Sentinel 工作原理

    基本概念

    资源

           资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。在接下来的文档中,我们都会用资源来描述代码块。

           只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源名来标示资源。

    规则

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


    Sentinel 功能和设计理念

    流量控制

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

            

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

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

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

    熔断降级

    通过并发线程数进行限制

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

    通过响应时间对资源进行降级

           除了对并发线程数进行控制以外,Sentinel 还可以通过响应时间来快速降级不稳定的资源。当依赖的资源出现响应时间过长后,所有对该资源的访问都会被直接拒绝,直到过了指定的时间窗口之后才重新恢复。


    Sentinel工作主流程

           在 Sentinel 里面,所有的资源都对应一个资源名称(resourceName),每次资源调用都会创建一个 Entry 对象。Entry 可以通过对主流框架的适配自动创建,也可以通过注解的方式或调用 SphU API 显式创建。Entry 创建的时候,同时也会创建一系列功能插槽(slot chain),这些插槽有不同的职责,例如:

    • NodeSelectorSlot 负责收集资源的路径,并将这些资源的调用路径,以树状结构存储起来,用于根据调用路径来限流降级;
    • ClusterBuilderSlot 则用于存储资源的统计信息以及调用者信息,例如该资源的 RT, QPS, thread count 等等,这些信息将用作为多维度限流,降级的依据;
    • StatisticSlot 则用于记录、统计不同纬度的 runtime 指标监控信息;
    • FlowSlot 则用于根据预设的限流规则以及前面 slot 统计的状态,来进行流量控制;
    • AuthoritySlot 则根据配置的黑白名单和调用来源信息,来做黑白名单控制;
    • DegradeSlot 则通过统计信息以及预设的规则,来做熔断降级;
    • SystemSlot 则通过系统的状态,例如 load1 等,来控制总的入口流量;

            Sentinel 将 ProcessorSlot 作为 SPI 接口进行扩展(1.7.2 版本以前 SlotChainBuilder 作为 SPI),使得 Slot Chain 具备了扩展的能力。可以自行加入自定义的 slot 并编排 slot 间的顺序,从而可以给 Sentinel 添加自定义的功能。


    Sentinel快速开始

    Sentinel进行资源保护的几个步骤:

    1. 定义资源
    2. 定义规则
    3. 检验规则是否生效
    1. Entry entry = null;
    2. // 务必保证 finally 会被执行
    3. try {
    4. // 资源名可使用任意有业务语义的字符串 开启资源的保护
    5. entry = SphU.entry("自定义资源名");
    6. // 被保护的业务逻辑 method
    7. // do something...
    8. } catch (BlockException ex) {
    9. // 资源访问阻止,被限流或被降级 Sentinel定义异常 流控规则,降级规则,热点参数规则。。。。 服务降级(降级规则)
    10. // 进行相应的处理操作
    11. } catch (Throwable ex) {
    12. // 若需要配置降级规则,需要通过这种方式记录业务异常 RuntimeException 服务降级 mock feign:fallback
    13. Tracer.traceEntry(ex, entry);
    14. } finally {
    15. // 务必保证 exit,务必保证每个 entry 与 exit 配对
    16. if (entry != null) {
    17. entry.exit();
    18. }

    Sentinel资源保护的方式

    基于API实现

    引入依赖

    1. <groupId>com.alibaba.cspgroupId>
    2. <artifactId>sentinel-coreartifactId>
    3. <version>1.8.4version>

    编写测试逻辑

    1. @RestController
    2. @Slf4j
    3. public class HelloController {
    4. private static final String RESOURCE_NAME = "HelloWorld";
    5. @RequestMapping(value = "/hello")
    6. public String hello() {
    7. try (Entry entry = SphU.entry(RESOURCE_NAME)) {
    8. // 被保护的逻辑
    9. log.info("hello world");
    10. return "hello world";
    11. } catch (BlockException ex) {
    12. // 处理被流控的逻辑
    13. log.info("blocked!");
    14. return "被流控了";
    15. }
    16. }
    17. /**
    18. * 定义流控规则
    19. */
    20. @PostConstruct
    21. private static void initFlowRules(){
    22. List rules = new ArrayList<>();
    23. FlowRule rule = new FlowRule();
    24. //设置受保护的资源
    25. rule.setResource(RESOURCE_NAME);
    26. // 设置流控规则 QPS
    27. rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
    28. // 设置受保护的资源阈值
    29. // Set limit QPS to 20.
    30. rule.setCount(1);
    31. rules.add(rule);
    32. // 加载配置好的规则
    33. FlowRuleManager.loadRules(rules);
    34. }
    35. }

    测试效果:http://localhost:8800/hello

                         

    缺点:

    • 业务侵入性很强,需要在controller中写入非业务代码.
    • 配置不灵活 若需要添加新的受保护资源 需要手动添加 init方法来添加流控规则

    @SentinelResource注解实现

    @SentinelResource 注解用来标识资源是否被限流、降级。

    • blockHandler: 定义当资源内部发生了BlockException应该进入的方法(捕获的是Sentinel定义的异常)。
    • fallback: 定义的是资源内部发生了Throwable应该进入的方法。
    • exceptionsToIgnore:配置fallback可以忽略的异常。

    1 引入依赖

    1. <groupId>com.alibaba.cspgroupId>
    2. <artifactId>sentinel-annotation-aspectjartifactId>
    3. <version>1.8.4version>

    2 配置切面支持

    1. @Configuration
    2. public class SentinelAspectConfiguration {
    3. @Bean
    4. public SentinelResourceAspect sentinelResourceAspect() {
    5. return new SentinelResourceAspect();
    6. }
    7. }

    3 UserController中编写测试逻辑,添加@SentinelResource,并配置blockHandler和fallback

    1. @SentinelResource(value = "hello world",
    2. blockHandler = "handleException",
    3. fallback = "fallbackException")
    4. @RequestMapping("/hello2")
    5. public String hello2() {
    6. //int i = 1 / 0;
    7. return "helloworld";
    8. }
    9. public String handleException(BlockException ex){
    10. return "被流控了";
    11. }
    12. public String fallbackException(Throwable t){
    13. return "被异常降级了";
    14. }
    15. @RequestMapping(value = "/findOrderByUserId/{id}")
    16. @SentinelResource(value = "findOrderByUserId",
    17. fallback = "fallback",fallbackClass = ExceptionUtil.class,
    18. blockHandler = "handleException",blockHandlerClass = ExceptionUtil.class
    19. )
    20. public R findOrderByUserId(@PathVariable("id") Integer id) {
    21. //ribbon实现
    22. String url = "http://mall-order/order/findOrderByUserId/"+id;
    23. R result = restTemplate.getForObject(url,R.class);
    24. if(id==4){
    25. throw new IllegalArgumentException("非法参数异常");
    26. }
    27. return result;
    28. }

    4 流控规则设置可以通过Sentinel dashboard配置

    客户端需要引入 Transport 模块来与 Sentinel 控制台进行通信。

    1. <groupId>com.alibaba.cspgroupId>
    2. <artifactId>sentinel-transport-simple-httpartifactId>
    3. <version>1.8.4version>

    5 启动 Sentinel 控制台

    下载控制台 jar 包并在本地启动:可以参见 此处文档

    1. #启动控制台命令
    2. java -jar sentinel-dashboard-1.8.4.jar

    访问http://localhost:8080/#/login ,默认用户名密码: sentinel/sentinel

                    


    Spring Cloud Alibaba整合Sentinel

    1.引入依赖

    1. <groupId>com.alibaba.cloudgroupId>
    2. <artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
    3. <dependency>
    4. <groupId>org.springframework.bootgroupId>
    5. <artifactId>spring-boot-starter-actuatorartifactId>
    6. dependency>

    2.添加yml配置,为微服务设置sentinel控制台地址

           添加Sentinel后,需要暴露/actuator/sentinel端点,而Springboot默认是没有暴露该端点的,所以需要设置,测试http://localhost:8800/actuator/sentinel

    1. server:
    2. port: 8800
    3. spring:
    4. application:
    5. name: mall-user-sentinel-demo
    6. cloud:
    7. nacos:
    8. discovery:
    9. server-addr: 127.0.0.1:8848
    10. sentinel:
    11. transport:
    12. # 添加sentinel的控制台地址
    13. dashboard: 127.0.0.1:8080
    14. # 指定应用与Sentinel控制台交互的端口,应用本地会起一个该端口占用的HttpServer
    15. # port: 8719
    16. #暴露actuator端点
    17. management:
    18. endpoints:
    19. web:
    20. exposure:
    21. include: '*'

    3.在sentinel控制台中设置流控规则

    • 资源名: 接口的API
    • 针对来源: 默认是default,当多个微服务都调用这个资源时,可以配置微服务名来对指定的微服务设置阈值
    • 阈值类型: 分为QPS和线程数 假设阈值为10
    • QPS类型: 只得是每秒访问接口的次数>10就进行限流
    • 线程数: 为接受请求该资源分配的线程数>10就进行限流

    测试: 因为QPS是1,所以1秒内多次访问会出现如下情形:

            

              


    微服务和Sentinel Dashboard通信原理

    Sentinel控制台与微服务端之间,实现了一套服务发现机制,集成了Sentinel的微服务都会将元数据传递给Sentinel控制台,架构图如下所示:

      

    测试:http://localhost:8719/getRules?type=flow 获取微服务流控规则信息。

    注意:随着微服务增加,端口是递增的,具体参考Sentinel Dashboard显示的微服务对应端口。

  • 相关阅读:
    【debian系统arm架构安装docker】且换源后依旧不行就离线导入镜像
    基于jsp+mysql+SSM学生兼职网站-计算机毕业设计
    计算机网络-传输层:TCP协议
    一键部署区块链背后的秘密(下)
    git安装与使用4.3
    Part 5:Pandas 数据统计函数【汇总类统计、唯一去重和按值计数、相关系数和协方差】
    JS 保留两位小数,不足用0补齐;js 实现对数字保留两位小数时 不足两位 自动补0;JavaScript保留两位小数,自动补零
    golang并发编程基础
    AI和人类,谁的钓鱼邮件更胜一筹?
    从X Fold+折叠屏手机再议vivo的用户导向创新思维
  • 原文地址:https://blog.csdn.net/m0_61853556/article/details/136271707