1 写在前头

1.1 什么是单体架构?

我们传统的项目都是单工程,多模块。一个项目下好几个模块,我们将业务逻辑都编写在一个工程中,然后编译、打包、部署一气呵成,简单粗暴。
而这种架构我们称之为单体架构。在单体架构中,单体应用将所有的业务都集中在同一个工程中,修改或增加业务都可能会对其他业务造成一定的影响,导致测试难度增加。
并且由于代码都集中到一个工程之中,耦合度高,而且服务也只部署到一个服务器上,导致工程并发能力有限。

由于单体架构存在上述的弊端,所以现在一个项目的开发方式也逐渐走向微服务架构

1.2 什么是微服务架构?

单体架构代码耦合度高?好的,那将其拆成多个服务;
单体架构并发能力有限?好的,不同的服务部署集群,一个扛不住就来多个;
单体架构容易引发雪崩?好的,服务之间故障隔离,一个服务挂了我不用你就是了。

上述就是微服务架构相对于单体架构的一些优势,那到底什么是微服务架构?

微服务架构是一种系统架构的设计风格。与传统的单体式架构不同,微服务架构提倡将一个单一的应用程序拆分成多个小型服务,这些小型服务都在各自独立的进程中运行,服务之间使用轻量级通信机制(通常是 HTTP RESTFUL API)进行通讯。

比如一个商城项目,其中不可避免的会有订单模块,库存模块,用户信息模块,在微服务架构中就会将这三个模块拆开,形成三个不同的服务:订单服务,库存服务,用户信息服务,每个服务可以有自己的开发团队,团队可以使用自己的开发语言。这些不同的微小服务,就是微服务。

2 SpringCloudAlibaba

2.1 服务拆分引发的问题

1 不同服务之间怎么发现彼此?
2 不同服务之间怎么通信?
3 多服务调用怎么保证事务的一致性?
4 服务部署到不同的机器上怎么控制并发?
5 某个服务的集群宕机怎么保证整个服务不雪崩?

看到这些问题是不是一阵头大?没关系,SpringCloudAlibaba给我们提供了解决上述问题的方案!

2.2 什么是SpringCloudAlibaba

SpringCloudAlibaba是阿里巴巴提供的微服务开发一站式解决方案,是阿里巴巴开源中间件与 Spring Cloud 体系的融合;

Spring Cloud Alibaba 是国内首个进入 Spring 社区的开源项目。2018 年 7 月,Spring Cloud Alibaba 正式开源,并进入 Spring Cloud 孵化器中孵化;2019 年 7 月,Spring Cloud 官方宣布 Spring Cloud Alibaba 毕业,并将仓库迁移到 Alibaba Github OSS 下。

虽然 Spring Cloud Alibaba 诞生时间不久,但俗话说的好“大树底下好乘凉”,依赖于阿里巴巴强大的技术影响力,Spring Cloud Alibaba 在业界得到了广泛的使用,成功案例也越来越多。

2.3 SpringCloudAlibaba提供的组件

Nacos:服务发现和配置管理
Sentinel:服务降级和服务流控
Seata:分布式事务处理框架

SpringCloud提供的组件:

Loadbalancer:负载均衡
OpenFeign:服务之间的远程调用
Gateway:网关,也是整个微服务的门户

3 Nacos

Nacos是整个微服务项目的注册中心和配置中心,所有的微服务都要来这里注册,以便让其它的服务发现自己,从而互相调用;而某个微服务的配置也可以扔给Nacos管理,启动的时候直接到Nacos拉取即可。

3.1 下载Nacos

Nacos是一个已经写好的项目,我们需要做的是将其下载,然后启动:

官网:
	https://nacos.io/zh-cn/
下载:
	https://github.com/alibaba/nacos/releases

并不是下载好Nacos就可以直接使用,Nacos还依赖于一些环境:

JDK 1.8+
Maven 3.2+

3.2 启动Nacos

