Reminance's Studio.

sentinel 简单使用

字数统计: 3k阅读时长: 12 min
2020/12/23 Share

@TOC

sentinel 简单使用

Sentinel 介绍

随着微服务的流行,服务和服务之间的稳定性变得越来越重要。 Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。

Sentinel 具有以下特征:

  • 丰富的应用场景: Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、实时熔断下游不可用应用等。
  • 完备的实时监控: Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
  • 广泛的开源生态: Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
  • 完善的 SPI 扩展点: Sentinel 提供简单易用、完善的 SPI 扩展点。您可以通过实现扩展点,快速的定制逻辑。例如定制规则管理、适配数据源等。

文档

中文文档
dashboard控制台
主流框架的适配#spring-cloud
在生产环境中使用-Sentinel
拦截/秒级监控/业务/集群限流日志

如何使用 Sentinel(springboot)

dashboard 安装

获取 Sentinel 控制台

您可以从 release 页面 下载最新版本的控制台 jar 包。

您也可以从最新版本的源码自行构建 Sentinel 控制台:

  • 下载 控制台 工程
  • 使用以下命令将代码打包成一个 fat jar:
    1
    mvn clean package

dashboard 启动

注意:启动 Sentinel 控制台需要 JDK 版本为 1.8 及以上版本。

Sentinel 控制台是一个标准的 Spring Boot 应用,以 Spring Boot 的方式运行 jar 包即可。
使用如下命令启动控制台:

1
2
3
4
java -Dserver.port=8080 \
-Dcsp.sentinel.dashboard.server=localhost:8080 \
-Dproject.name=sentinel-dashboard \
-jar target/sentinel-dashboard.jar

上述命令中我们指定几个 JVM 参数,其中 -Dserver.port=8080 是 Spring Boot 的参数,
用于指定 Spring Boot 服务端启动端口为 8080。其余几个是 Sentinel 客户端的参数。

为便于演示,我们对控制台本身加入了流量控制功能,具体做法是引入 Sentinel 提供的 CommonFilter 这个 Servlet Filter。
上述 JVM 参数的含义是:

参数 作用
-Dcsp.sentinel.dashboard.server=localhost:8080 向 Sentinel 接入端指定控制台的地址
-Dproject.name=sentinel-dashboard 向 Sentinel 指定应用名称,比如上面对应的应用名称就为 sentinel-dashboard

全部的配置项可以参考 启动配置项文档

经过上述配置,控制台启动后会自动向自己发送心跳。程序启动后浏览器访问 localhost:8080 即可访问 Sentinel 控制台。

从 Sentinel 1.6.0 开始,Sentinel 控制台支持简单的登录功能,默认用户名和密码都是 sentinel。用户可以通过如下参数进行配置:

  • -Dsentinel.dashboard.auth.username=sentinel 用于指定控制台的登录用户名为 sentinel
  • -Dsentinel.dashboard.auth.password=123456 用于指定控制台的登录密码为 123456;如果省略这两个参数,默认用户和密码均为 sentinel
  • -Dserver.servlet.session.timeout=7200 用于指定 Spring Boot 服务端 session 的过期时间,如 7200 表示 7200 秒;60m 表示 60 分钟,默认为 30 分钟;

注:若您的应用为 Spring Boot 或 Spring Cloud 应用,您可以通过 Spring 配置文件来指定配置,详情请参考 Spring Cloud Alibaba Sentinel 文档。

springboot应用接入

1. pom.xml
1
2
3
4
5
6
7
8
9
10
11
      <dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>2.2.3.RELEASE</version>
</dependency>
<!-- 使用zk作为规则持久化 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-zookeeper</artifactId>
<version>1.8.0</version>
</dependency>
2. 配置控制台信息

这里的spring.cloud.sentinel.transport.port 端口配置会在应用对应的机器上启动一个 Http Server,该 Server 会与 Sentinel 控制台做交互。比如 Sentinel 控制台添加了一个限流规则,会把规则数据 push 给这个 Http Server 接收,Http Server 再将规则注册到 Sentinel 中。

