文章目录

背景

  • 在微服务架构中,如何保证微服务的稳定性是一大课题。在​​《实战Spring Cloud 微服务容错保护Hystrix》​​文章中,我们通过使用Hystrix实现了服务熔断和降级,从而提高微服务系统的整体健壮性。
  • 但不幸的是Hystrix也已经停更,我们需要一种新的流量控制组件来完成以上工作。
  • 实战Spring Cloud之流量控制组件Sentinel_微服务

一、Sentinel是什么

  • Sentinel是阿里巴巴旗下的开源流量控制组件,通过以下链接​​《Sentinel 介绍》​​可以对Sentinel有个简单了解。
  • 实战Spring Cloud之流量控制组件Sentinel_微服务_02

  • 本文将分别通过服务提供方及服务消费者两个角度说明Sentinel是如何进行流量控制和熔断降级的。

1.1 安装Sentinel控制台

# 下载服务端
wget https://github.com/alibaba/Sentinel/releases/download/v1.8.0/sentinel- dashboard-1.8.0.jar
# 启动服务(默认端口为8080)
  • 登录控制台,默认用户名与密码为sentinel
  • 实战Spring Cloud之流量控制组件Sentinel_spring_03


  • 实战Spring Cloud之流量控制组件Sentinel_sentinel_04

二、创建微服务

2.1 创建微服务工程项目

  • 通过Spring网站创建项目
  • 实战Spring Cloud之流量控制组件Sentinel_spring cloud_05

  • 项目命名
  • 实战Spring Cloud之流量控制组件Sentinel_spring_06

  • 勾选Spring Web,Nacos Service Discovery,Sentinel依赖
  • 实战Spring Cloud之流量控制组件Sentinel_sentinel_07


  • 实战Spring Cloud之流量控制组件Sentinel_sentinel_08

  • 检查pom.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>nacos.democonsumer</groupId>
<artifactId>sentinel</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>sentinel</name>
<description>Demo project for Spring Boot</description>

<properties>
<java.version>1.8</java.version>
<spring-cloud-alibaba.version>2.2.1.RELEASE</spring-cloud-alibaba.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>

2.2 向Nacos服务中心注册微服务

  • 通过 Spring Cloud 原生注解 @EnableDiscoveryClient 开启服务注册发现功能
// 通过 Spring Cloud 原生注解 @EnableDiscoveryClient 开启服务注册发现功能
@EnableDiscoveryClient
@SpringBootApplication
public class SentinelApplication {

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

}
  • 通过application.yml进行配置
server:
port: 8083

spring:
application:
name: goods-service
cloud:
# nacos服务注册
nacos:
discovery:
server-addr: 172.16.109.118:8848
# sentinel服务
sentinel:
transport:
dashboard: 172.16.109.118:8080

2.3 编写微服务业务逻辑

/**
* 商品服务-模拟返回商品列表
*/
@RestController
@RequestMapping("api/goods")
public class GoodsService {

@Value("${spring.application.name}")
private String server;

@Value("${server.port}")
private String port;

public static final Logger logger = LoggerFactory.getLogger(GoodsService.class);
// 返回商品列表
@SentinelResource(value = "goods")
@GetMapping
public List<Goods> getAllGoods(HttpServletRequest httpRequest) throws InterruptedException {
// 设置等待时间
TimeUnit.MILLISECONDS.sleep(3000);
List<Goods> goods = new ArrayList<>();
goods.add(new Goods("电脑", 10));
goods.add(new Goods("手机", 20));
goods.add(new Goods("书籍", 30));
logger.info(port+":"+server+"服务被调用,调用者为:"+httpRequest.getRemoteAddr()+":"+httpRequest.getRemotePort());
return goods;
}

}

/**
* 商品类
*/
public class Goods implements Serializable {

// 商品名称
private String name;
// 商品价格
private Integer number;

public Goods(String name, Integer number) {
this.name = name;
this.number = number;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Integer getNumber() {
return number;
}

public void setNumber(Integer number) {
this.number = number;
}
}

2.4 启动微服务,通过Sentinel控制台进行监控

  • 通过Nacos控制台观察微服务注册信息
  • 关于Nacos的使用,可参考该篇文章:​​《实战Spring Cloud之Nacos替换Eureka》​
  • 实战Spring Cloud之流量控制组件Sentinel_spring cloud_09

  • 我们通过HttpClient工具访问一下微服务的Api端口,并进入Sentinel控制台进行监控:在控制台中,我们发现了服务名称,及该服务下的各种规则设置菜单。
  • 实战Spring Cloud之流量控制组件Sentinel_微服务_10

三、微服务的流量控制

3.1 通过JMeter模拟高并发流量

  • 设置20000个并发请求
  • 实战Spring Cloud之流量控制组件Sentinel_java_11

  • 设置HTTP请求地址:
  • 实战Spring Cloud之流量控制组件Sentinel_spring cloud_12

  • 设置报告输出
  • 实战Spring Cloud之流量控制组件Sentinel_spring cloud_13

  • 启动JMeter,观察Sentinel控制台,可以看到QPS的实时状况。
  • 实战Spring Cloud之流量控制组件Sentinel_spring_14

3.2 设置流控规则进行流量控制

