1 简介

Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。依托 Spring Cloud Alibaba,您只需要添加一些注解和少量配置,就可以将 Spring Cloud 应用接入阿里分布式应用解决方案,通过阿里中间件来迅速搭建分布式应用系统。

wiki

在Common项目仲裁Alibaba版本
导入时要注意版本依赖关系
image.png
Spring.IO SpringCloud官网
Spring-Cloud Alibaba

  1. <dependencyManagement>
  2. <dependencies>
  3. <dependency>
  4. <groupId>com.alibaba.cloud</groupId>
  5. <artifactId>spring-cloud-alibaba-dependencies</artifactId>
  6. <version>2.2.0.RELEASE</version>
  7. <type>pom</type>
  8. <scope>import</scope>
  9. </dependency>
  10. </dependencies>
  11. </dependencyManagement>

拓展:dependencyManagement和dependencies的区别?

dependencyManagement是依赖管理,相当于以后再dependencies里引spring cloud alibaba就不用写版本号, 全用dependencyManagement进行管理。注意他和普通依赖的区别,他只是备注一下,并没有在子项目里面实际加入了依赖。
具体的参考链接:cnblogs参考

拓展:依赖作用域(依赖作用域用于限制依赖项的可传递性,并确定依赖项何时包含在类路径中)

compile:默认值,适用于所有阶段(开发、测试、部署、运行),本jar会一直存在所有阶段。
provided:只在开发、测试阶段使用,目的是不让Servlet容器和你本地仓库的jar包冲突。如servlet.jar。
runtime:只在运行时使用,如JDBC驱动,适用运行和测试阶段。
test:只在测试时使用,用于编译和运行测试代码。不会随项目发布。
system:类似provided,需要显式提供包含依赖的jar,Maven不会在Repository中查找它。
import:导入的范围,只使用在dependencyManagement中,表示从其它的pom中导入dependecy的配置。

2 Nacos服务注册与配置中心

概述

  1. 简介

Nacos是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。Nacos的全名为:Dynamic Naming Configuration Service。
Nacos就是注册中心+配置中心的组合,等价于:eureka+config+Bus。

  1. Nacos集成了Ribbon,所以其天然就适合做负载均衡。

我们可以通过SpringTemplate +@LoadBalanced+ Nacos(其通过内置的Ribbion)来实现在消费端调用服务端的时候负载均衡的效果。
逻辑:Nacos整好了Ribbion->有了Ribbion就可以使用RestTemplate->有了RestTemplate+@LoadBalanced就可以使用负载均衡。(注:@LoadBalanced注解负责具体要用哪种算法去实现负载均衡,轮询还是权重?)

//1.O 配置
server:
  port: 83

spring:
  application:
    name: cloud-nacos-order
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
//消费者将要去访问的微服务名称
server-url:
  nacos-user-service: http://nacos-payment-provider

//2.0 往Spring容器注入RestTemplate
@Configuration
public class ApplicationContextConfig {
    @Bean
    @LoadBalanced  //负载均衡:轮询
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}
//3.0 实际使用:通过RestTemplate+Nacos,访问其他节点,有负载均衡效果,这个负载均衡是通过Nacos内置的Ribbion+@LoadBalanced来实现的。
@RestController
public class OrderNacosController {
    @Resource
    private RestTemplate restTemplate;

    @Value("${server-url.nacos-user-service}")
    private String url;


    @GetMapping("/order/getPayment/{id}")
    public String getPaymentInfo(@PathVariable("id") Long id) {
        return restTemplate.getForObject(url+"/payment/getPayment/"+id,String.class);
    }
}

下载NacosServer

  1. 下载地址

Github-Spring Cloud Alibaba - Nacos -Releases

  1. 启动nacos

Windows下进入startup.cmd。双击启动服务。
image.png

  1. 测试访问

地址:http://192.168.0.110:8848/nacos/index.html#/login
账号密码:nacos/nacos

  1. 问题排查

