Sentinel

 ·  ☕ 13  · 👀...

介绍

技术 特性 适用场景 说明
Sentinel - 基于信号量隔离
- 基于失败比率的熔断降级
- 基于QPS,支持调用关系的限流
- 支持秒级实时监控
- 分布式系统限流
- 熔断
- 多语言支持(Java、C++、Golang)
- 注解支持
- 介绍
- Github
- Wiki
- Guideline: 从 Hystrix 迁移到 Sentinel
- Sentinel-Dashboard
AHAS Sentinel 控制台 AHAS Sentinel 控制台 是 Sentinel 控制台的阿里云上版本,提供企业级的控制台服务,包括:可靠的实时监控和历史监控数据查询,无需自行存储、拉取动态规则管理/推送,无需自行配置外部数据源实时请求链路查看。若您已是 Sentinel 用户并接入了 开源 Sentinel 控制台,您只需替换一下依赖即可快速接入到 AHAS Sentinel 控制台。同样您也可以快速从云上控制台切换到开源控制台。
- 官网
- Doc
- GithubDoc

基本概念

说明
限流 利用某种规则,限制访问的速率,以达到保护某些资源的目的。
熔断
降级 -
热点 即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。

定义资源

抛出异常方式定义资源

1
2
3
4
5
6
7
try (Entry entry = SphU.entry("resourceName")) {
  // 被保护的业务逻辑
  // do something here...
} catch (BlockException ex) {
  // 资源访问阻止,被限流或被降级
  // 在此处进行相应的处理操作
}

返回布尔值方式定义资源

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// 资源名可使用任意有业务语义的字符串
  if (SphO.entry("自定义资源名")) {
    // 务必保证finally会被执行
    try {
      /**
      * 被保护的业务逻辑
      */
    } finally {
      SphO.exit();
    }
  } else {
    // 资源访问阻止,被限流或被降级
    // 进行相应的处理操作
  }

注解方式定义资源(推荐)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// 原本的业务方法.
@SentinelResource(blockHandler = "blockHandlerForGetUser")
public User getUserById(String id) {
    throw new RuntimeException("getUserById command failed");
}

// blockHandler 函数,原方法调用被限流/降级/系统保护的时候调用
public User blockHandlerForGetUser(String id, BlockException ex) {
    return new User("admin");
}
属性 说明
value 资源名称。
必需项。
entryType entry 类型。
可选项(默认为 EntryType.OUT)
blockHandler 对应处理 BlockException 的函数名称,可选项。
blockHandlerClass blockHandler 函数访问范围需要是 public,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException。blockHandler 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 blockHandlerClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
fallback fallback 函数名称,可选项,用于在抛出异常的时候提供 fallback 处理逻辑。
defaultFallback (since 1.6.0)默认的 fallback 函数名称,可选项,通常用于通用的 fallback 逻辑(即可以用于很多服务或方法)。
exceptionsToIgnore (since 1.6.0)用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。

规则

规则类型

类名 中文名称 说明
AuthorityRule 访问控制规则 根据资源的请求来源(origin)的黑、白名单机制的进行限流的规则
DegradeRule 熔断降级规则 根据 平均响应时间 或 异常比例降级的规则
FlowRule 流量控制规则 根据 QPS 或 线程数 的阈值 的进行限流的规则
ParamFlowRule 热点参数规则 根据 热点参数 进行限流的规则
SystemRule 系统保护规则 根据 最大负载、入口流量的平均响应时间、入口流量的最大并发数、入口资源的QPS 等进行流量控制

规则继承关系

-- Rule
---- AbstractRule
-------- AuthorityRule        ---- AuthorityRuleManager
-------- DegradeRule          ---- DegradeRuleManager
-------- FlowRule             ---- FlowRuleManager
-------- ParamFlowRule        ---- ParamFlowRuleManager
-------- SystemRule           ---- SystemRuleManager

规则类型及参数说明

访问控制规则(AuthorityRule)

说明
resource 资源名,即限流规则的作用对象
limitApp 对应的黑名单/白名单,不同 origin 用 “,” 分割,如:
appA,appB
stategy 限制模式。
AUTHORITY_WHITE 为白名单模式
AUTHORITY_BLACK 为黑名单模式
默认为白名单模式

熔断降级规则(DegradeRule)

