Sentinel 入门教程 - 整合篇(2020 年)

大纲

前言

为了减少开发的复杂度,Sentinel 对大部分的主流框架,例如 Web Servlet、Dubbo、Spring Cloud、gRPC、Spring WebFlux,Reactor 等都做了适配,只需要引入对应的依赖即可方便的整合 Sentinel。如果要实现 Spring Cloud 和 Sentinel 的整合,可以通过引入 Spring Cloud Alibaba Sentinel 来整合 Sentinel。Spring Cloud Alibaba 是阿里巴巴开源的,致力于提供微服务开发的一站式解决方案。Spring Cloud Alibaba 默认为 Sentinel 整合了 Servlet、RestTemplate、FeignClient 和 Spring WebFlux。Sentinel 在 Spring Cloud 生态中,不仅补全了 Hystrix 在 Servlet 和 RestTemplate 这一块空白,而且还完全兼容了 Hystrix 在 FeignClient 中限流降级的用法,并且支持运行时灵活地配置和调整限流降级规则。

官方文档

Sentinel 整合 Spring Cloud

1.0、版本说明

本案例使用各开源组件的版本说明如下,点击下载完整的案例代码

组件版本说明
Spring Boot2.1.18.RELEASE
Spring CloudGreenwich.SR6
Spring Cloud Alibaba2.1.3.RELEASE
Sentinel Dashboard1.8.0

1.1、引入 Maven 依赖

添加 spring-cloud-starter-alibaba-sentinel 依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.18.RELEASE</version>
</parent>

<properties>
<spring-cloud.version>Greenwich.SR6</spring-cloud.version>
<spring.cloud.alibaba.version>2.1.3.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-sentinel</artifactId>
</dependency>
</dependencies>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<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>

1.2、创建主启动类

1
2
3
4
5
6
7
@SpringBootApplication
public class SentinelApplication {

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

1.3、创建 Controller 测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@RestController
public class TestController {

/**
* 定义资源
* value:资源名称
* blockHandler:限流处理的方法
*
* @return
*/
@SentinelResource(value = "Hello", blockHandler = "exceptionHandler")
@GetMapping("/hello")
public String hello() {
// 使用限流规则
return "Hello Sentinel!";
}

/**
* 原方法被限流的时候调用此方法
*
* @param e
* @return
*/
public String exceptionHandler(BlockException e) {
e.printStackTrace();
return "系统繁忙,请稍候 ...";
}
}

1.4、配置 Sentinel 控制台

application.yml 配置文件里,指定 Sentinel 控制台的地址和端口

1
2
3
4
5
6
7
8
9
10
server:
port: 8080

spring:
application:
name: sentinel-spring-cloud
cloud:
sentinel:
transport:
dashboard: 127.0.0.1:9000

1.5、案例代码测试

  • 1)启动 Sentinel 控制台
1
$ java -Dserver.port=9000 -jar sentinel-dashboard-1.8.0.jar
  • 2)启动 Spring Cloud 应用,浏览器访问 http://127.0.0.1:8080/hello,若响应结果返回 Hello Sentinel!,说明应用启动成功

  • 3)浏览器访问 http://127.0.0.1:9000,打开 Sentinel 控制台,动态添加流控规则,如下图所示:

sentinel-spring-cloud-add-rule

  • 4)浏览器再次访问 http://127.0.0.1:8080/hello,当快速刷新页面时,请求的响应结果变为 系统繁忙,请稍后 ...,,则说明 Sentinel 的流控规则生效了

资源名的配置

  • 在 Sentinel 的控制台里,针对上面的示例代码,也可以在新增流控规则时,将资源名指定为 /hello
  • 资源名指的是资源的唯一名称,默认就是请求的接口路径(URL),可以自行修改。同一微服务应用内,资源名必须唯一。不同微服务应用之间,资源名可以重复。

Sentinel 整合 OpenFeign