如果启动的时候出现了如下错误提示:org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat。
则将startup.cmd的第28行,将nacos默认的集群模式改成单机模式就好了。
set MODE="standalone"
image.png

用于Discovery注册中心

Nacos-Discovery服务发现是微服务架构体系中最关键的组件之一。如果尝试着用手动的方式来给每一个客户端来配置所有服务提供者的服务列表是一件非常困难的事,而且也不利于 服务的动态扩缩容。Nacos Discovery Starter 可以帮助您将服务自动注册到 Nacos 服务端并且能够动态感知和刷新某个服务实例的服务列表。除此之外,Nacos Discovery Starter 也将服务实例自身的一些元数据信息-例如 host,port,健康检查URL,主页等-注册到 Nacos中。
image.png
简易案例接入入门:Github-Spring Cloud Alibaba - Nacos
官方详细文档:nacos - 官网

具体使用

  1. 将Nacos discovery 加入到Common项目里

    <dependency>
     <groupId>com.alibaba.cloud</groupId>
     <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    
  2. 在具体项目进行配置

引入common公共项目
在application.yml配置当前项目的服务器地址、端口和名称

spring:
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
  application:
    name: gulimall-product-nacos
server:
  port: 8003

在具体项目的启动类上标注@EnableDiscoveryClient开启服务发现功能

@EnableDiscoveryClient
@MapperScan("com.efly.gulimall.product.dao")
@SpringBootApplication
public class GulimallProductApplication {
    public static void main(String[] args) {
        SpringApplication.run(GulimallProductApplication.class, args);
    }
}
  1. 测试服务是否在注册中心注册成功

地址:http://192.168.0.110:8848/nacos/index.html#/login
账号密码:nacos/nacos
image.png

用于Config配置中心

简介
我们还可以用nacos作为配置中心。配置中心的意思是不在application.properties等文件中配置了,而是放到nacos配置中心公用,这样无需每台机器都改。
快速入门wiki:Github -Nacos-快速入门wiki

具体使用

  1. Common项目统一进行管控

    <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    </dependency>
    
  2. 在具体项目进行配置

在coupons项目中创建/src/main/resources/bootstrap.properties ,这个文件是springboot里规定的,他优先级别高于application.properties

# 改名字,对应nacos里的配置文件名
spring.application.name=gulimall-coupon
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
  1. 在Nacos中添加配置文件

详细的配置文件使用规则请参考下一小节,此处为简单的配置测试:
关于文件名,我们看控制台提示什么,提示缺少什么文件就补齐什么文件(默认的就是项目微服务名.properties)
image.png
名字和类名保持一致
image.png

命名规则参考 image.png

  1. 在项目里面使用Nacos-Config配置项

拓展:关于在SpringBoot项目里面使用配置项的方法。着重注意的一点:@RefreshScope注解可以达到在生成环境下,更改了nacos-config文件,不需要重启微服务配置即会自动更新。

方法一:使用@Value属性自动注入 使用@Value(“${}”) 得到JAVA属性文件(.properties)、YAML文件、环境变量(如JAVA_HOME)、命令行参数(启动时输入)的值

例子:
#1.0 在application.properties中
student.username=你好
student.age=3

#2.0 在控制器上
@RestController
@RequestMapping("coupon/nacos")
@RefreshScope
public class CouponTestController {
    @Value("${student.username}")
    private String name;

    @Value("${student.age}")
    private Integer age;

    @RequestMapping("/test")
    public String Test() {
        return name + age;
    }
}

#3.0 最终输出的值
http://localhost:8000/coupon/nacos/test
你好3

方法二:使用@EnableConfigurationProperties+@ConfigurationProperties @EnableConfigurationProperties注解的作用是:使使用 @ConfigurationProperties 注解的类生效。如果一个配置类只配置了@ConfigurationProperties注解,而没有使用@Component,那么在IOC容器中是获取不到properties 配置文件转化的bean。说白了 @EnableConfigurationProperties 相当于把使用 @ConfigurationProperties 的类进行了一次注入。 @ConfigurationProperties注解可以把properties文件转化为bean,然后使用@Component或@EnableConfigurationProperties注解把该bean注入到IOC容器中。 @Configuration:从Spring3.0起,@Configuration用于定义配置类,替代XML类+生成Bean对象(该注解是@Bean注解的前提)。注意:@Configuration配置类本身其实就一个@Component