由于我们Nacos没有部署集群,所以此处需要以单机的模式启动,在Nacos的bin目录下进入cmd,执行下述命令:

startup.cmd -m standalone

上述命令会让Nacos以单机模式启动,启动之后在浏览器访问:

localhost:8848/nacos/index.html

看到下述页面说明Nacos启动成功:
在这里插入图片描述

4 OpenFeign和Loadbalancer

前置条件:

我们需要在Nacos中注册两个微服务,我此处将其命名为client-test和cilent-account。
client-account:消费者(使用其它服务的接口,即“消费”)
client-test:生产者(给其它服务提供接口,即“生产”)

注意消费者生产者并不是非黑即白的概念,即某个服务既可能是生产者,也可能是消费者

4.1 对client-account服务做负载均衡(Loadbalancer)

4.1.1 配置

pom.xml:

无,spring-cloud-commons 和 spring-cloud-loadbalancer 已经被引入

application.properties:

配置类:

public class CustomLoadBalancerConfiguration {
	@Bean
	ReactorLoadBalancer<ServiceInstance> randomLoadBalancer (
		Environment environment,
		LoadBalancerClientFactory loadBalancerClientFactory) {
		String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
		// 在此也可返回自定义负载均衡器
		return new RandomLoadBalancer(
			loadBalancerClientFactory.getLazyProvider(name,
				ServiceInstanceListSupplier.class),
			name);
	}
}

注意:配置类并不是必须的,如果想要改变Loadbalancer的负载均衡方式就可以配置。

4.1.2 使用

Loadbalancer提供了两种负载均衡方式:随机(RandomLoadBalancer)和轮询(RoundRobinLoadBalancer):

轮询:消费者每次调用生产者的接口,依次使用集群中的服务
随机:消费者每次调用生产者的接口,随机使用集群中的服务

其中,轮询是Loadbalancer默认提供的方式,此处我将Loadbalancer的负载均衡方式改为了随机(参见配置类)。

修改client-account的启动类:

@SpringBootApplication
// name和目标微服务的注册名保持一致,configuration引入自定义的配置类
@LoadBalancerClient(name = "client-account", configuration = 
	CustomLoadBalancerConfiguration.class)
public class SpringCloudTestApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringCloudTestApplication.class, args);
	}
}

这样,当client-account去访问client-test时,就会实现随机访问集群中的服务。

4.2 client-account调用client-test服务(OpenFeign)

4.2.1 配置

pom.xml:

<!--openfeign-->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

<!--loadbalancer,springcloud高版本中,OpenFeign使用的负载均衡器,需单独引入-->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>

application.properties:

4.2.2 使用

client-test提供的接口:

@RefreshScope
@RestController
@RequestMapping("/api/test")
public class CountryController {

    @Autowired
    private CountryService countryService;

    /**
     * 127.0.0.1:8001/api/test/country/522 ---- get
     */
    @GetMapping(value = "/country/{countryId}")
    public Country getCountryByCountryId(@PathVariable int countryId) {
        return countryService.getCountryByCountryId(countryId);
    }
}

client-account中创建一个TestFeign接口,用于远程调用cient-test的接口

// name的值是要调用的微服务在Nacos中注册的名字,Nacos的重要性可见一斑。
@FeignClient(name = "client-test")
public interface TestFeign {
    @GetMapping(value = "/api/test/country/{countryId}")
    Country getCountryByCountryId(@PathVariable int countryId);
}

client-account在Controller中使用TestFeign接口

@RestController
@RequestMapping("/api/account")
publicc lass AccountController {
        @Autowired
        private TestFeign testFeign;
        
        /**
        * 127.0.0.1:8004/api/account/country/522
        * @param id
        * @return
        */
        @GetMapping("/country/{id}")
        public Country getCountry(@PathVariable int id) {
                return testFeign.getCountryByCountryId(id);
        }
}