  • 对Sentinel控制台中服务的资源增加流量控制规则
  • 实战Spring Cloud之流量控制组件Sentinel_微服务_15

  • 给微服务接口的QPS设置阈值
  • 实战Spring Cloud之流量控制组件Sentinel_spring_16


  • 实战Spring Cloud之流量控制组件Sentinel_spring cloud_17

  • 再次启动JMeter进行高并发测试,在控制台中进行观察,可以看到服务接口的QPS被限制在阈值以下。
  • 实战Spring Cloud之流量控制组件Sentinel_java_18

  • JMeter结果列表中可以观察到异常信息。
  • 实战Spring Cloud之流量控制组件Sentinel_sentinel_19

3.2 设置降级规则进行流量控制

  • 对Sentinel控制台中服务的资源增加熔断降级规则
  • 实战Spring Cloud之流量控制组件Sentinel_spring cloud_20

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

实战Spring Cloud之流量控制组件Sentinel_java_21

  • 在实时监控界面可以看到请求被拒绝,证明熔断降级规则生效
  • 实战Spring Cloud之流量控制组件Sentinel_spring_22

  • 在JMeter结果表格中也出现了大量失败的调用请求
  • 实战Spring Cloud之流量控制组件Sentinel_spring_23

四、在微服务调用方进行流量控制

4.1 创建微服务调用者

4.1.1 加入OpenFeign组件

<-- pom.xml -->
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-openfeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>

4.1.2 项目配置

server:
port: 8090

spring:
application:
name: user-consumer
cloud:
nacos:
discovery:
server-addr: 172.16.109.118:8848
# sentinel服务
sentinel:
transport:
dashboard: 172.16.109.118:8080


# 调用微服务超时时间设置
ribbon:
ConnectTimeout: 5000
ReadTimeout: 5000


# feign日志以什么级别监控哪个接口
logging:
level:
nacos.democonsumer.GoodService : debug

# 启用sentinel
feign:
sentinel:
enabled: true

4.1.3 主启动类增加注解

/**
* 主启动类
*/
// 启用Feign组件
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class DemoConsumerApplication {

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

4.1.4 增加微服务接口

  • 通过@FeignClient调用微服务,并定义服务熔断时如何处理
/**
* 商品微服务接口
*/
@Component
// 增加服务容错处理,指定服务熔断时处理的类名
@FeignClient(value="goods-service",fallback =FallBackService.class )
public interface GoodService {

@GetMapping(value="/api/goods")
List<GoodsDTO> getGoods();

}

/**
* 服务熔断处理:返回空值
*/
@Component
public class FallBackService implements GoodService {
private final static Logger logger= LoggerFactory.getLogger(FallBackService.class) ;

@Override
public List<GoodsDTO> getGoods() {
logger.info("服务已熔断...");
return new ArrayList<>();
}
}

实战Spring Cloud之流量控制组件Sentinel_spring_24

4.1.5 服务调用者调用程序

/**
* 用户消费者--调用nacos服务中心的商品服务,并对外提供RestFul接口测试
*/
@RestController
@RequestMapping("user/")
public class UserConsumer {
// 注入商品微服务接品
@Autowired
private GoodService goodService;

@GetMapping("/goods")
public User getUserGoods() {
User user = new User();
// 通过GoodsService接口调用商品微服务
try {
List<GoodsDTO> goods = goodService.getGoods();
user.setName("jack");
user.setGoods(goods);
} catch (Exception e){
throw new RuntimeException(e.getMessage());
}
return user;
}

}

4.2 启动微服务调用者,通过Sentinel控制台进行监控

  • 通过HttpClient工具进行测试,调用正常
  • 实战Spring Cloud之流量控制组件Sentinel_spring_25

  • 通过Sentinel控制台进行监控
  • 实战Spring Cloud之流量控制组件Sentinel_spring_26

4.3 对服务调用者中的服务提供方进行流量控制

  • 对Sentinel控制台中服务的资源增加流量控制规则,在FeignClient中,Sentinel为Feign调用生成了资源名策略定义,定义规则为 [httpmethod :protocol://requesturl](比如GET:http://goods-service/api/goods)
  • 实战Spring Cloud之流量控制组件Sentinel_微服务_27

  • 为便于测试,故意将QPS的单机阈值设为0
  • 实战Spring Cloud之流量控制组件Sentinel_spring_28


  • 实战Spring Cloud之流量控制组件Sentinel_微服务_29

  • 使用HttpClient工具再次测试,由于我们在流量控制规则中已对QPS做了限制,服务调用请求已无法通过,故触发fallback,返回空值。
  • 实战Spring Cloud之流量控制组件Sentinel_spring cloud_30

  • 服务调用者日志信息提示服务已熔断…
  • 实战Spring Cloud之流量控制组件Sentinel_微服务_31

小结

  • Sentinel与Hystrix相比,更加轻量级:Sentinel对主流框架提供适配的 API,来定义需要保护的资源,并提供设施对资源进行实时统计和调用链路分析。
  • Sentinel 提供了更加多样化的流量控制,熔断降级和系统负载保护手段。
  • Sentine具备完善的实时监控和控制台。