例子:
#1.0 配置文件(classpath:bootstrap.properties)
student.username=你好
student.age=3344

#2.0 配置类(将配置信息映射到CouponTestModel)
@Data
@ConfigurationProperties(prefix="student")
@PropertySource(value = {"classpath:bootstrap.properties"}, encoding = "UTF-8")
public class CouponTestModel {
    private String username;
    private Integer age;
}

#3.0 将CouponTestModel注入到SpringBoot
@Configuration
@EnableConfigurationProperties(CouponTestModel.class)
public class CouponConfig {
}

#4.0 使用
@RestController
@RequestMapping("coupon/nacos")
public class CouponTestController {

    @Autowired
    private CouponTestModel testModel;

    @RequestMapping("/test")
    public String Test() {
        return testModel.getUsername() + "//" + testModel.getAge();
    }
}

访问:http://localhost:8000/coupon/nacos/test
打印输出效果:你好//3344

配置中心高级用法(推荐生产使用)

  1. 默认情况:Namespace=public,Group=DEFAULT_GROUP,Cluster是DEFAULT。
  2. Namespace主要用来实现隔离,默认的命名空间是public:比方说我们现在有三个环境:开发、测试、生产,我们就可以创建三个Namespace,不同的Namespace之间是隔离的。
  3. Group可以把不同的微服务划分到同一个分组里面去,默认是DEFAULT_GROUP,如消息通知组、后台管理系统组、APP组。
  4. Service就是微服务,一个Service可以包含多个Cluster (集群),默认Cluster是DEFAULT,Cluster是对指定微服务的一个虚拟划分。比方说为了容灾,将Service微服务分别部署在了杭州机房和广州机房,这时就可以给杭州机房的Service微服务起一个Cluster集群名称(HZ) ,给广州机房的Service微服务起一个Cluster集群名称(GZ),还可以尽量让同一个机房的微服务互相调用,以提升性能。最后是Instance,就是微服务的实例。

image.png

  1. 每个微服务创建自己的命名空间

image.png

  1. 每个命名空间下再使用分组来区分具体环境(dev/test/prod)

image.png

  1. 在项目里面配置使用哪个配置文件
    #1.0 确定使用哪个命名空间
    spring.cloud.nacos.config.namespace=88bc74ae-f398-4edb-b321-f2207a50f705
    #2.0 确定使用哪个分组
    spring.cloud.nacos.config.group=dev
    

    Nacos集群

    默认Nacos使用内置的嵌入式数据库实现数据的存储。所以如果启动多个默认配置下的Nacos节点,数据存储是存在一致性问题的。为了解决这个问题,Nacos采用了集中式存储的方式来支持集群化部署,目前只支持MySQL的存储。
    Nacos支持三种部署模式
  • 单机模式:用于测试和单机试用。
  • 集群模式:用于生产环境,确保高可用。
    • 可参考生产方案:1个nginx、3个Nacos Server、1台mysql。Gateway绑定的是Nginx的地址,由Nginx进行负载均衡到3台Nacos,3台Nacos的配置持久化则中心化到MySQL。
  • 多集群模式:用于多数据中心场景。

image.png

3 Sentinel熔断与断流

功能分类:分为调用者和被调用者两个方面。

概览与使用

  1. 概览

Sentinel能解决的问题:服务雪崩、服务降级、服务熔断、服务限流。同时,为了减少开发的复杂程度,Sentinel对大部分的主流框架,例如 Web Servlet、Dubbo、Spring Cloud、gRPC、Spring WebFlux、Reactor 等都做了适配。只需要引入对应的依赖即可方便地整合 Sentinel。
参考文档概览:Alibaba-Sentinel-新手指南

