• SpringCloud Alibaba系列 Sentinel(三)


    目录

    高并发下的微服务容错方案?

    限流、熔断、降级

    1:限流

    2:熔断

    3:降级

    分布式系统的流量防卫兵-Sentinel

    什么是 Sentinel ?

    Sentinel 的主要概念

    资源

    规则

    上手 Sentinel

    部署Sentinel控制台

    从 Github 上下载 Sentinel

    启动 Sentinel 服务

    SpringCloud Alibaba 整合 Sentinel

    配置流控规则

    流控控制面板介绍

    流控效果介绍

    快速失败

    Warm Up

    排队等待

    熔断降级介绍

    慢调用比例

    异常比例

    异常数

    权限介绍

    自定义流控熔断返回的JSON信息

    Feign 整合 Sentinel 返回兜底数据


    高并发下的微服务容错方案?

    1:限流

    在高并发系统中一定要用,高并发的所有请求进来,不是让每个请求都打到后台集群的,后台集群有它的消费能力,应该在它消费能力之内放行请求,这个就是限流

    比如服务集群的处理能力是每秒1w,那么从网关处放过来的请求就是1w,超过1w的请求将直接丢弃,返回 “服务繁忙,稍后重试” 等字样。

    2:熔断

    一个服务常常会调用别的模块,可能是另外的一个远程服务、数据库,或者第三方 API 等。例如,支付的时候,可能需要远程调用银联提供的 API;查询某个商品的价格,可能需要进行数据库查询。然而,这个被依赖服务的稳定性是不能保证的。如果依赖的服务出现了不稳定的情况,请求的响应时间变长,那么调用服务的方法的响应时间也会变长,线程会产生堆积,最终可能耗尽业务自身的线程池,服务本身也变得不可用。

    现代微服务架构都是分布式的,由非常多的服务组成。不同服务之间相互调用,组成复杂的调用链路。以上的问题在链路调用中会产生放大的效果。复杂链路上的某一环不稳定,就可能会层层级联,最终导致整个链路都不可用。因此我们需要对不稳定的弱依赖服务调用进行熔断降级,暂时切断不稳定调用,避免局部不稳定因素导致整体的雪崩。熔断降级作为保护自身的手段.

    熔断就是在规定的时间内,下游服务还没有返回数据,上游服务在指定的时间内比如10秒内不调用下游服务,会在10秒后重新尝试调用下游服务,看下游服务是否正常响应了

    3:降级

    我们知道在一套完整的业务流程中是有主要的核心业务,和非核心业务的,比如电商系统中的商品、订单、支付是核心业务。推荐、优惠、附加业务(如小游戏)等是非核心业务。当服务流量很大的时候,可以降低非核心业务的可用性或者直接停掉。保证核心业务的可用。


    分布式系统的流量防卫兵-Sentinel

    官网:https://sentinelguard.io/zh-cn

    github:https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel

    什么是 Sentinel

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

    Sentinel 具有以下特征:

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

    Sentinel 的主要概念

    • 资源

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

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

    • 规则

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


    上手 Sentinel

    • 部署Sentinel控制台

    • 从 Github 上下载 Sentinel

    https://github.com/alibaba/Sentinel

    • 启动 Sentinel 服务

    注意:启动 Sentinel 控制台需要 JDK 版本为 1.8 及以上版本

    注意:Sentinel 控制台目前仅支持单机部署。

    使用如下命令启动控制台:

    java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar

    其中 -Dserver.port=8080 用于指定 Sentinel 控制台端口为 8080

    访问地址:http://ip:8080

    默认账号密码:sentinel/sentinel


    SpringCloud Alibaba 整合 Sentinel

    maven版本管理如下

    1. <properties>
    2. <java.version>17java.version>
    3. <maven.compiler.source>17maven.compiler.source>
    4. <maven.compiler.target>17maven.compiler.target>
    5. <maven.compiler.compilerVersion>17maven.compiler.compilerVersion>
    6. <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
    7. <project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
    8. <spring.boot.version>2.7.4spring.boot.version>
    9. <spring.cloud.version>2021.0.4spring.cloud.version>
    10. <spring.cloud.alibaba.version>2021.0.4.0spring.cloud.alibaba.version>
    11. properties>
    12. <dependencyManagement>
    13. <dependencies>
    14. <dependency>
    15. <groupId>org.springframework.bootgroupId>
    16. <artifactId>spring-boot-dependenciesartifactId>
    17. <version>${spring.boot.version}version>
    18. <type>pomtype>
    19. <scope>importscope>
    20. dependency>
    21. <dependency>
    22. <groupId>org.springframework.cloudgroupId>
    23. <artifactId>spring-cloud-dependenciesartifactId>
    24. <version>${spring.cloud.version}version>
    25. <type>pomtype>
    26. <scope>importscope>
    27. dependency>
    28. <dependency>
    29. <groupId>com.alibaba.cloudgroupId>
    30. <artifactId>spring-cloud-alibaba-dependenciesartifactId>
    31. <version>${spring.cloud.alibaba.version}version>
    32. <type>pomtype>
    33. <scope>importscope>
    34. dependency>
    35. dependencies>
    36. dependencyManagement>

    子服务 pom 中添加依赖

    1. <dependency>
    2. <groupId>com.alibaba.cloudgroupId>
    3. <artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
    4. dependency>

    application.yml 文件配置 sentinel

    1. spring:
    2. cloud:
    3. sentinel:
    4. transport:
    5. port: 8719
    6. # sentinel 控制台地址
    7. dashboard: localhost:8080

    这里的 spring.cloud.sentinel.transport.port 端口配置会在应用对应的机器上启动一个 Http Server,该 Server 会与 Sentinel 控制台做交互。比如 Sentinel 控制台添加了一个限流规则,会把规则数据 push 给这个 Http Server 接收,Http Server 再将规则注册到 Sentinel 中。这个端口不能被占用,多个微服务配置不同的port。若被占用,则端口自动+1

    确保客户端有访问量,Sentinel 会在客户端首次调用的时候进行初始化,开始向控制台发送心跳包。微服务接口被请求后,就会在控制台显示出微服务


    配置流控规则

    注意:这里的配置规则是通过 调用 sentinel 提供的 HTTP API 接口来改变的,这也意味着这些规则仅在内存态生效,应用重启之后,该规则会丢失。关于持久化规则后面会讲到,请查看官网:在生产环境中使用 Sentinel · alibaba/Sentinel Wiki · GitHub

    • 测试一下流控效果

    正常的请求拿到的数据如下

     当 一秒 时间里 请求次数超过 2 次,返回流控限制信息


    流控控制面板介绍

    流量控制 · alibaba/Sentinel Wiki · GitHub

    资源名:默认是请求路径,可自定义,要保证唯一

    针对来源:对哪个微服务进行限流,默认是不区分来源,全部限流,这个是针对 区分上游服务进行限流, 比如 视频服务 被 订单服务、用户服务调用,就可以针对订单服务来源进行限流,对用户服务来源不限流

    阈值类型:

    • 流量控制
      • 原理是监控应用流量的 QPS 或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。
    • 两种规则
      1. 基于统计QPS的流量控制:当 QPS 超过某个阈值的时候,则采取措施进行流量控制
      2. 基于统计并发线程数的流量控制:并发数控制用于保护业务线程池不被慢调用耗尽。Sentinel 并发控制不负责创建和管理线程池,而是简单统计当前请求上下文的线程数目(正在执行的调用数目)如果超出阈值,新的请求会被立即拒绝,效果类似于信号量隔离。

    流控效果介绍

    快速失败

    默认的流量控制方式,当QPS超过任意规则的阈值后,新的请求就会被立即拒绝

    Warm Up

    即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。

    排队等待

    严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法,主要用于处理间隔性突发的流量,如消息队列,想象一下这样的场景,在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求。

    • 匀速排队等待策略是 Leaky Bucket 算法结合虚拟队列等待机制实现的。
    • 注意:匀速排队模式暂时不支持 QPS > 1000 的场景,不能让用户无限的排对,不然等到啥时候去了?

    熔断降级介绍

    慢调用比例

    选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。

    示例:

    同下面的异常比例、异常数类似,就不贴示例了

    异常比例

    当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。 

    异常数

    当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。


    权限介绍

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


    自定义流控熔断返回的JSON信息

    1. import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
    2. import com.alibaba.csp.sentinel.slots.block.BlockException;
    3. import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
    4. import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
    5. import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
    6. import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
    7. import com.alibaba.csp.sentinel.slots.system.SystemBlockException;
    8. import com.alibaba.fastjson.JSON;
    9. import org.springframework.stereotype.Component;
    10. import javax.servlet.http.HttpServletRequest;
    11. import javax.servlet.http.HttpServletResponse;
    12. import java.util.HashMap;
    13. import java.util.Map;
    14. @Component
    15. public class CustomUrlBlockHandler implements BlockExceptionHandler {
    16. @Override
    17. public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
    18. Map backMap = new HashMap<>(2);
    19. if (e instanceof FlowException) {
    20. backMap.put("code", -1);
    21. backMap.put("msg", "限流-异常啦");
    22. } else if (e instanceof DegradeException) {
    23. backMap.put("code", -2);
    24. backMap.put("msg", "降级-异常啦");
    25. } else if (e instanceof ParamFlowException) {
    26. backMap.put("code", -3);
    27. backMap.put("msg", "热点-异常啦");
    28. } else if (e instanceof SystemBlockException) {
    29. backMap.put("code", -4);
    30. backMap.put("msg", "系统规则-异常啦");
    31. } else if (e instanceof AuthorityException) {
    32. backMap.put("code", -5);
    33. backMap.put("msg", "认证-异常啦");
    34. }
    35. response.setHeader("Access-Control-Allow-Origin", "*");
    36. response.setHeader("Cache-Control", "no-cache");
    37. response.setStatus(200);
    38. response.setCharacterEncoding("UTF-8");
    39. response.setContentType("application/json");
    40. response.getWriter().println(JSON.toJSONString(backMap));
    41. response.getWriter().flush();
    42. }
    43. }


    Feign 整合 Sentinel 返回兜底数据

    子服务 pom 中添加依赖

    1. <dependency>
    2. <groupId>org.springframework.cloudgroupId>
    3. <artifactId>spring-cloud-starter-openfeignartifactId>
    4. dependency>
    5. <dependency>
    6. <groupId>com.alibaba.cloudgroupId>
    7. <artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
    8. dependency>

    application.yml 文件配置 打开Sentinel对Feign的支持

    1. feign:
    2. sentinel:
    3. enabled: true

    当使用 feigin 调用下游服务的时候,下游服务异常,可以使用 @FeignClient 注解的 fallback 属性指定返回兜底数据

    1. // fallback:指定兜底数据是哪个实现类(兜底实现类,要实现本接口类)
    2. @FeignClient(name = "order-service", fallback = OrderServiceFallback.class)
    3. public interface OrderService {
    4. @GetMapping("/order/one")
    5. OrderDO getOne(@RequestParam("orderId") Long orderId);
    6. }
    1. @Service
    2. public class OrderServiceFallback implements OrderService {
    3. @Override
    4. public OrderDO getOne(Long orderId) {
    5. // 返回兜底数据
    6. OrderDO orderDO = new OrderDO();
    7. orderDO.setId(1L);
    8. return orderDO;
    9. }
    10. }

    返回了兜底数据

  • 相关阅读:
    推荐系统-模型:Feed 流推荐
    Mac 使用 crontab + typora 自动保存笔记到 git
    【计算机网络】网络层IP协议
    【心电信号】Simulink胎儿心电信号提取【含Matlab源码 1550期】
    antd4 Form表单验证的错误信息用Tooltip展示
    LeetCode链表练习(上)
    vue3获取元素并修改元素样式
    47、Docker 安装 ElasticSearch、Kibana、IK分词器
    vue学习之属性绑定
    配置dns服务的正反向解析
  • 原文地址:https://blog.csdn.net/a1053765496/article/details/127602500