在client-account微服务的启动类上添加@EnableFeignClients注解

@EnableFeignClients
@SpringBootApplication
public class SpringCloudAlibabaAccountApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringCloudAlibabaAccountApplication.class, args);
    }
}

现在启动项目,就可以在client-account服务中调用client-test的接口了!

5 Gateway

Gateway被称为网关,顾名思义,网络的关卡,在一个微服务项目中部署网关,让客户端只能通过网关访问微服务内部的接口,保证了微服务项目内各个接口的安全:
在这里插入图片描述

5.1创建Gateway项目

Gateway项目也是一个单独的项目,也就是说Gateway也是一个微服务,它也是需要去Nacos中注册的。

前置问题
Gateway的组件不能和SpringWeb的组件共存。
为什么?

Gateway构建于Spring 5+,基于Spring boot 2.x响应式的、非阻塞式的API,同时,他支持webSockets和spring框架紧密集成。而当一个项目中有spring-web时,启动项目时默认使用的是spring-boot-starter-web的内置容器,该容器不支持非阻塞,所以gateway就会报错,所以gateway和spring web组件不能共存。

5.1.1 配置

pom.xml:

<!-- gateway -->
<!-- nacos discovery -->
<dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

<!-- gateway -->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

<!-- loadbalancer(springcloud高版本中,OpenFeign使用的负载均衡器,需单独引入) -->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>

<!-- openfeign
	(不添加该依赖,网关无法转发客户端的请求,猜测Nacos负载均衡器和Gateway负载均衡器不一致造成)
-->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

application.properties:

# for server
server.port=8000

# for spring
spring.application.name=client-gateway

# for nacos
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848

# 设置该项目非Web启动(也就是上面说方案二)
spring.main.web-application-type=reactive

# for gateway route
# 默认false,开启后可以通过ip:port/服务名称/接口地址进行服务转发
#spring.cloud.gateway.discovery.locator.enabled=true
# 把服务名转换为小写,Eureka中默认都是大写,但Nacos不会自动转换,所以也可以不写。
#spring.cloud.gateway.discovery.locator.lower-case-service-id=true
spring.cloud.gateway.routes[0].id=account-service
spring.cloud.gateway.routes[0].uri=lb://client-account
spring.cloud.gateway.routes[0].predicates[0]=Path=/api/account/**
spring.cloud.gateway.routes[1].id=common-service
spring.cloud.gateway.routes[1].uri=lb://client-test
spring.cloud.gateway.routes[1].predicates[0]=Path=/api/test/**

5.1.2 使用

启动类上添加下列注解:

@EnableFeignClients
@EnableDiscoveryClient

解决跨域问题:

@Configuration
public class CorsAutoConfiguration {
	@Bean
	public WebFilter corsFilter() {
		/**
		* ServerWebExchange:请求上下文,里面可以获取request和response等信息
		* WebFilterChain:放行链,将请求放行给下一个过滤器
		*/
		return (ServerWebExchange ctx, WebFilterChain chain) -> {
			ServerHttpRequest request = ctx.getRequest();
			if(CorsUtils.isCorsRequest(request)) {
				ServerHttpResponse response = ctx.getResponse();
				HttpHeaders headers = response.getHeaders();
				// 允许跨域访问
				headers.set(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN,
					request.getHeaders().getOrigin());
				// 允许的header
				headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS,
					"X-Token,Token,Authorization,x-requested-with,Content-Type");
				headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS,
					"PUT,POST,GET,OPTIONS,DELETE");
				headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
				headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*");
				headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, "3600");
				if(request.getMethod() == HttpMethod.OPTIONS) {
					response.setStatusCode(HttpStatus.OK);
					return Mono.empty();
				}
			}
			return chain.filter(ctx);
		};
	}
}

至此,Gateway基本功能已经完善,可以将所有微服务的端口都换做是Gateway的端口,让整个Gateway成为整个微服务项目的门户。