Sentinel 可以简单的分为 Sentinel 核心库和 Dashboard。核心库不依赖 Dashboard,但是结合 Dashboard 可以取得最好的效果。 安装DashBoard控制台 下载地址:Alibaba-Sentinel-Releases 下载指定版本的Jar包,并且使用java命令运行:java -jar D:\0000Learning\Quick\Sentinel.jar —server.port=8999 以8999端口运行:http://localhost:8999,账号密码分别为:sentinel/sentinel 秒杀配置1000/S,但是如果有人使用Jmeter模拟攻击,1秒钟发起2000次请求,此时Sentinel配置的是1000次/秒,则其他浏览器就不能访问服务器了。nginx+ip做额外的观察 note:如果启动失败,可以查看下是否是Java版本是否匹配(Sentinel1.8.1版本适配Java1.8是正常的,适配Java17即不正常)

分为两步骤:定义资源,定义规则。

  1. 配置的持久化

核心:将配置信息保存在nacos配置中心,在 sentinel 启动的时候,去 nacos上读取相关规则配置信息。就算以后在 sentinel 上面修改了,重启应用以后也是无效的。
参考链接:https://blog.csdn.net/hancoder/article/details/109063671

  1. 资源:@SentinelResource

资源的概念:Sentinel的资源可以是任何东西:服务,服务里的方法,甚至是一段代码。使用 Sentinel 来进行资源保护,主要分为几个步骤:定义资源、定义规则、检验规则是否生效。
先把可能需要保护的资源定义好(埋点),之后再配置规则。也可以理解为,只要有了资源,我们就可以在任何时候灵活地定义各种流量控制规则。在编码的时候,只需要考虑这个代码是否需要保护,如果需要保护,就将之定义为一个资源。对于主流的框架,Sentinel 会提供适配,只需要按照适配中的说明配置,Sentinel 就会默认定义提供的服务,方法等为资源。
资源的使用,参考文档:Alibaba-Sentinel-自定义资源在代码中使用注解定义资源
默认的资源都是被扫描到的接口方法等资源内容。

核心配置属性 若blockHandler和fallback都进行了配置,则被限流降级而抛出BlockException时只会进入blockHandler处理逻辑。

  • blockHandler / blockHandlerClass:负责处理配置方面违规

如接口配置了QPS为1,则访问超过了1QPS则会熔断方法然后进入blockHandler指定的方法里面。

  - blockHandler 对应处理 BlockException 的函数名称,可选项。
  - blockHandler 函数访问范围需要是 public,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException。
  - blockHandler 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 blockHandlerClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
  • fallback / fallbackClass:可以处理Java运行时抛出的异常

fallback 函数名称,可选项,用于在抛出异常的时候提供 fallback 处理逻辑。fallback 函数可以针对所有类型的异常(除了exceptionsToIgnore里面排除掉的异常类型)进行处
理。fallback 函数签名和位置要求:

  - 返回值类型必须与原函数返回值类型一致;
  - 方法参数列表需要和原函数一致,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。
  - fallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。

代码示例

/*特别地,若blockHandler和fallback都进行了配置,则被限流降级而抛出 BlockException 时只会进入 blockHandler 处理逻辑。
若未配置 blockHandler、fallback 和 defaultFallback,则被限流降级时会将 BlockException 直接抛出(若方法本身未定义 throws BlockException 则会被 JVM 包装一层 UndeclaredThrowableException)*/

@SentinelResource(value = "getSession", blockHandler = "exceptionHandler")
@RequestMapping("/getSession")
public String getSession(HttpSession session, HttpServletRequest request) throws InterruptedException {
    String couponsByMember1 = couponFeign.getCouponsByMember();
    System.out.println(couponsByMember1);
    return couponsByMember1 + "success";
}
//1.8版本之后的降级方法(参数最后多一个 BlockException,其余与原函数一致)
public String exceptionHandler(HttpSession session, HttpServletRequest request, BlockException ex) {
    return "服务不可用";
}

