== Spring Cloud Alibaba Sentinel

### Introduction of Sentinel

As microservices become popular, the stability of service calls is becoming increasingly important. https://github.com/alibaba/Sentinel[Sentinel] takes "flow" as the breakthrough point, and works on multiple fields including flow control, circuit breaking and load protection to protect service reliability.

https://github.com/alibaba/Sentinel[Sentinel] has the following features:


* *Rich Scenarios*： Sentinel has supported the key scenarios of Alibaba’s Double 11 Shopping Festivals for over 10 years, such as second kill(i.e., controlling sudden bursts of traffic flow so that it’s within the acceptable range of the system capacity), message load shifting, circuit breaking of unreliable downstream applications.
* *Comprehensive Real-Time Monitoring*： Sentinel provides real-time monitoring capability. You can see the monitoring data of your servers at the accuracy of seconds, and even the overall runtime status of a cluster with less than 500 nodes.
* *Extensive Open-Source Ecosystem*： Sentinel provides out-of-box modules that can be easily integrated with other open-source frameworks/libraries, such as Spring Cloud, Dubbo, and gRPC. To use Sentinel, you only need to introduce the related dependency and make a few simple configurations.
* *Sound SPI Extensions*： Sentinel provides easy-to-use and sound SPI extension interfaces. You can customize logics with the SPI extensions quickly, for example, you can define your own rule management, or adapt to specific data sources.

### How to Use Sentinel

If you want to use Sentinel in your project, please use the starter with the group ID as `org.springframework.cloud` and the artifact ID as `spring-cloud-starter-alibaba-sentinel`.

```xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
```

The following is a simple example of how to use Sentinel:

```java
@SpringBootApplication
public class Application {

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

}

@RestController
public class TestController {

    @GetMapping(value = "/hello")
    @SentinelResource("hello")
    public String hello() {
        return "Hello Sentinel";
    }

}
```

The @SentinelResource annotation is used to identify if a resource is rate limited or degraded. In the above sample, the 'hello' attribute of the annotation refers to the resource name.

@SentinelResource also provides attributes such as `blockHandler`, `blockHandlerClass`,  and `fallback` to identify rate limiting or degradation operations. For more details, refer to  https://github.com/alibaba/Sentinel/wiki/%E6%B3%A8%E8%A7%A3%E6%94%AF%E6%8C%81[Sentinel Annotation Support].

##### Sentinel Dashboard

Sentinel dashboard is a lightweight console that provides functions such as machine discovery, single-server resource monitoring, overview of cluster resource data, as well as rule management. To use these features, you only need to complete a few steps.

*Note*: The statistics overview for clusters only supports clusters with less than 500 nodes, and has a latency of about 1 to 2 seconds.

.Sentinel Dashboard
image::https://github.com/alibaba/Sentinel/wiki/image/dashboard.png[]

To use the Sentinel dashboard, simply complete the following 3 steps.

###### Get the Dashboard

You can download the latest dashboard JAR file from the https://github.com/alibaba/Sentinel/releases[Release Page].

You can also get the latest source code to build your own Sentinel dashboard：

* Download the  https://github.com/alibaba/Sentinel/tree/master/sentinel-dashboard[Dashboard] project.
* Run the following command to package the code into a FatJar: `mvn clean package`


###### Start the Dashboard

Sentinel dashboard is a standard SpringBoot application, and you can run the JAR file in the Spring Boot mode.

```shell
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar
```

If there is conflict with the 8080 port, you can use `-Dserver.port=new port` to define a new port.

#### Configure the Dashboard

.application.yml
----
spring:
  cloud:
    sentinel:
      transport:
        port: 8719
        dashboard: localhost:8080
----

The port number specified in `spring.cloud.sentinel.transport.port` will start an HTTP Server on the corresponding server of the application, and this server will interact with the Sentinel dashboard. For example, if a rate limiting rule is added in the Sentinel dashboard, the the rule data will be pushed to and recieved by the HTTP Server, which in turn registers the rule to Sentinel.

For more information about Sentinel dashboard, please refer to https://github.com/alibaba/Sentinel/wiki/%E6%8E%A7%E5%88%B6%E5%8F%B0[Sentinel Dashboard].

### Feign Support

Sentinel is compatible with the https://github.com/OpenFeign/feign[Feign] component. To use it, in addition to introducing the `sentinel-starter` dependency, complete the following 2 steps:

* Enable the Sentinel support for feign in the properties file. `feign.sentinel.enabled=true`
* Add the `feign starter` dependency to trigger and enable `sentinel starter`:
```xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
```

This is a simple usage of `FeignClient`:

```java
@FeignClient(name = "service-provider", fallback = EchoServiceFallback.class, configuration = FeignConfiguration.class)
public interface EchoService {
    @RequestMapping(value = "/echo/{str}", method = RequestMethod.GET)
    String echo(@PathVariable("str") String str);
}

class FeignConfiguration {
    @Bean
    public EchoServiceFallback echoServiceFallback() {
        return new EchoServiceFallback();
    }
}

class EchoServiceFallback implements EchoService {
    @Override
    public String echo(@PathVariable("str") String str) {
        return "echo fallback";
    }
}
```

NOTE: The resource name policy in the corresponding interface of Feign is：httpmethod:protocol://requesturl. All the attributes in the `@FeignClient` annotation is supported by Sentinel.

The corresponding resource name of the `echo` method in the `EchoService` interface is `GET:http://service-provider/echo/{str}`.

### RestTemplate Support

Spring Cloud Alibaba Sentinel supports the protection of `RestTemplate` service calls using Sentinel. To do this, you need to add the `@SentinelRestTemplate` annotation when constructing the `RestTemplate` bean.

```java
@Bean
@SentinelRestTemplate(blockHandler = "handleException", blockHandlerClass = ExceptionUtil.class)
public RestTemplate restTemplate() {
    return new RestTemplate();
}
```

The attribute of the `@SentinelRestTemplate` annotation support flow control(`blockHandler`, `blockHandlerClass`) and circuit breaking(`fallback`, `fallbackClass`).

==

The `blockHandler` or `fallback` is the static method of `blockHandlerClass` or `fallbackClass`.

The parameter and return value of method in `@SentinelRestTemplate` is same as `org.springframework.http.client.ClientHttpRequestInterceptor#interceptor`, but it has one more parameter `BlockException` to catch the exception by Sentinel.

The method signature of `handleException` in `ExceptionUtil` above should be like this:

```java
public class ExceptionUtil {
    public static ClientHttpResponse handleException(HttpRequest request, byte[] body, ClientHttpRequestExecution execution, BlockException exception) {
        ...
    }
}
```

NOTE: When the application starts, it will check if the `@SentinelRestTemplate` annotation corresponding to the flow control or circuit breaking method exists, if it does not exist, it will throw an exception.

The attribute of the `@SentinelRestTemplate` annotation is optional.

It will return `RestTemplate request block by sentinel` when you using `RestTemplate` blocked by Sentinel. You can override it by your own logic. We provide `SentinelClientHttpResponse` to handle the response.

Sentinel RestTemplate provides two granularities for resource rate limiting:

* `schema://host:port/path`： Protocol, host, port and path

* `schema://host:port`： Protocol, host and port

NOTE: Take `https://www.taobao.com/test` as an example. The corresponding resource names have two levels of granularities, `https://www.taobao.com` and `https://www.taobao.com/test`.

### Dynamic Data Source Support

`SentinelProperties` provide `datasource` attribute to configure datasource.

For example, 4 data sources are configures：

```
spring.cloud.sentinel.datasource.ds1.file.file=classpath: degraderule.json
spring.cloud.sentinel.datasource.ds1.file.rule-type=flow

#spring.cloud.sentinel.datasource.ds1.file.file=classpath: flowrule.json
#spring.cloud.sentinel.datasource.ds1.file.data-type=custom
#spring.cloud.sentinel.datasource.ds1.file.converter-class=org.springframework.cloud.alibaba.cloud.examples.JsonFlowRuleListConverter
#spring.cloud.sentinel.datasource.ds1.file.rule-type=flow

spring.cloud.sentinel.datasource.ds2.nacos.server-addr=localhost:8848
spring.cloud.sentinel.datasource.ds2.nacos.dataId=sentinel
spring.cloud.sentinel.datasource.ds2.nacos.groupId=DEFAULT_GROUP
spring.cloud.sentinel.datasource.ds2.nacos.data-type=json
spring.cloud.sentinel.datasource.ds2.nacos.rule-type=degrade

spring.cloud.sentinel.datasource.ds3.zk.path = /Sentinel-Demo/SYSTEM-CODE-DEMO-FLOW
spring.cloud.sentinel.datasource.ds3.zk.server-addr = localhost:2181
spring.cloud.sentinel.datasource.ds3.zk.rule-type=authority

spring.cloud.sentinel.datasource.ds4.apollo.namespace-name = application
spring.cloud.sentinel.datasource.ds4.apollo.flow-rules-key = sentinel
spring.cloud.sentinel.datasource.ds4.apollo.default-flow-rule-value = test
spring.cloud.sentinel.datasource.ds5.apollo.rule-type=param-flow
```

This method follows the configuration of Spring Cloud Stream Binder. `TreeMap` is used for storage internally, and comparator is `String.CASE_INSENSITIVE_ORDER`.

NOTE: d1, ds2, ds3, ds4 are the names of `ReadableDataSource`, and can be coded as you like. The `file`, `zk`, `nacos` , `apollo` refer to the specific data sources. The configurations following them are the specific configurations of these data sources respecitively.