说明
resource 资源名,即限流规则的作用对象
count 阈值
grade 降级模式。
DEGRADE_GRADE_RT:平均响应时间。
DEGRADE_GRADE_EXCEPTION_RATIO:异常比例,取值:0~1。
默认值:DEGRADE_GRADE_RT
timeWindow 降级的时间,单位为秒

同一个资源可以同时有多个降级规则。

流量控制规则(FlowRule)

说明
resource 资源名,资源名是限流规则的作用对象
count 限流阈值
grade 限流阈值类型,QPS 或线程数模式。
默认值:QPS
limitAPP 流控针对的调用来源。
默认值:default,代表不区分调用来源
stategy 判断的根据是资源自身,还是根据其它关联资源(refResource),还是根据链路入口。
默认值:根据资源本身
controlBehavior 流控效果(直接拒绝/排队等待/慢启动模式)。
默认值:直接拒绝

同一个资源可以同时有多个限流规则。

热点参数规则(ParamFlowRule)

热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。

系统保护规则(SystemRule)

Sentinel 系统自适应限流从整体维度对应用入口流量进行控制,结合应用的 Load总体平均 RT入口 QPS线程数等几个维度的监控指标,让系统的入口流量和系统的复杂达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。

加载限流规则

从 代码 加载限流规则

pom.xml

1
2
3
4
5
6
<!-- 配置 Sentinel -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    <version>2.1.0.RELEASE</version>
</dependency>

SentinelController

 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
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.wanglibing.demo11.utils.SentinelBlock;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class SentinelController {

    @GetMapping("/sentinel")
    /**
     * 使用 @SentinelResource 注解定义资源
     */
    @SentinelResource(value = "sentinelResource",blockHandler = "sentinelBlock")
    public String getResult(){
        return "Hello,wanglibing";
    }

    public String sentinelBlock(BlockException blockException){
        return "类内部的服务限流"+blockException.getRule();
    }

    @GetMapping("/sentinel1")
    /**
     * 使用 @SentinelResource 注解定义资源
     */
    @SentinelResource(value = "sentinelResource",blockHandler = "sentinelBlockUtils",blockHandlerClass = SentinelBlock.class)
    public String getResult1(){
        return "Hello,从外部文件中加载限流规则";
    }
}

SentinelBlock

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import com.alibaba.csp.sentinel.slots.block.BlockException;

public class SentinelBlock {
    /**
     * 回调方法
     * 注意:这里的方法必须为 static 类型
     * @param blockException
     * @return
     */
    public static String sentinelBlockUtils(BlockException blockException){
        return "Utils中的服务限流"+blockException.getRule();
    }
}

SentinelConfig

 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
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.google.common.collect.Lists;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
public class SentinelConfig implements CommandLineRunner {
    /**
     * 初始化规则
     */
    public void initRules(){
        // 定义 FlowRole
        FlowRule flowRule = new FlowRule();
        // 设定资源
        flowRule.setResource("sentinelResource");
        // 设定阈值为1(默认类型为QPS)
        flowRule.setCount(1);

        //将 FlowRule 加载到内存中
        FlowRuleManager.loadRules(Lists.newArrayList(flowRule));
        System.out.println("加载限流规则成功");
    }

    @Override
    public void run(String... args) throws Exception {
        initRules();
    }
}

从 本地文件 加载限流规则

pom.xml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
<!-- 配置 Sentinel -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    <version>2.1.0.RELEASE</version>
</dependency>

<!-- 拉模式:使用文件配置规则-->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-extension</artifactId>
    <version>1.6.3</version>
</dependency>

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-context</artifactId>
    <version>2.1.3.RELEASE</version>
</dependency>

SentinelController

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class SentinelController {

    @GetMapping("/sentinel")
    /**
     * 使用 @SentinelResource 注解定义资源
     */
    @SentinelResource(value = "sentinelResource",blockHandler = "sentinelBlock")
    public String getResult(){
        return "Hello,wanglibing";
    }

    public String sentinelBlock(BlockException blockException){
        return "类内部的服务限流"+blockException.getRule();
    }
}

bootstrap.yml

1
2
3
4
5
6
7
8
9
spring:
  cloud:
    sentinel:
      datasource:
        ds1:
          file:
            file: 'classpath: flow-rule.json'
            data-type: json
            rule-type: flow

flow-rule.json

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[
  {
    "resource": "sentinelResource",
    "controlBehavior": 0,
    "count": 1,
    "grade": 1,
    "limitApp": "default",
    "strategy": 0
  }
]

