微服务-服务容错 - 实践
1.高并发带来的问题
在微服务架构中,我们将业务拆分成⼀个个的服务,服务与服务之间可以相互调⽤,但是由于⽹络原因或者⾃身的原因,服务并不能保证服务的100%可⽤,如果单个服务出现问题,调⽤这个服务就会出现⽹络延迟,此时若有大量的网络涌入,会形成任务堆积,最终导致服务瘫痪。
2.模拟场景
2.1 新建一个cloud.sentinel.provider项目
package com.jiazhong.mingxing.project.cloud.sentinel.provider.controller;
import com.jiazhong.mingxing.cloud.commons.util.JsonResult;
import com.jiazhong.mingxing.cloud.commons.util.ResultTool;
import lombok.SneakyThrows;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/sentinel_provider")
public class SentinelProviderController {
@SneakyThrows
@GetMapping("/a")
public JsonResult a() {
Thread.sleep(3000);
return ResultTool.success("This is SentinelProviderController`a method");
}
@GetMapping("/b")
public JsonResult b() {
return ResultTool.success("This is SentinelProviderController`b method");
}
}
启动项目
2.2新建cloud.sentinel.consumer项目
写一个SentinelProviderFeign接口
package com.jiazhong.mingxing.project.cloud.sentinel.provider.feign;
import com.jiazhong.mingxing.cloud.commons.util.JsonResult;
import com.jiazhong.mingxing.project.cloud.sentinel.provider.feign.impl.SentinelProviderFeignImpl;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
@FeignClient(value = "cloud-sentinel-provider", path = "sentinel_provider", fallback = SentinelProviderFeignImpl.class)
public interface SentinelProviderFeign {
@GetMapping("/a")
JsonResult a();
@GetMapping("/b")
JsonResult b();
}
写service以及实现类
package com.jiazhong.mingxing.project.cloud.sentinel.provider.service;
import com.jiazhong.mingxing.cloud.commons.util.JsonResult;
import org.springframework.stereotype.Service;
@Service
public interface SentinelConsumerService {
JsonResult a();
JsonResult b();
}
package com.jiazhong.mingxing.project.cloud.sentinel.provider.feign.impl;
import com.jiazhong.mingxing.cloud.commons.util.JsonResult;
import com.jiazhong.mingxing.cloud.commons.util.ResultTool;
import com.jiazhong.mingxing.project.cloud.sentinel.provider.feign.SentinelProviderFeign;
import org.springframework.stereotype.Component;
@Component
public class SentinelProviderFeignImpl implements SentinelProviderFeign {
@Override
public JsonResult a() {
return sentinelProviderFeign.a();
}
@Override
public JsonResult b() {
return sentinelProviderFeign.b();
}
}
新建controller类
package com.jiazhong.mingxing.project.cloud.sentinel.provider.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.jiazhong.mingxing.cloud.commons.util.JsonResult;
import com.jiazhong.mingxing.cloud.commons.util.ResultTool;
import com.jiazhong.mingxing.project.cloud.sentinel.provider.service.SentinelConsumerService;
import lombok.SneakyThrows;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/sentinel_consumer")
public class CloudSentinelConsumerController {
private SentinelConsumerService sentinelConsumerService;
public CloudSentinelConsumerController(SentinelConsumerService sentinelConsumerService) {
this.sentinelConsumerService = sentinelConsumerService;
}
@GetMapping("/a")
public JsonResult a() {
return sentinelConsumerService.a();
}
@GetMapping("/b")
public JsonResult b() {
return sentinelConsumerService.b();
}
}
修改yml文件
server:
port: 8022
jetty:
threads:
max: 10
spring:
application:
name: cloud-sentinel-consumer
#这里是微服务的内容
#注册
cloud:
nacos:
discovery:
namespace: 5dde225c-61e0-4015-8a2f-5eabe8407195 # 你的命名空间
server-addr: 192.168.xx.xx:8848 # 自己的地址
#ephemeral: false
sentinel:
transport:
port: 8719 #跟控制台交流的端⼝,随意指定⼀个未使⽤的端⼝即可
dashboard: localhost:8888 # 指定控制台服务的地址
web-context-unify: false
feign:
sentinel:
enabled: true
启动该项目
2.3.下载压测工具JMeter
下载地址:https://jmeter.apache.org/
解压,启动jmeter.sh






2000个请求,访问a,a占用资源,来一个正常的b,没有资源处理,响应时间会增加。

3.服务雪崩效应
4.常见容错方案
要防⽌雪崩的扩散,我们就要做好服务的容错,容错说⽩了就是保护⾃⼰不被猪队友拖垮的⼀些措施,下⾯介绍常见的服务容错思路和组件。 常⻅的容错思路有隔离、超时、限流、熔断、降级这几种,下⾯分别介绍⼀下。
4.1隔离
它是指将系统按照⼀定的原则划分为若⼲服务模块,各个模块之间相对独⽴,⽆强影响。当有故障发⽣时,能将问 题和影响隔离在某个模块内部, ⽽不扩散⻛险,不波及其他模块,不影响整体的系统服务。
常⻅的隔离⽅式有:
- 线程池隔离。
- 信号量隔离。