Every data source has 3 common configuration items: `data-type`, `converter-class` and `rule-type`.

`data-type` refers to `Converter`. Spring Cloud Alibaba Sentinel provides two embedded values by default: `json` and `xml` (the default is json if not specified). If you do not want to use the embedded `json` or `xml` `Converter`, you can also fill in `custom` to indicate that you will define your own `Converter`, and then configure the `converter-class`. You need to specify the full path of the class for this configuration.

`rule-type` refers to the rule type in datasource(`flow`, `degrade`, `authority`, `system`, `param-flow`).

If the data source takes effect and is loaded successfully, the dashboard will print information as shown below:

```
[Sentinel Starter] DataSource ds1-sentinel-file-datasource load 3 DegradeRule
[Sentinel Starter] DataSource ds2-sentinel-nacos-datasource load 2 FlowRule
```

NOTE: XML format is not supported by default. To make it effective, you need to add the  `jackson-dataformat-xml` dependency.

To learn more about how dynamic data sources work in Sentinel, refer to https://github.com/alibaba/Sentinel/wiki/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%99%E6%89%A9%E5%B1%95[Dynamic Rule Extension].

### Endpoint Support

Before you use the Endpoint feature, please add the  `spring-boot-starter-actuator` dependency in Maven, and enable access of Endpoints in your configuration.

* Add `management.security.enabled=false` in Spring Boot 1.x. The exposed endpoint path is `/sentinel`.
* Add `management.endpoints.web.exposure.include=*` in Spring Boot 2.x. The exposed endpoint path is `/actuator/sentinel`.

The information exposed in Sentinel Endpoint is very useful. It includes all the rules of the current application, the log directory, the IP of the current instance, the Sentinel Dashboard address, the Block Page, the heartbeat frequency of the application and the Sentinel Dashboard, and so on.

### More

The following table shows that when there are corresponding bean types in `ApplicationContext`, some actions will be taken:

:frame: topbot
[width="60%",options="header"]
|====
^|Existing Bean Type ^|Action ^|Function
|`UrlCleaner`|`WebCallbackManager.setUrlCleaner(urlCleaner)`|Resource cleaning(resource(for example, classify all URLs of /foo/:id to the  /foo/* resource))
|`UrlBlockHandler`|`WebCallbackManager.setUrlBlockHandler(urlBlockHandler)`|Customize rate limiting logic
|`RequestOriginParser`|`WebCallbackManager.setRequestOriginParser(requestOriginParser)`|Setting the origin
|====

The following table shows all the configurations of Spring Cloud Alibaba Sentinel:

:frame: topbot
[width="60%",options="header"]
|====
^|Configuration ^|Description ^|Default Value
|`spring.cloud.sentinel.enabled`|Whether Sentinel automatic configuration takes effect|true
|`spring.cloud.sentinel.eager`|Cancel Sentinel dashboard lazy load|false
|`spring.cloud.sentinel.transport.port`|Port for the application to interact with Sentinel dashboard. An HTTP Server which uses this port will be started in the application|8719
|`spring.cloud.sentinel.transport.dashboard`|Sentinel dashboard address|
|`spring.cloud.sentinel.transport.heartbeatIntervalMs`|Hearbeat interval between the application and Sentinel dashboard|
|`spring.cloud.sentinel.transport.client-ip`|Client IP|
|`spring.cloud.sentinel.filter.order`|Loading order of Servlet Filter. The filter will be constructed in the Starter|Integer.MIN_VALUE
|`spring.cloud.sentinel.filter.url-patterns`|Data type is array. Refers to the collection of Servlet Filter ULR patterns|/*
|`spring.cloud.sentinel.filter.enabled`|Enable to instance CommonFilter|true
|`spring.cloud.sentinel.metric.charset`|metric file character set|UTF-8
|`spring.cloud.sentinel.metric.fileSingleSize`|Sentinel metric single file size|
|`spring.cloud.sentinel.metric.fileTotalCount`|Sentinel metric total file number|
|`spring.cloud.sentinel.log.dir`|Directory of Sentinel log files|
|`spring.cloud.sentinel.log.switch-pid`|If PID is required for Sentinel log file names|false
|`spring.cloud.sentinel.servlet.blockPage`| Customized redirection URL. When rate limited, the request will be redirected to the pre-defined URL |
|`spring.cloud.sentinel.flow.coldFactor`| https://github.com/alibaba/Sentinel/wiki/%E9%99%90%E6%B5%81---%E5%86%B7%E5%90%AF%E5%8A%A8[ColdFactor] |3
|====

NOTE: These configurations will only take effect in servlet environment. RestTemplate and Feign will not take effect for these configurations.