mirror of
https://gitee.com/mirrors/Spring-Cloud-Alibaba.git
synced 2021-06-26 13:25:11 +08:00
refactor sentinel example directory tree
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-examples</artifactId>
|
||||
<version>0.2.0.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
<artifactId>sentinel-core-example</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<description>Example demonstrating how to use sentinel</description>
|
||||
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>${maven-deploy-plugin.version}</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
@@ -0,0 +1,275 @@
|
||||
# Sentinel Example
|
||||
|
||||
## 项目说明
|
||||
|
||||
本项目演示如何使用 Sentinel starter 完成 Spring Cloud 应用的限流管理。
|
||||
|
||||
[Sentinel](https://github.com/alibaba/Sentinel) 是阿里巴巴开源的分布式系统的流量防卫组件,Sentinel 把流量作为切入点,从流量控制,熔断降级,系统负载保护等多个维度保护服务的稳定性。
|
||||
|
||||
|
||||
## 示例
|
||||
|
||||
### 如何接入
|
||||
|
||||
在启动示例进行演示之前,我们先了解一下如何接入 Sentinel。
|
||||
|
||||
> **注意:本章节只是为了便于您理解接入方式,本示例代码中已经完成接入工作,您无需再进行修改。**
|
||||
|
||||
1. 首先,修改 `pom.xml` 文件,引入 Sentinel starter。
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
2. 接入限流埋点
|
||||
- HTTP 埋点
|
||||
|
||||
Sentinel starter 默认为所有的 HTTP 服务提供了限流埋点,如果只想对 HTTP 服务进行限流,那么只需要引入依赖,无需修改代码。
|
||||
- 自定义埋点
|
||||
|
||||
如果需要对某个特定的方法进行限流或降级,可以通过 `@SentinelResource` 注解来完成限流的埋点,示例代码如下:
|
||||
|
||||
```java
|
||||
@SentinelResource("resource")
|
||||
public String hello() {
|
||||
return "Hello";
|
||||
}
|
||||
```
|
||||
|
||||
当然也可以通过原始的 `SphU.entry(xxx)` 方法进行埋点,可以参见 [Sentinel 文档](https://github.com/alibaba/Sentinel/wiki/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8#%E5%AE%9A%E4%B9%89%E8%B5%84%E6%BA%90)。
|
||||
|
||||
3. 配置限流规则
|
||||
|
||||
Sentinel 提供了两种配置限流规则的方式:代码配置 和 控制台配置。本示例使用的方式为通过控制台配置。
|
||||
|
||||
1. 通过代码来实现限流规则的配置。一个简单的限流规则配置示例代码如下,更多限流规则配置详情请参考 [Sentinel 文档](https://github.com/alibaba/Sentinel/wiki/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8#%E5%AE%9A%E4%B9%89%E8%A7%84%E5%88%99)。
|
||||
|
||||
```java
|
||||
List<FlowRule> rules = new ArrayList<FlowRule>();
|
||||
FlowRule rule = new FlowRule();
|
||||
rule.setResource(str);
|
||||
// set limit qps to 10
|
||||
rule.setCount(10);
|
||||
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
|
||||
rule.setLimitApp("default");
|
||||
rules.add(rule);
|
||||
FlowRuleManager.loadRules(rules);
|
||||
```
|
||||
|
||||
2. 通过控制台进行限流规则配置请参考文章后面的图文说明。
|
||||
|
||||
### 启动 Sentinel 控制台
|
||||
|
||||
1. 首先需要获取 Sentinel 控制台,支持直接下载和源码构建两种方式。
|
||||
|
||||
1. 直接下载:[下载 Sentinel 控制台](http://edas-public.oss-cn-hangzhou.aliyuncs.com/install_package/demo/sentinel-dashboard.jar)
|
||||
2. 源码构建:进入 Sentinel [Github 项目页面](https://github.com/alibaba/Sentinel),将代码 git clone 到本地自行编译打包,[参考此文档](https://github.com/alibaba/Sentinel/tree/master/sentinel-dashboard)。
|
||||
|
||||
2. 启动控制台,执行 Java 命令 `java -jar sentinel-dashboard.jar`完成 Sentinel 控制台的启动。
|
||||
控制台默认的监听端口为 8080。Sentinel 控制台使用 Spring Boot 编程模型开发,如果需要指定其他端口,请使用 Spring Boot 容器配置的标准方式,详情请参考 [Spring Boot 文档](https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-customizing-embedded-containers)。
|
||||
|
||||
### 应用启动
|
||||
|
||||
1. 增加配置,在应用的 /src/main/resources/application.properties 中添加基本配置信息
|
||||
|
||||
```
|
||||
spring.application.name=sentinel-example
|
||||
server.port=18083
|
||||
spring.cloud.sentinel.dashboard=localhost:8080
|
||||
```
|
||||
|
||||
2. 启动应用,支持 IDE 直接启动和编译打包后启动。
|
||||
|
||||
1. IDE直接启动:找到主类 `ServiceApplication`,执行 main 方法启动应用。
|
||||
2. 打包编译后启动:首先执行 `mvn clean package` 将工程编译打包,然后执行 `java -jar sentinel-core-example.jar`启动应用。
|
||||
|
||||
### 调用服务
|
||||
|
||||
使用 curl 分别调用两个 URL,可以看到访问成功。
|
||||
|
||||
<p align="center"><img src="https://cdn.yuque.com/lark/0/2018/png/54319/1532084640137-8f4bc16c-4336-4c1b-9ddd-4582b967717a.png" width="240" heigh='180' ></p>
|
||||
|
||||
|
||||
### 配置限流规则并验证
|
||||
|
||||
1. 访问 http://localhost:8080 页面,可以在左侧看到 Sentinel-Example 应用已经注册到了控制台,单击 **流控规则** ,可以看到目前的流控规则为空。
|
||||
|
||||
> **注意:如果您在控制台没有找到应用,请调用一下进行了 Sentinel 埋点的 URL 或方法,因为 Sentinel 使用了 lazy load 策略。详细的排查过程请参见 [Sentinel FAQ](https://github.com/alibaba/Sentinel/wiki/FAQ)。**
|
||||
|
||||
<p align="center"><img src="https://cdn.nlark.com/lark/0/2018/png/54319/1532315951819-9ffd959e-0547-4f61-8f06-91374cfe7f21.png" width="1000" heigh='400' ></p>
|
||||
|
||||
|
||||
2. 配置 URL 限流规则:点击新增流控规则,资源名填写需要限流的 URL 相对路径,单机阈值选择需要限流的阈值,点击新增进行确认。(为了便于演示效果,这里将值设置成了 1)。
|
||||
|
||||
<p align="center"><img src="https://cdn.yuque.com/lark/0/2018/png/54319/1532078717483-62ab74cd-e5da-4241-a45d-66166b1bde99.png" width="480" heigh='180' ></p>
|
||||
|
||||
|
||||
3. 配置自定义限流规则:点击新增流控规则,资源名填写 `@SentinelResource` 注解 `value` 字段的值,单机阈值选择需要限流的阈值,点击新增进行确认。(为了便于演示效果,这里将值设置成了 1)。
|
||||
|
||||
|
||||
<p align="center"><img src="https://cdn.yuque.com/lark/0/2018/png/54319/1532080384317-2943ce0a-daaf-495d-8afc-79a0248a119a.png" width="480" heigh='180' ></p>
|
||||
|
||||
|
||||
4. 访问 URL,当 QPS 超过 1 时,可以看到限流效果如下。
|
||||
|
||||
<p align="center"><img src="https://cdn.yuque.com/lark/0/2018/png/54319/1532080652178-be119c4a-2a08-4f67-be70-fe5ed9a248a3.png" width="480" heigh='180' ></p>
|
||||
|
||||
<p align="center"><img src="https://cdn.yuque.com/lark/0/2018/png/54319/1532080661437-b84ee161-6c2d-4df2-bdb7-7cf0d5be92fb.png" width="480" heigh='180' ></p>
|
||||
|
||||
|
||||
## 自定义限流处理逻辑
|
||||
|
||||
1. URL 限流触发后默认处理逻辑是,直接返回 "Blocked by Sentinel (flow limiting)"。
|
||||
如果需要自定义处理逻辑,实现的方式如下:
|
||||
|
||||
```java
|
||||
public class CustomUrlBlockHandler implements UrlBlockHandler {
|
||||
@Override
|
||||
public void blocked(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException {
|
||||
// todo add your logic
|
||||
}
|
||||
}
|
||||
|
||||
WebCallbackManager.setUrlBlockHandler(new CustomUrlBlockHandler());
|
||||
```
|
||||
|
||||
2. 自定义限流触发后,默认的处理逻辑是抛出异常。
|
||||
|
||||
如果需要自定义处理逻辑,填写 `@SentinelResource` 注解的 `blockHandler` 属性(针对所有类型的 `BlockException`,需自行判断)或 `fallback` 属性(针对熔断降级异常),注意**对应方法的签名和位置有限制**,详情见 [Sentinel 注解支持文档](https://github.com/alibaba/Sentinel/wiki/%E6%B3%A8%E8%A7%A3%E6%94%AF%E6%8C%81#sentinelresource-%E6%B3%A8%E8%A7%A3)。示例实现如下:
|
||||
|
||||
```java
|
||||
public class TestService {
|
||||
|
||||
// blockHandler 是位于 ExceptionUtil 类下的 handleException 静态方法,需符合对应的类型限制.
|
||||
@SentinelResource(value = "test", blockHandler = "handleException", blockHandlerClass = {ExceptionUtil.class})
|
||||
public void test() {
|
||||
System.out.println("Test");
|
||||
}
|
||||
|
||||
// blockHandler 是位于当前类下的 exceptionHandler 方法,需符合对应的类型限制.
|
||||
@SentinelResource(value = "hello", blockHandler = "exceptionHandler")
|
||||
public String hello(long s) {
|
||||
return String.format("Hello at %d", s);
|
||||
}
|
||||
|
||||
public String exceptionHandler(long s, BlockException ex) {
|
||||
// Do some log here.
|
||||
ex.printStackTrace();
|
||||
return "Oops, error occurred at " + s;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```java
|
||||
public final class ExceptionUtil {
|
||||
|
||||
public static void handleException(BlockException ex) {
|
||||
System.out.println("Oops: " + ex.getClass().getCanonicalName());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
一个简单的示例可以见 [sentinel-demo-annotation-spring-aop](https://github.com/alibaba/Sentinel/tree/master/sentinel-demo/sentinel-demo-annotation-spring-aop)。
|
||||
|
||||
## Endpoint 信息查看
|
||||
|
||||
Spring Boot 应用支持通过 Endpoint 来暴露相关信息,Sentinel Starter 也支持这一点。
|
||||
|
||||
在使用之前需要在 Maven 中添加 `spring-boot-starter-actuator`依赖,并在配置中允许 Endpoints 的访问。
|
||||
* Spring Boot 1.x 中添加配置 `management.security.enabled=false`
|
||||
* Spring Boot 2.x 中添加配置 `management.endpoints.web.exposure.include=*`
|
||||
|
||||
Spring Boot 1.x 可以通过访问 http://127.0.0.1:18083/sentinel 来查看 Sentinel Endpoint 的信息。Spring Boot 2.x 可以通过访问 http://127.0.0.1:18083/acutator/sentinel 来访问。
|
||||
|
||||
<p align="center"><img src="https://cdn.yuque.com/lark/0/2018/png/54319/1532084199224-1a41591d-7a06-4680-be8a-5de319ac635d.png" width="480" heigh='360' ></p>
|
||||
|
||||
## 查看实时监控
|
||||
Sentinel 控制台支持实时监控查看,您可以通过 Sentinel 控制台查看各链路的请求的通过数和被限流数等信息。
|
||||
其中 `p_qps` 为通过(pass) 流控的 QPS,`b_qps` 为被限流 (block) 的 QPS。
|
||||
|
||||
<p align="center"><img src="https://cdn.nlark.com/lark/0/2018/png/54319/1532313595369-8428cd7d-9eb7-4786-a149-acf0da4a2daf.png" width="480" heigh='180' ></p>
|
||||
|
||||
## DataSource 支持
|
||||
|
||||
Sentinel 内部提供了[动态规则的扩展实现 DataSource](https://github.com/alibaba/Sentinel/wiki/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%99%E6%89%A9%E5%B1%95#datasource-%E6%89%A9%E5%B1%95)。
|
||||
|
||||
Sentinel starter 整合了目前存在的几类 DataSource。只需要在配置文件中进行相关配置,即可在 Spring 容器中自动注册 DataSource。
|
||||
|
||||
比如要定义一个 `FileRefreshableDataSource`,配置如下:
|
||||
|
||||
spring.cloud.sentinel.datasource.type=file
|
||||
spring.cloud.sentinel.datasource.recommendRefreshMs=2000
|
||||
spring.cloud.sentinel.datasource.bufSize=2048
|
||||
spring.cloud.sentinel.datasource.charset=utf-8
|
||||
spring.cloud.sentinel.datasource.configParser=myParser
|
||||
spring.cloud.sentinel.datasource.file=/Users/you/rule.json
|
||||
|
||||
然后使用`@SentinelDataSource` 注解修饰 DataSource 即可注入:
|
||||
|
||||
@SentinelDataSource("spring.cloud.sentinel.datasource")
|
||||
private DataSource dataSource;
|
||||
|
||||
`@SentinelDataSource` 注解的 value 属性可以不填。默认值就是 `spring.cloud.sentinel.datasource`。
|
||||
|
||||
`value` 属性代表配置前缀。示例中会去找 `spring.cloud.sentinel.datasource.xxx` 相关的配置。
|
||||
|
||||
`spring.cloud.sentinel.datasource.type` 就是对应的 DataSource 类型。
|
||||
|
||||
`spring.cloud.sentinel.datasource.recommendRefreshMs` 里的 `recommendRefreshMs` 对应相关 DataSource 的属性。
|
||||
|
||||
`spring.cloud.sentinel.datasource.configParser`代表 `ConfigParser` 在 Spring 容器里的 name。如果没找到,会抛出异常。
|
||||
|
||||
type目前支持file, nacos, zk, apollo。
|
||||
|
||||
### 自定义DataSource
|
||||
|
||||
自定义DataSource只需要两步。
|
||||
|
||||
1. 定义DataSource
|
||||
|
||||
public class CustomDataSource implements DataSource {
|
||||
private String fieldA;
|
||||
private String fieldB;
|
||||
...
|
||||
}
|
||||
|
||||
2. 装配DataSource。有两种方式处理。
|
||||
|
||||
* 直接构造DataSource
|
||||
|
||||
@Bean
|
||||
public CustomDataSource customDataSource() {
|
||||
CustomDataSource customDataSource =
|
||||
new CustomDataSource();
|
||||
customDataSource.setFieldA("valueA");
|
||||
customDataSource.setFieldB("valueB");
|
||||
...
|
||||
return customDataSource;
|
||||
}
|
||||
|
||||
* 在classpath:/META-INF/sentinel-datasource.properties中管理DataSource信息
|
||||
|
||||
custom = yourpackage.CustomDataSource
|
||||
|
||||
在application.properties中定义DataSource
|
||||
|
||||
spring.cloud.sentinel.datasource.type = custom
|
||||
spring.cloud.sentinel.datasource.fieldA = valueA
|
||||
spring.cloud.sentinel.datasource.fieldB = valueB
|
||||
|
||||
注意:由于目前Sentinel的AbstractDataSource需要有个ConfigParser作为构造函数中的参数,并且它的子类的构造都是通过多个参数的构造函数构造的。
|
||||
所以目前所有的Sentinel starter中的DataSource都是基于FactoryBean并且通过设置属性构造的。如果有这方面的需求,需要再多加一个registerFactoryBean过程。
|
||||
|
||||
SentinelDataSourceRegistry.registerFactoryBean("custeom", CustomDataSourceFactoryBean.class);
|
||||
|
||||
如果自定义DataSource可以注入属性,那么没有必要使用SentinelDataSourceRegistry注册FactoryBean。
|
||||
|
||||
|
||||
## More
|
||||
Sentinel 是一款功能强大的中间件,从流量控制,熔断降级,系统负载保护等多个维度保护服务的稳定性。此 Demo 仅演示了 使用 Sentinel 作为限流工具的使用,更多 Sentinel 相关的信息,请参考 [Sentinel 项目](https://github.com/alibaba/Sentinel)。
|
||||
|
||||
如果您对 spring cloud sentinel starter 有任何建议或想法,欢迎在 issue 中或者通过其他社区渠道向我们提出。
|
||||
|
@@ -0,0 +1,245 @@
|
||||
# Sentinel Example
|
||||
## Project Instruction
|
||||
|
||||
This example illustrates how to use Sentinel starter to implement flow control for Spring Cloud applications.
|
||||
|
||||
[Sentinel](https://github.com/alibaba/Sentinel) is an open-source project of Alibaba. Sentinel takes "traffic flow" as the breakthrough point, and provides solutions in areas such as flow control, concurrency, circuit breaking, and load protection to protect service stability.
|
||||
|
||||
|
||||
## Demo
|
||||
|
||||
### Connect to Sentinel
|
||||
Before we start the demo, let's learn how to connect Sentinel to a Spring Cloud application.
|
||||
**Note: This section is to show you how to connect to Sentinel. The configurations have been completed in the following example, so you don't need modify the code any more.**
|
||||
|
||||
1. Add dependency spring-cloud-starter-alibaba-sentinel in the pom.xml file in your Spring Cloud project.
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
|
||||
</dependency>
|
||||
|
||||
2. Define Resources
|
||||
|
||||
1. Define HTTP Resources
|
||||
Sentinel starter defines all HTTP URLS as resources by relative paths. If you only want to add flow control for your HTTP services, you do not need to modify your code.
|
||||
|
||||
2. Define Custom Resources
|
||||
If you want to implement flow control or degradation for a specific method, you can add an @SentinelResource annotation to the method, as shown in the code below.
|
||||
|
||||
@SentinelResource("resource")
|
||||
public String hello() {
|
||||
return "Hello";
|
||||
}
|
||||
|
||||
3. Configure flow control rules
|
||||
|
||||
Sentinel provides two ways to configure flow control rules, init from code or configure by dashboard.
|
||||
|
||||
1. Init rule from code: See the code below for a simple flow rule. See [Sentinel Docs](https://github.com/alibaba/Sentinel/wiki/How-to-Use#define-rules) for more information about flow rules.
|
||||
|
||||
List<FlowRule> rules = new ArrayList<FlowRule>();
|
||||
FlowRule rule = new FlowRule();
|
||||
rule.setResource(str);
|
||||
// set limit qps to 10
|
||||
rule.setCount(10);
|
||||
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
|
||||
rule.setLimitApp("default");
|
||||
rules.add(rule);
|
||||
FlowRuleManager.loadRules(rules);
|
||||
|
||||
2. Config by dashboard: See the following section.
|
||||
|
||||
### Start Sentinel Dashboard
|
||||
|
||||
1. Install Sentinel dashboard by downloading a fatjar or build from source code.
|
||||
|
||||
1. Download: [Download Sentinel Dashboard](http://edas-public.oss-cn-hangzhou.aliyuncs.com/install_package/demo/sentinel-dashboard.jar)
|
||||
2. Build from source code: Get source code by `git clone git@github.com:alibaba/Sentinel.git` from [Github Sentinel](https://github.com/alibaba/Sentinel) and build your code. See [build reference](https://github.com/alibaba/Sentinel/tree/master/sentinel-dashboard) for details.
|
||||
|
||||
2. Start the dashboard by running the `java -jar sentinel-dashboard.jar` command.
|
||||
The default port of Sentinel dashboard is 8080. Sentinel dashboard is a Spring Boot project. If you want to use another port, see [Spring Boot Reference](https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-customizing-embedded-containers).
|
||||
|
||||
### Start Application
|
||||
|
||||
1. Add necessary configurations to file `/src/main/resources/application.properties`.
|
||||
|
||||
spring.application.name=sentinel-example
|
||||
server.port=18083
|
||||
spring.cloud.sentinel.dashboard=localhost:8080
|
||||
|
||||
2. Start the application in IDE or by building a fatjar.
|
||||
|
||||
1. Start in IDE: Find main class `ServiceApplication`, and execute the main method.
|
||||
2. Build a fatjar:Execute command `mvn clean package` to build a fatjar,and run command `java -jar sentinel-core-example.jar` to start the application.
|
||||
|
||||
### Invoke Service
|
||||
|
||||
Execute command `curl http://127.0.0.1:18083/hello`
|
||||
Execute command `curl http://127.0.0.1:18083/test`
|
||||
|
||||
The screenshot belows shows invoke success:
|
||||
|
||||
<p align="center"><img src="https://cdn.yuque.com/lark/0/2018/png/54319/1532084640137-8f4bc16c-4336-4c1b-9ddd-4582b967717a.png" width="240" heigh='180' ></p>
|
||||
|
||||
### Configure Flow Control
|
||||
|
||||
1. Open http://localhost:8080 in browser, and you can find a Sentinel-Example Application has been registered to the dashboard.
|
||||
|
||||
**Note: If you can't find your application in the dashboard, invoke a method that has been defined as a Sentinel Resource,for Sentinel uses lazy load strategy.**
|
||||
|
||||
<p align="center"><img src="https://cdn.nlark.com/lark/0/2018/png/54319/1532315951819-9ffd959e-0547-4f61-8f06-91374cfe7f21.png" width="1000" heigh='400' ></p>
|
||||
|
||||
|
||||
2. Configure HTTP Resource Flow Rule:Click **流控规则(Flow Rule)** on the left-side navigation pane and **新增流控规则(Create Flow Rule)**. On the Create Flow Rule dialogbox, type the URL relative path in the **资源名(Resource Name)** field , enter **单机阈值(Threshold)** value, then click **新增(OK)**. Here we set threshold to 1 for demonstration purpose.
|
||||
|
||||
<p align="center"><img src="https://cdn.yuque.com/lark/0/2018/png/54319/1532078717483-62ab74cd-e5da-4241-a45d-66166b1bde99.png" width="480" heigh='180' ></p>
|
||||
|
||||
3. Configure Custom Resource Flow Rule:Click **流控规则(Flow Rule)** on the left-side navigation pane and **新增流控规则(Create Flow Rule)**. type the value() of @SentinelResource in the **资源名(Resource Name)** field , enter **单机阈值(Threshold)** value, then click **新增(OK)**.Here we set threshold to 1 for demonstration purpose.
|
||||
|
||||
<p align="center"><img src="https://cdn.yuque.com/lark/0/2018/png/54319/1532080384317-2943ce0a-daaf-495d-8afc-79a0248a119a.png" width="480" heigh='180' ></p>
|
||||
|
||||
4. Visit the URL in your browser again. When QPS is more than 1, we can see that flow control takes effect.
|
||||
|
||||
<p align="center"><img src="https://cdn.yuque.com/lark/0/2018/png/54319/1532080652178-be119c4a-2a08-4f67-be70-fe5ed9a248a3.png" width="480" heigh='180' ></p>
|
||||
|
||||
<p align="center"><img src="https://cdn.yuque.com/lark/0/2018/png/54319/1532080661437-b84ee161-6c2d-4df2-bdb7-7cf0d5be92fb.png" width="480" heigh='180' ></p>
|
||||
|
||||
|
||||
## Customize Flow Control Logic
|
||||
|
||||
1. When a URL resource is blocked by Sentinel, the default logic is return HTTP response "Blocked by Sentinel (flow limiting)".
|
||||
|
||||
If you want to customize your flow control logic, see the code below:
|
||||
|
||||
public class CustomUrlBlockHandler implements UrlBlockHandler {
|
||||
@Override
|
||||
public void blocked(HttpServletRequest httpServletRequest,
|
||||
HttpServletResponse httpServletResponse) throws IOException {
|
||||
// todo add your logic
|
||||
}
|
||||
}
|
||||
|
||||
WebCallbackManager.setUrlBlockHandler(new CustomUrlBlockHandler());
|
||||
|
||||
|
||||
2. When a custom resource is blocked by Sentinel, the default logic is throw BlockException.
|
||||
|
||||
If you want to customize your flow control logic, implement interface `SentinelExceptionHandler`, set @SentinelResource's blockHandler() and blockHandlerClass(). See the code below:
|
||||
|
||||
@SentinelResource(value = "resource", blockHandler = "", blockHandlerClass = ExceptionUtil.class)
|
||||
public String hello() {
|
||||
return "Hello";
|
||||
}
|
||||
|
||||
// ExceptionUtil.java
|
||||
public class ExceptionUtil {
|
||||
public static void handleException(BlockException ex) {
|
||||
System.out.println("Oops: " + ex.getClass().getCanonicalName());
|
||||
}
|
||||
}
|
||||
|
||||
## Endpoint
|
||||
|
||||
Sentinel starter also supports the implementation of Spring Boot actuator endpoints.
|
||||
|
||||
**Prerequisite:**
|
||||
|
||||
Add dependency `spring-boot-starter-actuator` to your pom.xml file, and configure your endpoint security strategy.
|
||||
|
||||
* Spring Boot1.x: Add configuration `management.security.enabled=false`
|
||||
* Spring Boot2.x: Add configuration `management.endpoints.web.exposure.include=*`
|
||||
|
||||
To view the endpoint information, visit the following URLS:
|
||||
* Spring Boot1.x: Sentinel Endpoint URL is http://127.0.0.1:18083/sentinel.
|
||||
* Spring Boot2.x: Sentinel Endpoint URL is http://127.0.0.1:18083/actuator/sentinel.
|
||||
|
||||
<p align="center"><img src="https://cdn.yuque.com/lark/0/2018/png/54319/1532084199224-1a41591d-7a06-4680-be8a-5de319ac635d.png" width="480" heigh='360'></p>
|
||||
|
||||
## Metrics
|
||||
You can view metrics information on Sentinel Dashboard.
|
||||
|
||||
To see the metrics, click **实时监控(Real-time Monitoring)** in the left-side navigation pane.
|
||||
|
||||
`p_qps` stands for passed requests per second, `b_qps` stands for blocked requests per second.
|
||||
|
||||
<p align="center"><img src="https://cdn.nlark.com/lark/0/2018/png/54319/1532313595369-8428cd7d-9eb7-4786-a149-acf0da4a2daf.png" width="480" heigh='180'></p>
|
||||
|
||||
## DataSource
|
||||
|
||||
Sentinel provide [DataSource](https://github.com/alibaba/Sentinel/blob/master/sentinel-extension/sentinel-datasource-extension/src/main/java/com/alibaba/csp/sentinel/datasource/DataSource.java) to manage dynamic rules.
|
||||
|
||||
Sentinel starter integrated 4 DataSources provided by Sentinel. It will be register into Spring Context if you write some configs in `application.properties`.
|
||||
|
||||
If you want to define FileRefreshableDataSource:
|
||||
|
||||
spring.cloud.sentinel.datasource.type=file
|
||||
spring.cloud.sentinel.datasource.recommendRefreshMs=2000
|
||||
spring.cloud.sentinel.datasource.bufSize=2048
|
||||
spring.cloud.sentinel.datasource.charset=utf-8
|
||||
spring.cloud.sentinel.datasource.configParser=myParser
|
||||
spring.cloud.sentinel.datasource.file=/Users/you/rule.json
|
||||
|
||||
then use `@SentinelDataSource` to annotate DataSource:
|
||||
|
||||
@SentinelDataSource("spring.cloud.sentinel.datasource")
|
||||
private DataSource dataSource;
|
||||
|
||||
The value() of `@SentinelDataSource` is not required, it means the prefix of configuration. Default value is `spring.cloud.sentinel.datasource`.
|
||||
|
||||
spring.cloud.sentinel.datasource.type means the type of DataSource.
|
||||
|
||||
spring.cloud.sentinel.datasource.recommendRefreshMs means the recommendRefreshMs property of specified DataSource.
|
||||
|
||||
spring.cloud.sentinel.datasource.configParser means the name of spring bean that type is ConfigParser. If the bean is not exists, will throw exception.
|
||||
|
||||
Now datasource type support 4 categories: file, nacos, zk, apollo.
|
||||
|
||||
### User-defined DataSource
|
||||
|
||||
User-defined DataSource need 2 steps.
|
||||
|
||||
1. Define DataSource
|
||||
|
||||
public class CustomDataSource implements DataSource {
|
||||
private String fieldA;
|
||||
private String fieldB;
|
||||
...
|
||||
}
|
||||
|
||||
2. Assemble DataSource. There are 2 ways to do this.
|
||||
|
||||
* Construct DataSource directly
|
||||
|
||||
@Bean
|
||||
public CustomDataSource customDataSource() {
|
||||
CustomDataSource customDataSource = new CustomDataSource();
|
||||
customDataSource.setFieldA("valueA");
|
||||
customDataSource.setFieldB("valueB");
|
||||
...
|
||||
return customDataSource;
|
||||
}
|
||||
|
||||
* define DataSource metadata in `classpath:/META-INF/sentinel-datasource.properties`
|
||||
|
||||
custom = yourpackage.CustomDataSource
|
||||
|
||||
define configuration in `application.properties`
|
||||
|
||||
spring.cloud.sentinel.datasource.type = custom
|
||||
spring.cloud.sentinel.datasource.fieldA = valueA
|
||||
spring.cloud.sentinel.datasource.fieldB = valueB
|
||||
|
||||
Note: The AbstractDataSource of Sentinel need a ConfigParser as a constructor param and the subclass of AbstractDataSource was construct by multi-param constructor.
|
||||
Now All DataSources in starter was construct by FactoryBean. If you want to do it in this way, you should register FactoryBean by SentinelDataSourceRegistry.
|
||||
|
||||
SentinelDataSourceRegistry.registerFactoryBean("custeom", CustomDataSourceFactoryBean.class);
|
||||
|
||||
It is no need to using SentinelDataSourceRegistry to register FactoryBean if your User-defined DataSource can inject fields.
|
||||
|
||||
|
||||
## More
|
||||
For more information about Sentinel, see [Sentinel Project](https://github.com/alibaba/Sentinel).
|
||||
|
||||
If you have any ideas or suggestions for Spring Cloud Sentinel starter, please don't hesitate to tell us by submitting github issues.
|
||||
|
@@ -0,0 +1,14 @@
|
||||
package org.springframework.cloud.alibaba.cloud.examples;
|
||||
|
||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||
|
||||
/**
|
||||
* @author fangjian
|
||||
*/
|
||||
public class ExceptionUtil {
|
||||
|
||||
public static void handleException(BlockException ex) {
|
||||
System.out.println("Oops: " + ex.getClass().getCanonicalName());
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
package org.springframework.cloud.alibaba.cloud.examples;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.csp.sentinel.datasource.ConfigParser;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.TypeReference;
|
||||
|
||||
/**
|
||||
* @author fangjian
|
||||
*/
|
||||
public class JsonFlowRuleListParser implements ConfigParser<String, List<FlowRule>> {
|
||||
@Override
|
||||
public List<FlowRule> parse(String source) {
|
||||
return JSON.parseObject(source, new TypeReference<List<FlowRule>>() {});
|
||||
}
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
package org.springframework.cloud.alibaba.cloud.examples;
|
||||
|
||||
import com.alibaba.csp.sentinel.datasource.ConfigParser;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.alibaba.sentinel.annotation.SentinelProtect;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* @author xiaojing
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class ServiceApplication {
|
||||
|
||||
@Bean
|
||||
@SentinelProtect(blockHandler = "handleException", blockHandlerClass = ExceptionUtil.class)
|
||||
public RestTemplate restTemplate() {
|
||||
return new RestTemplate();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RestTemplate restTemplate2() {
|
||||
return new RestTemplate();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ConfigParser myParser() {
|
||||
return new JsonFlowRuleListParser();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(ServiceApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
package org.springframework.cloud.alibaba.cloud.examples;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import com.alibaba.csp.sentinel.annotation.SentinelResource;
|
||||
|
||||
/**
|
||||
* @author xiaojing
|
||||
*/
|
||||
@RestController
|
||||
public class TestController {
|
||||
|
||||
@Autowired
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
@RequestMapping(value = "/hello", method = RequestMethod.GET)
|
||||
@SentinelResource("resource")
|
||||
public String hello() {
|
||||
return "Hello";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/test", method = RequestMethod.GET)
|
||||
public String test1() {
|
||||
return "Hello test";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/template", method = RequestMethod.GET)
|
||||
public String client() {
|
||||
return restTemplate.getForObject("http://www.taobao.com/test", String.class);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
spring.application.name=sentinel-example
|
||||
server.port=18083
|
||||
management.endpoints.web.exposure.include=*
|
||||
spring.cloud.sentinel.port=8721
|
||||
spring.cloud.sentinel.dashboard=localhost:8080
|
||||
|
||||
|
||||
|
||||
spring.cloud.sentinel.datasource.type=file
|
||||
spring.cloud.sentinel.datasource.recommendRefreshMs=3000
|
||||
spring.cloud.sentinel.datasource.bufSize=4056196
|
||||
spring.cloud.sentinel.datasource.charset=utf-8
|
||||
spring.cloud.sentinel.datasource.configParser=myParser
|
||||
spring.cloud.sentinel.datasource.file=/Users/you/rule.json
|
Reference in New Issue
Block a user