从 Nacos 加载限流规则

配置 pom.xml

1
2
3
4
5
<!-- 使用 Nacos 保存限流规则-->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

配置 bootstrap.yml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
spring:
  application:
    name: demo13
  cloud:
    sentinel:
      datasource:
        ds:
          nacos:
            server-addr: nacos:8848
            dataId: ${spring.application.name}-sentinel
            groupId: DEFAULT_GROUP
            rule-type: flow

配置nacos

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Data ID:demo13-sentinel
# Group:DEFAULT_GROUP
# 配置格式:JSON
# 配置内容:如下所示:
[
    {
        "resource": "/log",
        "limitApp": "default",
        "grade": 1,
        "count": 5,
        "strategy": 0,
        "controlBehavior": 0,
        "clusterMode": false
    }
]

# resource:        资源名,即限流规则的作用对象
# limitApp:        流控针对的调用来源,若为 default 则不区分调用来源
# grade:           限流阈值类型(QPS 或并发线程数);0代表根据并发数量来限流,1代表根据QPS来进行流量控制
# count:           限流阈值
# strategy:        调用关系限流策略
# controlBehavior: 流量控制效果(直接拒绝、Warm Up、匀速排队)
# clusterMode:     是否为集群模式

控制台

启动控制台

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 下载
$ wget https://github.com/alibaba/Sentinel/releases/download/1.6.3/sentinel-dashboard-1.6.3.jar

# 启动
$ java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.6.3.jar
## 指定控制台的登陆用户名为 sentinel。
## 默认用户名:sentinel
$ java -Dsentinel.dashboard.auth.username=sentinel

## 指定控制台的登录密码为 123456
## 默认登陆密码:123456
$ java -Dsentinel.dashboard.auth.password=123456

## 指定 Spring Boot 服务端 session 的过期时间,如:
## 7200 表示 7200 秒;
## 60m 表示 60 分钟
## 默认为 30 分钟;
$ java -Dserver.servlet.session.timeout=7200

# 登陆控制台
## 地址:http://localhost:8080
## 用户名:sentinel
## 密码:sentinel

与控制台集成示例

1
2
3
4
5
6
spring:
  cloud:
    sentinel:
      transport:
        # 配置控制台
        dashboard: localhost:8080

配置项说明

基础配置项

名称 说明 类型 默认值
project.name 指定应用的名称 String null
csp.sentinel.app.type 指定应用的类型 int 0 (APP_TYPE_COMMON)
csp.sentinel.metric.file.single.size 单个监控日志文件的大小 long 52428800 (50MB)
csp.sentinel.metric.file.total.count 监控日志文件的总数上限 int
csp.sentinel.statistic.max.rt 最大的有效响应时长(ms),超出此值则按照此值记录 int 4900
csp.sentinel.spi.classloader SPI 加载时使用的 ClassLoader,默认为给定类的 ClassLoader String default

日志相关配置项

名称 说明 类型 默认值
csp.sentinel.log.dir Sentinel 日志文件目录 String ${user.home}/logs/csp/
csp.sentinel.log.use.pid 日志文件名中是否加入进程号,用于单机部署多个应用的情况 boolean false
csp.sentinel.log.output.type Record 日志输出的类型,file 代表输出至文件,console 代表输出至终端 String file
1
2
3
# 注意:若需要在单台机器上运行相同服务的多个实例,则需要加入 
-Dcsp.sentinel.log.use.pid=true 
# 来保证不同实例日志的独立性。

sentinel-transport-common 的配置项

名称 说明 类型 默认值
csp.sentinel.dashboard.server (必需项)控制台的地址,指定控制台后客户端会自动向该地址发送心跳包。地址格式为:hostIp:port String null
csp.sentinel.heartbeat.interval.ms 心跳包发送周期,单位毫秒 long null

Sentinel Dashboard中修改规则同步到Nacos

修改pom.xml

1
2
3
4
5
6
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
    <!-- 注释掉这里 -->
    <!--<scope>test</scope>-->
</dependency>

修改前端

webapp/resources/app/scripts/directives/sidebar/sidebar.html 中

1
2
3
4
5
<li ui-sref-active="active">
    <a ui-sref="dashboard.flowV1({app: entry.app})">
        <i class="glyphicon glyphicon-filter"></i>&nbsp;&nbsp;流控规则
    </a>