测试:在DashBoard配置指定接口的流控
image.png
image.png
效果
image.png
其他方式定义资源:包括抛出异常的方式定义资源、异步调用支持的方式,详见下方文档:其他方式定义资源

  1. SpringBoot项目通用整合

    通用配置

### 1.0 pom文件添加Sentinel启动器 ###
<!--基础组件-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    <version>${spring-cloud-alibaba.version}</version>
</dependency>
<!--流量统计-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
    <version>${spring-cloud-alibaba.version}</version>
</dependency>
<!-- sentinel-core1.8开始用来做适配的 -->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-spring-webmvc-adapter</artifactId>
    <version>1.8.1</version>
</dependency>
<!-- 用于熔断 -->
<dependency>
       <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    <version>${spring-cloud-alibaba.version}</version>
</dependency>
<!-- 用于网关的启动器 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId
    <version>2.2.6.RELEASE</version>
</dependency>

### 2.0 ymal文件配置上DashBoard(任意微服务如果需要用到Sentinel都需要做如下相对应的配置) ###
# sentinel控制台地址
spring.cloud.sentinel.transport.dashboard=localhost:8333
#当前微服务和Dashboard控制台的通信端口
spring.cloud.sentinel.transport.port=8719
# 暴露所有监控端点,使得sentinel可以实时监控
management.endpoints.web.exposure.include=*
###或者在ymal下的配置###
management:
  endpoints:
    web:
      exposure:
        include: "*"
# 配置文件打开Sentinel对Feign的支持
feign.sentinel.enabled=true

全局限流提示

package com.efly.gulimall.product.config;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.fastjson.JSON;
import com.efly.gulimall.product.helper.base.AjaxResult;
import org.springframework.context.annotation.Configuration;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Configuration
public class MySentinalConfiguration implements BlockExceptionHandler {
    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws IOException {
        AjaxResult ajaxResult = AjaxResult.error("访问太频繁,请稍后再试");
        httpServletResponse.setContentType("application/json;charset=utf-8");
        httpServletResponse.getWriter().write(JSON.toJSONString(ajaxResult) + "servlet用法");
    }
}

测试限流使用(频繁刷新访问)
image.png

Feign的熔断与降级

### 1.0 在调用处的Feign接口
package com.efly.gulimall.product.feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
//fallback为Feign远程执行失败了要去调用调用哪个类的同名方法(需要将该指定类注入到SpringIOC容易,并且声明一致)
@FeignClient(name = "gulimall-coupon-micservere",fallback = GetCouponsByMember.class)
public interface CouponFeign {
    @RequestMapping("coupon/login/getSession")
    String getCouponsByMember();
}

//必须将其注入到SpringIOC容器里面,并重写降级方法
package com.efly.gulimall.product.feign;
import org.springframework.stereotype.Component;
@Component
public class GetCouponsByMember implements CouponFeign {
    @Override
    public String getCouponsByMember() {
        return "远程调用失败";
    }
}

### 2.0 实际使用代码 ###
//如果couponFeign.getCouponsByMember()远程调用失败了则会熔断并且调用我们在调用处写的方法(越到后面速度越快,即不直接走远程方法了)
@RequestMapping("/getSession")
public String getSession(HttpSession session, HttpServletRequest request) {
    String couponsByMember1 = couponFeign.getCouponsByMember();
    System.out.println(couponsByMember1);
    return couponsByMember1 + "success";
}

自定义网关错误页

package com.efly.gulimall.gulimallgateway.config;

import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
import com.alibaba.fastjson.JSON;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Configuration
public class MyGateWaySentinelConfiguration {
    public MyGateWaySentinelConfiguration() {
        GatewayCallbackManager.setBlockHandler(new BlockRequestHandler() {
            //网关限流了请求,就会调用此回调
            @Override
            public Mono<ServerResponse> handleRequest(ServerWebExchange exchange, Throwable t) {
                String errorJson = JSON.toJSONString("官网阻塞");
                Mono<ServerResponse> body = ServerResponse.ok().body(Mono.just(errorJson), String.class);
                return body;
            }
        });
    }
}