6 Sentinel

简介:

Sentinel 翻译过来就是哨兵,那么哨兵的作用自然就是监控。
Sentinel 是由阿里巴巴中间件团队开发的开源项目,是一种面向分布式微服务架构的轻量级高可用流量控制组件。
Sentinel 主要以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度帮助用户保护服务的稳定性。

基本概念:资源规则

资源:我们在项目中想要保护的东西都可以称为资源,可以是某个服务,方法,或者一个代码块
规则:围绕我们想要保护的资源而设定的规则,常见如流控和熔断。

两大组成:核心库控制台

Sentinel 核心库:
        Sentinel 的核心库不依赖任何框架或库,能够运行于 Java 8 及以上的版本的运行时环境中,同时对 Spring Cloud、Dubbo 等微服务框架提供了很好的支持。
Sentinel 控制台:
        Sentinel 提供的一个轻量级的开源控制台,基于SpringBoot开发,它为用户提供了机器自发现、簇点链路自发现、监控、规则配置等功能。

6.1 下载Sentinel控制台

文档地址:https://sentinelguard.io/zh-cn/docs/introduction.html
仓库地址:https://github.com/alibaba/Sentinel

修改控制台的日志输出位置
sentinel默认的输出位置为:${user_home}/logs/csp/${project.name}.properties。也就是默认位置为c盘。
对于已经使用了sentinel的微服务,可以在其resource目录下创建一个sentinel.properties文件,其中定义如下配置即可更改sentinel的日志输出位置:

csp.sentinel.log.dir=G:/file_static/logs/sentinel_logs/client-account/

访问Sentinel的控制台:
sentinel的控制台就是一个jar包,因为是用SpringBoot写的,开发者没有重新定义其端口号,默认就是8080,这是一个常用端口号,可能会被占用,所以我们可以在启动时修改其端口号:

java -jar sentinel-dashboard-1.8.3.jar --server.port=9090

账号和密码都是sentinel
在这里插入图片描述

6.2 定义资源和规则

6.2.1 定义资源

Sphu定义资源
Sentinel 提供了一个名为 SphU 的类,它包含的 try-catch 风格的 API ,可以帮助我们手动定义资源:

@GetMapping("/string/{name}")
public String getName(@PathVariable String name) {
        Entry entry = null;
        try {
                // 定义资源名称
                entry = SphU.entry("getName");
                // 业务逻辑开始
                return name;
                // 业务逻辑结束
        } catch (BlockExceptione) {
                // 资源被流控时
                return"您被流控了";
        } finally {
                if(entry != null) {
                        entry.exit();
                }
        }
}

这样就定义好了一个资源,我们可以为其添加熔断或者流控规则,并且可以在sentinel面板看到该资源:
在这里插入图片描述
Spho定义资源
Sentinel 还提供了一个名为 SphO 的类,它包含了 if-else 风格的 API,能帮助我们手动定义资源:

@GetMapping("/integer/{id}")
public int getInt(@PathVariable int id) {
        // 定义资源名称
        if(SphO.entry("getInt")) {
                try {
                        // 您的业务逻辑
                        return id;
                } finally {
                        SphO.exit();
                }
        } else {
                // 您的限流或熔断逻辑
                return -1;
        }
}

这样就定义好了一个资源,我们可以为其添加熔断或者流控规则,并且可以在sentinel面板看到该资源:
在这里插入图片描述
@SentinelResource方式定义资源(推荐)

/**
* @author weiyond
* 2022/9/29 13:45
*/
@RestController
@RequestMapping("/api/account")
public class AccountController {
        @Autowired
        private TestFeign testFeign;