</li>

修改为:

1
2
3
4
5
<li ui-sref-active="active">
    <a ui-sref="dashboard.flow({app: entry.app})">
        <i class="glyphicon glyphicon-filter"></i>&nbsp;&nbsp;流控规则
    </a>
</li>

创建Nacos的配置类

 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
//com.alibaba.csp.sentinel.dashboard.rule
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.config.ConfigFactory;
import com.alibaba.nacos.api.config.ConfigService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.List;
import java.util.Properties;

@Configuration
public class NacosConfig {

    @Bean
    public Converter<List<FlowRuleEntity>, String> flowRuleEntityEncoder() {
        return JSON::toJSONString;
    }

    @Bean
    public Converter<String, List<FlowRuleEntity>> flowRuleEntityDecoder() {
        return s -> JSON.parseArray(s, FlowRuleEntity.class);
    }

    @Bean
    public ConfigService nacosConfigService() throws Exception {
        Properties properties = new Properties();
        properties.put(PropertyKeyConst.SERVER_ADDR, "localhost");
        return ConfigFactory.createConfigService(properties);
    }
}
//如果用到了namespace隔离环境,可以在nacosConfigService方法中再加入配置,比如:
//properties.put(PropertyKeyConst.NAMESPACE, "130e71fa-97fe-467d-ad77-967456f2c16d");

实现Nacos的配置拉取

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
@Component("flowRuleNacosProvider")
public class FlowRuleNacosProvider implements DynamicRuleProvider<List<FlowRuleEntity>> {

    @Autowired
    private ConfigService configService;
    @Autowired
    private Converter<String, List<FlowRuleEntity>> converter;

    public static final String FLOW_DATA_ID_POSTFIX = "-sentinel";
    public static final String GROUP_ID = "DEFAULT_GROUP";

    @Override
    public List<FlowRuleEntity> getRules(String appName) throws Exception {
        String rules = configService.getConfig(appName + FLOW_DATA_ID_POSTFIX, GROUP_ID, 3000);
        if (StringUtil.isEmpty(rules)) {
            return new ArrayList<>();
        }
        return converter.convert(rules);
    }
}

实现Nacos的配置推送

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
@Component("flowRuleNacosPublisher")
public class FlowRuleNacosPublisher implements DynamicRulePublisher<List<FlowRuleEntity>> {

    @Autowired
    private ConfigService configService;
    @Autowired
    private Converter<List<FlowRuleEntity>, String> converter;

    public static final String FLOW_DATA_ID_POSTFIX = "-sentinel";
    public static final String GROUP_ID = "DEFAULT_GROUP";

    @Override
    public void publish(String app, List<FlowRuleEntity> rules) throws Exception {
        AssertUtil.notEmpty(app, "app name cannot be empty");
        if (rules == null) {
            return;
        }
        configService.publishConfig(app + FLOW_DATA_ID_POSTFIX, GROUP_ID, converter.convert(rules));
    }
}

修改 Controller

1
2
3
4
5
6
7
//com.alibaba.csp.sentinel.dashboard.controller.v2.FlowControllerV2
@Autowired
@Qualifier("flowRuleNacosProvider")
private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
@Autowired
@Qualifier("flowRuleNacosPublisher")
private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;

AHAS Sentinel 控制台

启动

1
$ java -Dproject.name=<AppName> -Dahas.license=<License>

pom.xml

应用程序

1
2
3
4
5
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-transport-simple-http</artifactId>
    <version>1.6.3</version>
</dependency>

Spring Cloud Gateway

1
2
3
4
5
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>spring-cloud-gateway-starter-ahas-sentinel</artifactId>
    <version>1.0.1</version>
</dependency>

application.properties

# 指定您要接入的特定的 AHAS 环境
ahas.namespace=default
# 自定义您的应用名称,例如 spring-cloud-gateway
project.name=spring-cloud-gateway
# 通过公网地域接入时,需要您的证书信息;其他地域不需要证书。
# 证书获取方式:
# 在 AHAS 控制台左侧导航栏,选择流控降级 > 网关流控,
# 选择右上角网关接入,在配置启动参数页签下,找到您的证书信息。
ahas.license=xxx

应用接入

https://ahas.console.aliyun.com/
左侧 【流控降级】->【应用流控】

网关接入

https://ahas.console.aliyun.com/
左侧
【流控降级】->【网关流控】