功能:流控功能

概述文档:流控规则文档网关流控
SpringCloud-Alibaba整合文档:Sentinel
流控更多侧重于被调用方。

概述

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

  • 资源名:唯一名称,默认请求路径
  • 针对来源:sentinel可以针对调用者进行限流,填写微服务名,默认default(不区分来源)
  • 阈值类型/单机值:
    • QPS(每秒钟的请求数量):当调用该api就QPS达到阈值的时候,进行限流
    • 线程数.当调用该api的线程数达到阈值的时候,进行限流
  • 单机/均摊阈值:和下面的选项有关
  • 集群阈值模式:
    • 单机均摊:前面设置的阈值是每台机器的阈值
    • 总体阈值:前面设置的阈值是集群总体的阈值
  • 流控模式:
    • 直接:api达到限流条件时,直接限流。分为QPS和线程数
    • 关联:当关联的资到阈值时,就限流自己。别人惹事,自己买单。当两个资源之间具有资源争抢或者依赖关系的时候,这两个资源便具有了关联。举例来说,read_db 和 write_db 这两个资源分别代表数据库读写,我们可以给 read_db 设置限流规则来达到写优先的目的:设置 strategy 为 RuleConstant.STRATEGY_RELATE 同时设置 refResource 为 write_db。这样当写库操作过于频繁时,读数据的请求会被限流。或者支付接口到达流量峰值,下单服务就限流。
    • 链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)【api级别的针对来源】
  • 流控效果:
    • 快速失败:直接拒绝。当QPS超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出FlowException
    • warm up:若干秒后才能达到阈值。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过”冷启动”,让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮
    • 排队等待:让请求以均匀的速度通过

bbfc69e24c311869fadda1db87fc3b02_12394e569076162ed25460ecbb73e384.png

功能:熔断降级

参考文档

概念文档:熔断和降级
SpringCloud-Feign整合文档:整合文档
熔断与降级异同点
相同点:为了保证集群大部分服务的可用性和可靠性,防止崩溃,牺牲小我;用户最终都是体验到某个功能不可用。
不同点:熔断是被调用方故障,触发的系统主动规则;降级是基于全局考虑,停止一些正常服务,释放资源。
熔断更多侧重于调用方。

概述

4月15日和18日,民航局分别向吉祥航HO1608等3个航班发出熔断指令:4月6日入境的德国汉莎航空公司LH720航班(法兰克福至沈阳)确诊新冠肺炎旅客9例;自5月16日起,继续暂停该航班运行2班。熔断的航班量均不得用于其他航线。

除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。一个服务常常会调用别的模块,可能是另外的一个远程服务、数据库,或者第三方 API 等。例如,支付的时候,可能需要远程调用银联提供的 API;查询某个商品的价格,可能需要进行数据库查询。然而,这个被依赖服务的稳定性是不能保证的。如果依赖的服务出现了不稳定的情况,请求的响应时间变长,那么调用服务的方法的响应时间也会变长,线程会产生堆积,最终可能耗尽业务自身的线程池,服务本身也变得不可用。
现代微服务架构都是分布式的,由非常多的服务组成。不同服务之间相互调用,组成复杂的调用链路。以上的问题在链路调用中会产生放大的效果。复杂链路上的某一环不稳定,就可能会层层级联,最终导致整个链路都不可用。因此我们需要对不稳定的弱依赖服务调用进行熔断降级,暂时切断不稳定调用,避免局部不稳定因素导致整体的雪崩。熔断降级作为保护自身的手段,通常在客户端(调用端)进行配置。

熔断策略

Sentinel 提供以下几种熔断策略:

  • 慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
  • 异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。
  • 异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。

可以在控制台针对某个接口配置限流配置,配置了降级的接口虽然在运营,但是调用方会去读取其内部配置的降级配置。
image.png
image.png

网关流控