        /**
        * 127.0.0.1:8004/api/account/country/522
        *
        * SentinelResource参数解释:
        *   value:
                    指定资源名称,可以随便取,按照见名知意,我们一般取当前接口调用的下游服务的方法名作为资源名
        *   blockHandler:
                    当资源被限流或降级时,指定一个方法来作为备用逻辑
        *       若备用方法和当前方法不在用一个类还需要指定blockHandlerClass参数
        *   fallback:
                    当资源被熔断时,指定一个方法来作为备用逻辑
        *       若备用方法和当前方法不在用一个类还需要指定fallbackClass参数
        * @param id
        * @return
        */
        @GetMapping("/country/{id}")
        @SentinelResource(value = "getCountryByCountryId",
                blockHandler = "blockHandler",
                fallback = "fallback")
        public Country getCountry(@PathVariable int id) {
                return testCountryFeignClient.getCountryByCountryId(id);
        }
        
        /**
        * 发生限流和降级时,就会调用该方法来充当备用处理的逻辑
        *  FlowException:发生流控时,抛出该异常
        *  DegradeException:发生降级时,抛出该异常
        * @param id
        * @param exception
        * @return
        */
        public Countryb lockHandler(int id, BlockException exception) {
                if(exception instanceof FlowException) {
                        System.out.println("您被限流了.");
                } else if(exception instanceof DegradeException) {
                        System.out.println("您被降级了.");
                } else {
                        System.out.println("当前接口不可用.");
                }
                return new Country();
        }
        
        /**
        * 当资源熔断了,就调用该方法来充当备用处理逻辑
        * @param id
        * @return
        */
        public Country fallback(int id) {
                System.out.println("当前接口熔断了");
                return new Country();
        }
}

6.2.2 定义规则

流控规则
对上面通过@SentinelResource定义的资源getCountryByCountryId添加流控:
在这里插入图片描述
现在,getCountryByCountryId这个资源已经被Sentinel保护起来了!1秒内多次访问getCountryByCountryId资源,浏览器出现我们自定义的限流信息(接口直接返回空对象,不会去调用下游服务,减轻下游服务的压力):
在这里插入图片描述
上述定义流控规则是根据Sentinel控制台实现的,如果你愿意,还可以使用编码的方式实现流控(这也证明了Sentinel核心库并不依赖于Sentile控制台):

@GetMapping("/country/{id}")
@SentinelResource(value = "getCountryByCountryId",
        blockHandler = "blockHandler",
        fallback = "fallback")
public Country getCountry(@PathVariable int id) {
        // 调用编码方式的流控规则
        initFlowRules();
        return testCountryFeignClient.getCountryByCountryId(id);
}

// 资源限流时执行的逻辑
public Country blockHandler(int id, BlockException exception) {
        return new Country();
}

private static void initFlowRules() {
        List<FlowRule> rules = new ArrayList<>();
        // 定义一个限流规则对象
        FlowRule rule = new FlowRule();
        // 资源名称
        rule.setResource("getCountryByCountryId");
        // 限流阈值的类型为QPS
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        // 设置QPS的阈值为2
        rule.setCount(1);
        
        rules.add(rule);
        // 定义限流规则
        FlowRuleManager.loadRules(rules);
}

编码方式也能实现限流:
在这里插入图片描述
熔断规则
熔断降级是什么?

在分布式微服务架构中,一个系统往往由多个服务组成,不同服务之间相互调用,组成复杂的调用链路。如果链路上的某一个服务出现故障,那么故障就会沿着调用链路在系统中蔓延,最终导致整个系统瘫痪。Sentinel 提供了熔断降级机制就可以解决这个问题。
Sentinel 的熔断将机制会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),暂时切断对这个资源的调用,以避免局部不稳定因素导致整个系统的雪崩。
熔断降级作为服务保护自身的手段,通常在客户端(调用端)进行配置,资源被熔断降级最直接的表现就是抛出 DegradeException 异常。

Sentinel提供的三种熔断降级策略:

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

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

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

注意:Sentinel 1.8.0 版本对熔断降级特性进行了全新的改进升级,以上熔断策略针对的是Sentinel 1.8.0 及以上版本。