Sentinel 适配了 OpenFeign 组件,如果想使用 Sentinel,除了引入 spring-cloud-starter-alibaba-sentinel 依赖之外,还需要以下两个步骤:

  • 在配置文件里打开 Sentinel 对 OpenFeign 的支持:feign.sentinel.enabled=true
  • 加入 spring-cloud-starter-openfeign 依赖使 Sentinel starter 中的自动配置类生效

2.0、版本说明

本案例使用各开源组件的版本说明如下,其中服务注册中心使用 Nacos,若改为使用 Eureka,只需要在案例里将 Nacos 相关的配置(Maven 依赖 + YAML 配置)替换掉即可,点击下载完整的案例代码

组件版本说明
Spring Boot2.1.18.RELEASE
Spring CloudGreenwich.SR6
Spring Cloud Alibaba2.1.3.RELEASE
Sentinel Dashboard1.8.0
Nacos Server1.4.0

2.1、案例目标

实现 sentinel-consumer 微服务通过 OpenFeign 访问 sentinel-provider 微服务时的流量控制。

2.2、准备工作

启动 Sentinel 控制台应用

1
$ java -Dserver.port=9000 -jar sentinel-dashboard-1.8.0.jar

启动 Nacos Server,并在 Nacos Server 的控制面台里,创建名称为 dev 的命名空间

sentinel-nacos-create-namespace

2.3、创建 Maven 父工程

创建 Maven 父工程,配置好工程需要的父级依赖,目的是为了更方便管理与简化配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.18.RELEASE</version>
</parent>

<properties>
<spring-cloud.version>Greenwich.SR6</spring-cloud.version>
<spring.cloud.alibaba.version>2.1.3.RELEASE</spring.cloud.alibaba.version>
</properties>

<!-- 管理依赖 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<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>

<!-- 利用传递依赖,公共部分 -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>

2.4、创建 Sentinel Provider 工程

引入 Maven 依赖

1
2
3
4
5
6
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>

创建主启动类,添加 @EnableDiscoveryClient 注解,启用服务发现功能,并将服务注册到 Nacos

1
2
3
4
5
6
7
8
@SpringBootApplication
@EnableDiscoveryClient
public class ProviderApplication {

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

创建 Controller 测试类

1
2
3
4
5
6
7
8
9
10
11
@RestController
public class ProviderController {

private Logger LOG = LoggerFactory.getLogger(ProviderController.class);

@GetMapping("/hello")
public String hello() {
LOG.info("provider invoke ... ");
return "Hello Sentinel!";
}
}

创建 application.yml 配置文件,添加 Nacos 注册中心的地址和端口等信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
server:
port: 8080
servlet:
context-path: /provider

spring:
application:
name: sentinel-provider
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
namespace: 4bfcbae8-8c37-417d-89e4-d5134e23eb18
cluster-name: DEFAULT

2.5、创建 Sentinel Consumer 工程

引入 Maven 依赖,包括 spring-cloud-starter-openfeignspring-cloud-starter-alibaba-sentinel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>

创建 Feign Client 的接口类

1
2
3
4
5
6
@FeignClient(value = "sentinel-provider", fallback = FallbackService.class)
public interface FeignAgent {

@GetMapping("/provider/hello")
public String hello();
}

创建处理限流、降级的回调类

1
2
3
4
5
6
7
8
@Component
public class FallbackService implements FeignAgent {

@Override
public String hello() {
return "系统繁忙,请稍候 ...";
}
}

创建主启动类,添加 @EnableDiscoveryClient@EnableFeignClients 注解

1
2
3
4
5
6
7
8
9
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class ConsumerApplication {

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

创建 Controller 测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RestController
public class ConsumerController {

@Autowired
private FeignAgent feignAgent;

private Logger LOG = LoggerFactory.getLogger(ConsumerController.class);

@GetMapping("/hello")
public String hello() {
LOG.info("consumer invoke ... ");
return feignAgent.hello();
}
}

创建 application.yml 配置文件,添加 Nacos 注册中心的地址和端口等信息,并启用 Sentinel 对 OpenFeign 的支持

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
server:
port: 8082
servlet:
context-path: /consumer

spring:
application:
name: sentinel-consumer
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
namespace: 4bfcbae8-8c37-417d-89e4-d5134e23eb18
cluster-name: DEFAULT
sentinel:
transport:
dashboard: 127.0.0.1:9000

# 启用 Sentinel 对 OpenFeign 的支持
feign:
sentinel:
enabled: true

2.6、案例代码测试

提示

  • @FeignClient 注解中的所有属性,Sentinel 都做了兼容。
  • Sentinel 与 Feign 整合时,Feign Client 对应的接口的资源名定义规则为:HTTP请求方式:协议://服务名/请求路径
  • 比如,在上面 FeignAgent 接口中的 hello() 方法对应的资源名为:GET:http://sentinel-provider/provider/hello
  • 1)分别启动 sentinel-consumer、sentinel-provider 应用