配置项说明

名称 说明 类型 默认值
csp.sentinel.dashboard.server - 必填项
控制台的地址,指定控制台后客户端会自动向该地址发送心跳包。地址格式为:hostIp:port
String null
csp.sentinel.heartbeat.interval.ms 心跳包发送周期,单位毫秒 long null
csp.sentinel.api.port 本地启动 HTTP API Server 的端口号 int 8719

DataSource扩展

接口或抽象类

说明 应用场景
ReadableDataSource 接口 从内存或其它数据源读取规则 扩展数据源
WritableDataSource 接口 将规则写入内存或其它数据源 扩展数据源
AutoRefreshDataSource 抽象类 客户端主动向某个规则管理中心定期轮询拉取规则 - pull 模式拓展
- 不保证一致性
- 不保证实时性
- 拉取过于频繁会有性能问题
AbstractDataSource 抽象类 规则中心统一推送,客户端通过注册监听器的方式时刻监听变化,比如使用 Nacos、Zookeeper 等配置中心。 - push 模式拓展
- 生产环境推荐使用

注册数据源

方法一

1
2
3
//通过手动注册数据源的方式,将数据源注册至指定的规则管理器中
ReadableDataSource<String, List<FlowRule>> flowRuleDataSource = new NacosDataSource<>(remoteAddress, groupId, dataId, parser);
FlowRuleManager.register2Property(flowRuleDataSource.getProperty());

方法二

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
//借助 Sentinel 的 InitFunc SPI 扩展接口
package com.test.init;

public class DataSourceInitFunc implements InitFunc {

    @Override
    public void init() throws Exception {
        final String remoteAddress = "localhost";
        final String groupId = "Sentinel:Demo";
        final String dataId = "com.alibaba.csp.sentinel.demo.flow.rule";

        ReadableDataSource<String, List<FlowRule>> flowRuleDataSource = new NacosDataSource<>(remoteAddress, groupId, dataId,
            source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {}));
        FlowRuleManager.register2Property(flowRuleDataSource.getProperty());
    }
}

日志

 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
# 日志类型:秒级拦截详情日志
# 存储路径:{user_home}/logs/csp/sentinel-block.log
# 格式:
2014-06-20 16:35:10|1|sayHello(java.lang.String,long),FlowException,default,origin|61,0
2014-06-20 16:35:11|1|sayHello(java.lang.String,long),FlowException,default,origin|1,0
## 2014-06-20 16:35:10:             时间戳;
## 1:                               序号;
## sayHello(java.lang.String,long): 资源描述符;
## XXXException:表示被限制的种类。     FlowException 表示被限流,DegradeException 表示被降级,SystemException 表示被系统保护
## default:                         规则上配置的限制应用;
## origin:                          实际被限制的来源应用,可能为空字符串;
## 61,0:                            61 代表这一秒内限流降级发生的次数,0 无含义(可忽略)。

# 日志类型:秒级监控日志
# 存储路径:${user_home}/logs/csp/${app_name}-${pid}-metrics.log
# 格式:
1532415661000|2018-07-24 15:01:01|sayHello(java.lang.String)|12|3|4|2|295
## 1532415661000:             时间戳
## 2018-07-24 15:01:01:       格式化之后的时间戳
## sayHello(java.lang.String):资源名
## 12:                        表示到来的数量,即此刻通过 Sentinel 规则 check 的数量(passed QPS)
## 3:                         实际该资源被拦截的数量(blocked QPS)
## 4:                         每秒结束的资源个数(完成调用),包括正常结束和异常结束的情况(exit QPS)
## 2:                         异常的数量
## 295:                       资源的平均响应时间(RT)

# 日志类型:业务日志
# 存储路径:{user_home}/logs/csp/sentinel-record.log.xxx
# 存储内容:规则的推送、接收、处理等记录

主流框架适配

Web Servlet

pom.xml

1
2
3
4
5
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-web-servlet</artifactId>
    <version>x.y.z</version>
</dependency>

web.xml

1
2
3
4
5
6
7
8
9
<filter>
	<filter-name>SentinelCommonFilter</filter-name>
	<filter-class>com.alibaba.csp.sentinel.adapter.servlet.CommonFilter</filter-class>
</filter>

<filter-mapping>
	<filter-name>SentinelCommonFilter</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