熔断降级的三种状态:
在这里插入图片描述
现在开始演示熔断降级,名词解释:

上游服务:处于调用链的上方的服务
下游服务:处于调用链的下方的服务

显然,此处Demo中,我们的client-account就是上游服务,client-test就是下游服务。

我们在哪里做熔断降级?

在上游服务做熔断降级,这样当下游服务发生异常时,可以即时熔断上游服务和下游服务的调用链,避免下游服务的长时间宕机从而引起上游服务阻塞,不断有请求堆积,占用资源,慢慢扩散至整个项目,导致整个项目不可用,这就是雪崩。

client-account服务的熔断降级逻辑:

@RestController
@RequestMapping("/api/account")
public class AccountController {

        @Autowired
        private TestFeign testFeign;
        
        /**
        * 127.0.0.1:8004/api/account/country/522
        * SentinelResource参数:
        *      fallback:当资源被熔断时,指定一个方法来作为备用逻辑
        *      若备用方法和当前方法不在用一个类还需要指定fallbackClass参数
        *
        * @param id
        * @return
        */
        @GetMapping("/country/{id}")
        @SentinelResource(value = "getCountryByCountryId", fallback = "fallback")
        public Country getCountry(@PathVariable int id) {
                return testCountryFeignClient.getCountryByCountryId(id);
        }
        
        /**
        * 当资源熔断了,就调用该方法来充当备用处理逻辑
        *
        * @param id
        * @return
        */
        public Country fallback(int id) {
                monitor();
                System.out.println("当前接口熔断了");
                return new Country();
        }
        
        /**
        * 自定义事件监听器,监听熔断器状态转换
        * preState:熔断的上一个状态
        * newState:当前熔断状态
        */
        public void monitor() {
                EventObserverRegistry
                        .getInstance()
                        .addStateChangeObserver(
                                "logging",
                                (prevState, newState, rule, snapshotValue) -> {
                                        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-ddHH:mm:ss");
                                        if(newState == CircuitBreaker.State.OPEN) {
                                                // 变换至OPEN state时会携带触发时的值
                                                System.err.println(String.format("%s -> OPEN at%s, 发送请求次数=%.2f",
                                                        prevState.name(),
                                                        format.format(new Date(TimeUtil.currentTimeMillis())), 
                                                        snapshotValue));
                                        } else {
                                                System.err.println(String.format("%s -> %s at %s",
                                                        prevState.name(),
                                                        newState.name(),
                                                        format.format(new Date(TimeUtil.currentTimeMillis()))));
                                        }
                                }
                        );
        }
        
}

client-test服务随便产生一个异常:
在这里插入图片描述
Sentinel控制台getCountryByCountryId设置熔断降级规则:
在这里插入图片描述
上面的规则翻译成白话如下:

1秒内对目标资源的请求次数大于1次,且目标资源发生的异常数量超过1,那么就熔断该资源所使用的下游服务,熔断后的10秒内都使用其备用逻辑。

1秒内多次向资源传递小于0的参数:
在这里插入图片描述
idea控制台输出,可以看到根据sentinel控制台定义的熔断规则,此时熔断已经开启:
在这里插入图片描述
在熔断时长内(此处为10s),即使传递正常的参数也会直接降级,走备用逻辑:
在这里插入图片描述
熔断时长结束,熔断进入half-open状态,此时再次传递-1参数,half-open就会再次进入open:

下游服务异常应答:
在这里插入图片描述
idea输出:
在这里插入图片描述
熔断时长再次结束,熔断进入half-open状态,此时传递正常参数,half-open就会再次进入closed状态:
下游服务正常应答:
在这里插入图片描述
idea输出:
在这里插入图片描述
当然,上述是使用Sentinel控制台设置的规则,我们依然可以使用编码的方式实现熔断规则。

省略,下次和Seata一起补上 ^ ^

参考文章

http://c.biancheng.net/springcloud/micro-service.html
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