  • 2)浏览器访问 http://127.0.0.1:8082/consumer/hello,若响应结果为 Hello Sentinel!,说明两个应用启动成功,同时在 Nacos 的控制台可以看到已经有两个服务注册了,如下图所示:

sentinel-nacos-services

  • 3)浏览器访问 http://127.0.0.1:9000,打开 Sentinel 的控制台,动态添加流控规则,如下图所示:

sentinel-feign-add-flow-rule

  • 4)浏览器再次访问 http://127.0.0.1:8082/consumer/hello,当快速刷新页面时,请求的响应结果变为 系统繁忙,请稍后 ...,则说明 sentinel-consumer 微服务通过 OpenFeign 访问 sentinel-provider 微服务时,Sentinel 的流控规则生效了

Sentinel 整合 Gateway

Sentinel 支持对 Spring Cloud Gateway、Zuul 1.x、Zuul 2.x 等主流的 API Gateway 进行限流。从 1.6.0 版本开始,Sentinel 提供了 Spring Cloud Gateway 的适配模块,可以提供两种资源维度的限流:

  • Route 维度:即在 Spring 配置文件中配置的 Gateway 路由条目,资源名为对应的 routeId
  • 自定义 API 分组维度:用户可以利用 Sentinel 提供的 API 来自定义一些 API 分组

3.0、版本说明

组件版本说明
Spring Boot2.1.18.RELEASE
Spring CloudGreenwich.SR6
Spring Cloud Alibaba Sentinel2.1.3.RELEASE
Spring Cloud Alibaba Nacos Config2.1.3.RELEASE
Nacos Server1.4.0
Sentinel Dashboard1.8.0

3.1、案例说明

本案例是在上述 Sentinel 整合 OpenFeign 案例的基础上开发的,注册中心依旧使用 Nacos,其中主要的变化是新创建了 sentinel-gateway 工程,因此下面只给出新增或者更改后的代码和配置,点击下载完整的案例代码。

3.2、案例目标

本案例主要实现 sentinel-gateway 微服务将请求转发给 sentinel-consumer 微服务时的流量控制,其中 sentinel-consumer 微服务通过 OpenFeign 访问 sentinel-provider 微服务时的流量控制在上述 Sentinel 整合 OpenFeign 案例已经实现了,这里不再累述,完整的调用流程为 sentinel-gateway –> sentinel-consumer –> sentinel-provider。

3.3、准备工作

启动 Sentinel 控制台

1
$ java -Dserver.port=9000 -jar sentinel-dashboard-1.8.0.jar

启动 Nacos Server,并在 Nacos Server 的控制面台里,创建名称为 dev 的命名空间

sentinel-nacos-create-namespace

3.4、创建 Sentinel Gateway 工程

引入 Maven 依赖,其中 spring-cloud-alibaba-sentinel-gateway 模块用于 Sentinel 适配 Gateway

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>