FilterConfig

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

    @Bean
    public FilterRegistrationBean sentinelFilterRegistration() {
        FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new CommonFilter());
        registration.addUrlPatterns("/*");
        registration.setName("sentinelFilter");
        registration.setOrder(1);

        return registration;
    }
}

Dubbo

pom.xml( 大于等于 Dubbo 2.7.x )

1
2
3
4
5
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-apache-dubbo-adapter</artifactId>
    <version>x.y.z</version>
</dependency>

pom.xml( 小于等于 Dubbo 2.6.x )

1
2
3
4
5
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-dubbo-adapter</artifactId>
    <version>x.y.z</version>
</dependency>

Spring Boot/Spring Cloud

示例

sentinel-guide-spring-cloud

Spring WebFlux

pom.xml

1
2
3
4
5
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-spring-webflux-adapter</artifactId>
    <version>x.y.z</version>
</dependency>

WebFluxConfig

 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
@Configuration
public class WebFluxConfig {

    private final List<ViewResolver> viewResolvers;
    private final ServerCodecConfigurer serverCodecConfigurer;

    public WebFluxConfig(ObjectProvider<List<ViewResolver>> viewResolversProvider,
                         ServerCodecConfigurer serverCodecConfigurer) {
        this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
        this.serverCodecConfigurer = serverCodecConfigurer;
    }

    @Bean
    @Order(-1)
    public SentinelBlockExceptionHandler sentinelBlockExceptionHandler() {
        // Register the block exception handler for Spring WebFlux.
        return new SentinelBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
    }

    @Bean
    @Order(-1)
    public SentinelWebFluxFilter sentinelWebFluxFilter() {
        // Register the Sentinel WebFlux filter.
        return new SentinelWebFluxFilter();
    }
}

示例

sentinel-demo-spring-webflux

gRPC

pom.xml

1
2
3
4
5
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-grpc-adapter</artifactId>
    <version>x.y.z</version>
</dependency>

客户端代码示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public class ServiceClient {

    private final ManagedChannel channel;

    ServiceClient(String host, int port) {
        this.channel = ManagedChannelBuilder.forAddress(host, port)
            .intercept(new SentinelGrpcClientInterceptor()) // 在此处注册拦截器
            .build();
        // 在此处初始化客户端 stub 类
    }
}

服务端代码示例

1
2
3
4
5
6
import io.grpc.Server;

Server server = ServerBuilder.forPort(port)
     .addService(new MyServiceImpl()) // 添加自己的服务实现
     .intercept(new SentinelGrpcServerInterceptor()) // 在此处注册拦截器
     .build();

Reactive

pom.xml

1
2
3
4
5
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-reactor-adapter</artifactId>
    <version>x.y.z</version>
</dependency>

接入示例

1
2
3
someService.doSomething() // return type: Mono<T> or Flux<T>
   .transform(new SentinelReactorTransformer<>(resourceName)) // 在此处进行变换
   .subscribe();

Spring Cloud Gateway

pom.xml

1
2
3
4
5
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
    <version>x.y.z</version>
</dependency>

GatewayConfiguration

 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
@Configuration
public class GatewayConfiguration {

    private final List<ViewResolver> viewResolvers;
    private final ServerCodecConfigurer serverCodecConfigurer;

    public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,
                                ServerCodecConfigurer serverCodecConfigurer) {
        this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
        this.serverCodecConfigurer = serverCodecConfigurer;
    }

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
        // Register the block exception handler for Spring Cloud Gateway.
        return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
    }

    @Bean
    @Order(-1)
    public GlobalFilter sentinelGatewayFilter() {
        return new SentinelGatewayFilter();
    }
}

示例

Netflix Zuul 1.x

pom.xml

1
2
3
4
5
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-zuul-adapter</artifactId>
    <version>x.y.z</version>
</dependency>

ZuulConfig

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

    @Bean
    public ZuulFilter sentinelZuulPreFilter() {
        // We can also provider the filter order in the constructor.
        return new SentinelZuulPreFilter();
    }

    @Bean
    public ZuulFilter sentinelZuulPostFilter() {
        return new SentinelZuulPostFilter();
    }

    @Bean
    public ZuulFilter sentinelZuulErrorFilter() {
        return new SentinelZuulErrorFilter();
    }
}

示例

网关限流 - Zuul 1.x

Apache RocketMQ

参考


Wanglibing
Wanglibing
Engineer,Lifelong learner