4.2超时
4.3限流
限流就是限制系统的输入和输出流量已达到保护系统的目的,为了保护系统的稳固巡行,一旦达到的需要限制的阈值,就需要限制流量并采取少量措施以完成限制流量的目的。
4.4熔断

- 熔断关闭状态(Closed) B服务没有故障时,熔断器所处的状态,对调⽤⽅(A服务)的调⽤不做任何限制。
- 熔断开启状态(Open) B服务有故障时,后续对该服务接⼝的调⽤不再经过⽹络(不在对B 服务进行访问),直接执⾏本地的fallback的⽅法。
- 半熔断状态(Half-Open) 尝试恢复服务调⽤,允许有限的流量调⽤该服务,并监控调⽤成功率。如果成功率达到预期,则说明服务已恢复,进⼊熔断关闭状态; 如果成功率仍旧很低,则重新进⼊熔断开启状态。
4.5降级
降级其实就是为服务提供⼀个托底(备选)⽅案,⼀旦服务⽆法正常调⽤,就使⽤托底(备选)方案。

我们使用容错组件Sentinel
5.Sentinel入门
5.1什么是Sentinel
Sentinel 是 Alibaba 开源的分布式系统流量控制、熔断降级、系统负载保护工具,核心目标是 保障微服务架构的稳定性,避免因流量突增、服务故障、资源耗尽等问题导致整体系统雪崩。
它与 Spring Cloud 生态深度集成(如 Spring Cloud Alibaba Sentinel),可无缝对接 Nacos、Gateway、Feign 等组件,是微服务架构中 “稳定性防护” 的核心组件之一。
- 资源:是 Sentinel 的关键概念。它可以是 Java 应⽤程序中的任何内容,可以是⼀个服务,也可以是⼀个⽅法,甚⾄可以是⼀段代码。就是 Sentinel 需要保护的东⻄。 我们⼊⻔案例中的 customer/b ⽅法就可以认为是⼀个资源。
- 规则:作⽤在资源之上,定义以什么样的⽅式保护资源,主要包括流量控制规则、熔断降级规则以及系统保护规则。规则就是⽤来定义如何进⾏保护资源的。 我们⼊⻔案例就是为 customer/b 资源设置了⼀种流控规则,限制了进⼊ customer/b 的流量。
5.2Sentinel的组成部分
- 核心库( Java 客户端)不依赖任何框架|库,能够运⾏于所有 Java 运⾏环境,同时对 Dubbo/Spring Cloud 等框架也有较好的⽀持。
- 控制台( Dashboard )基于 Spring Boot 开发,打包后可以直接运⾏,不需要额外的 Tomcat 等应⽤容器。
5.3微服务集成Sentinel
5.3.1导入依赖
com.alibaba.cloud
spring-cloud-starter-alibaba-sentinel
5.3.2安装控制台
Sentinel 提供⼀个轻量级的控制台,它提供机器发现、单机资源实时监控以及规则管理等功能。 下载 jar 包,存放到任意⽂件夹。https://github.com/alibaba/Sentinel/releases(下载1.8.9)
5.3.3启动控制台
通过 cmd 命令可以启动控制台。
## 其中8888是端⼝号,1.8.5是下载的版本号。都是可以修改的。
java -Dserver.port=8888 -Dcsp.sentinel.dashboard.server=localhost:8888 -
Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.9.jar
在浏览器中输入地址:localhost:8888 即可出现下图画面

用户以及密码都是sentinel

5.3.4 修改“消费者项目”,在⾥边加⼊有关控制台的配置
spring:
cloud:
sentinel:
transport:
port: 8719 #跟控制台交流的端⼝,随意指定⼀个未使⽤的端⼝即可
dashboard: localhost:8888 # 指定控制台服务的地址
启动生产者和消费者项目,多访问几次,就会在Sentinel中看到

设置每秒最多访问2次


若1秒内多于2次,出现下图

6.案例
在controller类中写下述方法
@GetMapping("/c")
public JsonResult c() {
return ResultTool.success("This is SentinelConsumerController`c method!");
}
这样可以只启动消费者
6.1流控(线程数)


启动Jmeter

有3/7的几率失败
6.2让步
在controller类下写入d方法
@GetMapping("/d")
public JsonResult d() {
return ResultTool.success("This is SentinelConsumerController`d method!");
}

如果d的资源每秒访问数超过4次就会限流访问c

c不可以访问,d可以访问
6.3链路
链路:只记录指定链路上的流量(指定资源从⼊⼝资源进来的流量,如果达到阈值,就进⾏限流), 可看作 api 级别的针对来源,链路的粒度更细,需要如下步骤才能实现6.3.1修改yml文件
添加下述代码
web-context-unify: false
6.3.2在service中写方法
@SentinelResource("messageE")
public JsonResult e() {
return ResultTool.success("This is SentinelConsumerServiceImpl`e method!");
}
6.3.3写两个controller方法e1 e2
@GetMapping("/e1")
public JsonResult e1() {
return sentinelConsumerService.e();
}
@GetMapping("/e2")
public JsonResult e2() {
return sentinelConsumerService.e();
}

对e1限流,e2不限流

浙公网安备 33010602011771号