创建 Gateway 的配置类,用于定义被限流或者降级时处理的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Configuration
public class GatewayConfiguration {

/**
* 初始化
*/
@PostConstruct
public void init() {
// 设置被限流或者降级处理时的回调方法
GatewayCallbackManager.setBlockHandler(new BlockRequestHandler() {

// 被限流或者降级时处理的方法
@Override
public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
return ServerResponse.status(200).syncBody("系统繁忙,请稍后 ...");
}
});
}
}

创建主启动类,添加 @EnableDiscoveryClient 注解

1
2
3
4
5
6
7
8
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {

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

创建 application.yml 配置文件,由于这里指定了 context-path,因此在路由规则配置中需要使用 StripPrefix 参数将访问进来的 URL 中的 context-path 截取掉,否则 sentinel-gateway 微服务访问 sentinel-consumer 微服务时,会出现 404 错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
server:
port: 8083
servlet:
context-path: gateway

spring:
application:
name: sentinel-gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
namespace: 4bfcbae8-8c37-417d-89e4-d5134e23eb18
cluster-name: DEFAULT
sentinel:
transport:
dashboard: 127.0.0.1:9000
gateway:
routes:
- id: sentinel-gateway-route
uri: lb://sentinel-consumer
predicates:
- Path=/${server.servlet.context-path}/consumer/hello/**
filters:
- StripPrefix=1

若在 application.yml 配置文件里没有配置 context-path,那么路由规则配置可以使用以下的写法:

1
2
3
4
5
6
7
8
9
10
11
server:
port: 8083

spring:
cloud:
gateway:
routes:
- id: sentinel-gateway-route
uri: lb://sentinel-consumer
predicates:
- Path=/consumer/hello/**

3.5、案例代码测试

  • 1)分别启动 sentinel-gateway、sentinel-consumer、sentinel-provider 应用
  • 2)浏览器访问 http://127.0.0.1:8083/gateway/consumer/hello,若响应结果为 Hello Sentinel!,说明三个应用启动成功,同时在 Nacos 的控制台可以看到已经有三个服务注册了,如下图所示:

sentinel-gatway-services

  • 3)这里让 Sentinel 基于 Route 维度进行网关限流,浏览器访问 http://127.0.0.1:9000,打开 Sentinel 的控制台,在 sentinel-gateway 服务里动态添加网关流控规则,其中 API 名称就是 application.yml 配置文件里的路由 ID,如下图所示:

sentinel-gateway-add-flow-rule

  • 4)浏览器再次访问 http://127.0.0.1:8083/gateway/consumer/hello,当快速刷新页面时,请求的响应结果变为 系统繁忙,请稍后 ...,则说明 sentinel-gateway 微服务访问 sentinel-consumer 微服务时,Sentinel 的网关流控规则生效了

3.6、使用自定义 API 进行限流

  • 1)在 Sentinel 控制台里,删除所有与 sentinel-gateway 应用相关的网关流控规则

  • 2)在 Sentinel 控制台的菜单栏里找到 sentinel-gatway -> API 管理 -> 新增 API 分组,由于上面在 application.yml 配置文件中指定了 context-path,因此表单里的” 匹配串” 为 /gateway/consumer/hello/**,” 匹配模式” 选择 前缀

sentinel-gateway-add-api

sentinel-gateway-add-api-2

  • 3)在 Sentinel 控制台的菜单栏里找到 sentinel-gatway -> 流控规则 -> 新增网关流控规则,在表单里的 “API 类型” 选择 API 分组,”API 名称” 选择刚刚创建的 API 即可

sentinel-gateway-api-add-flow-rule

  • 4)浏览器访问 http://127.0.0.1:8083/gateway/consumer/hello,当快速刷新页面时,请求的响应结果变为 系统繁忙,请稍后 ...,则说明 sentinel-gateway 微服务访问 sentinel-consumer 微服务时,Sentinel 使用自定义 API 成功对网关进行限流了

参考博客