1
2
3
4
5
6
7
application.yml
spring:
cloud:
sentinel:
transport:
port: 8719
dashboard: localhost:8080
3. 配置sentinel resource

@SentinelResource 注解

注意:注解方式埋点不支持 private 方法。

@SentinelResource 用于定义资源,并提供可选的异常处理和 fallback 配置项。 @SentinelResource 注解包含以下属性:

  • value:资源名称,必需项(不能为空)
  • entryType:entry 类型,可选项(默认为 EntryType.OUT
  • blockHandler / blockHandlerClass: blockHandler 对应处理 BlockException 的函数名称,可选项。blockHandler 函数访问范围需要是 public,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException。blockHandler 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 blockHandlerClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
  • fallback / fallbackClass:fallback 函数名称,可选项,用于在抛出异常的时候提供 fallback 处理逻辑。fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。fallback 函数签名和位置要求:
    • 返回值类型必须与原函数返回值类型一致;
    • 方法参数列表需要和原函数一致,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。
    • fallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
  • defaultFallback(since 1.6.0):默认的 fallback 函数名称,可选项,通常用于通用的 fallback 逻辑(即可以用于很多服务或方法)。默认 fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。若同时配置了 fallback 和 defaultFallback,则只有 fallback 会生效。defaultFallback 函数签名要求:
    • 返回值类型必须与原函数返回值类型一致;
    • 方法参数列表需要为空,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。
    • defaultFallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
  • exceptionsToIgnore(since 1.6.0):用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。

1.8.0 版本开始,defaultFallback 支持在类级别进行配置。

注:1.6.0 之前的版本 fallback 函数只针对降级异常(DegradeException)进行处理,不能针对业务异常进行处理。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    @GetMapping("/version")
@ApiOperation(value = "version")
// @SentinelResource(value = "version", blockHandler = "handleException", blockHandlerClass = {ExceptionUtil.class})
@SentinelResource(value = "version", blockHandler = "versionBlock", fallback = "versionFallback")
public Integer version() {
// if (new Random().nextInt() % 2 == 0) {
// log.error("随机异常");
// throw new ProcessException("随机异常");
// }
return 11;
}

// Fallback 函数,函数签名与原函数一致或加一个 Throwable 类型的参数.
public Integer versionFallback() {
System.out.println("versionFallback");
return 0;
}

// Block 异常处理函数,参数最后多一个 BlockException,其余与原函数一致.
public Integer versionBlock(BlockException ex) {
// Do some log here.
ex.printStackTrace();
return 0;
}
4. DataSource 扩展

推荐通过控制台设置规则后将规则推送到统一的规则中心,客户端实现 ReadableDataSource 接口端监听规则中心实时获取变更

DataSource 扩展常见的实现方式有:

  • 拉模式:客户端主动向某个规则管理中心定期轮询拉取规则,这个规则中心可以是 RDBMS、文件,甚至是 VCS 等。这样做的方式是简单,缺点是无法及时获取变更;
  • 推模式:规则中心统一推送,客户端通过注册监听器的方式时刻监听变化,比如使用 Nacos、Zookeeper 等配置中心。这种方式有更好的实时性和一致性保证。
    Sentinel 目前支持以下数据源扩展:

Pull-based: 动态文件数据源、Consul, Eureka
Push-based: ZooKeeper, Redis, Nacos, Apollo, etcd

注册数据源
借助 Sentinel 的 InitFunc SPI 扩展接口。只需要实现自己的 InitFunc 接口,在 init 方法中编写注册数据源的逻辑。比如:

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
package com.queen.shop.order.controller.api;

import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
import com.alibaba.csp.sentinel.datasource.zookeeper.ZookeeperDataSource;
import com.alibaba.csp.sentinel.init.InitFunc;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.queen.shop.common.util.JsonUtil;

import java.util.List;

public class DataSourceInitFunc implements InitFunc {

@Override
public void init() throws Exception {
// 引入groupId和dataId的概念,是为了方便和Nacos进行切换
// 规则会持久化到zk的/groupId/flowDataId节点
// groupId和和flowDataId可以用/开头也可以不用
// 建议不用以/开头,目的是为了如果从Zookeeper切换到Nacos的话,只需要改数据源类名就可以
final String groupId = "sentinel_rules/shop-api";
final String dataId = "rest-api-flow";
final String remoteAddress = "127.0.0.1:2181";

ReadableDataSource<String, List<FlowRule>> flowRuleDataSource = new ZookeeperDataSource<>(remoteAddress, groupId, dataId,
source -> JsonUtil.toObject(source, List.class, FlowRule.class));
FlowRuleManager.register2Property(flowRuleDataSource.getProperty());
}
}

接着将对应的类名添加到位于资源目录(通常是 resource 目录)下的 META-INF/services 目录下的 com.alibaba.csp.sentinel.init.InitFunc 文件中,比如:

1
com.queen.shop.order.controller.api.DataSourceInitFunc

这样,当初次访问任意资源的时候,Sentinel 就可以自动去注册对应的数据源了。

测试添加流控规则
com.queen.shop.order.controller.api.ZookeeperConfigSender

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
package com.queen.shop.order.controller.api;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;

/**
* Zookeeper config sender for demo
*
* @author guonanjun
*/
public class ZookeeperConfigSender {

private static final int RETRY_TIMES = 3;
private static final int SLEEP_TIME = 1000;

public static void main(String[] args) throws Exception {
final String remoteAddress = "localhost:2181";

final String groupId = "sentinel_rules/shop-api";
final String dataId = "rest-api-flow";
final String rule = "[\n"
+ " {\n"
+ " \"resource\": \"version\",\n"
+ " \"controlBehavior\": 0,\n"
+ " \"count\": 2.0,\n"
+ " \"grade\": 1,\n"
+ " \"limitApp\": \"default\",\n"
+ " \"strategy\": 0\n"
+ " }\n"
+ "]";


CuratorFramework zkClient = CuratorFrameworkFactory.newClient(remoteAddress, new ExponentialBackoffRetry(SLEEP_TIME, RETRY_TIMES));
zkClient.start();
String path = getPath(groupId, dataId);
Stat stat = zkClient.checkExists().forPath(path);
if (stat == null) {
zkClient.create().creatingParentContainersIfNeeded().withMode(CreateMode.PERSISTENT).forPath(path, null);
}
zkClient.setData().forPath(path, rule.getBytes());

try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}

zkClient.close();
}

private static String getPath(String groupId, String dataId) {
String path = "";
if (groupId.startsWith("/")) {
path += groupId;
} else {
path += "/" + groupId;
}
if (dataId.startsWith("/")) {
path += dataId;
} else {
path += "/" + dataId;
}
return path;
}
}

或者使用zkCli设置:

1
2
3
4
ls /sentinel_rules/shop-api/rest-api-flow
stat /sentinel_rules/shop-api/rest-api-flow
get /sentinel_rules/shop-api/rest-api-flow
set /sentinel_rules/shop-api/rest-api-flow [{"resource":"version","controlBehavior":0,"count":2.0,"grade":1,"limitApp":"default","strategy":0}]

其他支持

CATALOG
  1. 1. sentinel 简单使用
    1. 1.1. Sentinel 介绍
    2. 1.2. 文档
    3. 1.3. 如何使用 Sentinel(springboot)
      1. 1.3.1. dashboard 安装
        1. 1.3.1.1. 获取 Sentinel 控制台
      2. 1.3.2. dashboard 启动
      3. 1.3.3. springboot应用接入
        1. 1.3.3.0.1. 1. pom.xml
        2. 1.3.3.0.2. 2. 配置控制台信息
        3. 1.3.3.0.3. 3. 配置sentinel resource
      4. 1.3.3.1. 4. DataSource 扩展
  2. 1.4. 其他支持