1. What is Sentinel?
As distributed systems become more and more popular, reliability between services becomes more important than ever. Sentinel is a powerful flow control component, with "flow" as the entry point, covering multiple areas, including flow control, concurrency restriction, circuit interruption and adaptive system protection to ensure the reliability of microservices.
In a word, it is Spring Cloud Alibaba
used to replace the previous Hystrix
technology.
2. What's the use?
Used for system flow control, fuse degradation, system load protection, etc.
3. Download and start Sentinel
1. Download address
2. Start
java -jar sentinel-dashboard-1.7.2.jar
3. To access the Dashboard, the user name and password are bothsentinel
4. Test preparation
1. Create a new springboot project
2. Introduce dependencies
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- sentinel-datasource-nacos 后续持久化用 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</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>
3. Add annotations to the startup class@EnableDiscoveryClient
@SpringBootApplication
@EnableDiscoveryClient
public class AlibabaSentinelServiceApplication {
public static void main(String[] args) {
SpringApplication.run(AlibabaSentinelServiceApplication.class, args);
}
}
4. application.properties
Configure
server.port=8401
spring.application.name=cloudalibaba-sentinel-service
spring.cloud.nacos.discovery.server-addr=localhost:8848
spring.cloud.sentinel.transport.dashboard=localhost:8080
spring.cloud.sentinel.transport.port=8719
spring.cloud.sentinel.datasource.dsl.nacos.server-addr=localhost:8848
spring.cloud.sentinel.datasource.dsl.nacos.data-id=${spring.application.name}
spring.cloud.sentinel.datasource.dsl.nacos.group-id=DEFAULT_GROUP
spring.cloud.sentinel.datasource.dsl.nacos.data-type=json
spring.cloud.sentinel.datasource.dsl.nacos.rule-type.=flow
management.endpoints.web.exposure.include=*
5. Provide test interface
@RestController
public class FlowLimitController {
private static Logger log = LoggerFactory.getLogger(FlowLimitController.class);
@GetMapping("/testA")
public String testA(){
// try {
// TimeUnit.MILLISECONDS.sleep(800);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
return "testA-----";
}
@GetMapping("/testB")
public String testB(){
log.info(Thread.currentThread().getName() + "...testB ");
return "testB -----";
}
}
6. Start sentinel
and nacos
don't understand nacos can refer to
5. Test flow control rules
- Resource name: unique name, default request path
- For the source: Sentinel can limit the flow for the caller, fill in the microservice name, and default
default
(do not distinguish the source) - Threshold type/single machine threshold
- QPS (the number of requests per second): When the QPS that calls the api reaches the threshold, limit the current
- Number of threads: when the number of threads calling the api reaches the threshold, limit the current
- Flow control mode
- Direct: When the api reaches the current-limiting condition, the current is directly limited
- Association: When the associated resource reaches the threshold, it limits the flow of itself.
The A interface is associated with the B interface. When the B interface reaches the threshold, the current limit of the A interface is used to protect the B interface. For example, the payment interface and the ordering interface, when the payment interface reaches the threshold, the ordering interface is limited in flow, which plays a role in protecting the payment interface. - Link: Only record the traffic on the specified link (the traffic coming in from the specified resource entrance resource, if it reaches the threshold, it will limit the flow)
- Flow control effect
- Fail fast: directly fail and throw an exception
- Warm up: According to the value of codeFactor (cold load factor, default 3), from threshold/codeFactor, after warm-up time, it reaches the set QPS threshold.
Generally used for functions similar to spikes. - Waiting in line: queuing at a constant speed to allow requests to pass at a constant speed. The threshold type must be set to QPS, otherwise it will be invalid.
5.1 Test QPS to reach the threshold
The configuration is as follows:
when you click continuously to see the following current limit prompt (the number of 1s requests exceeds the configured threshold)
5.2 The number of test threads reaches the threshold
The configuration is as follows: in
order to facilitate testing, let each called method sleep for a while
@GetMapping("/testA")
public String testA(){
//测试线程阈值
try {
TimeUnit.MILLISECONDS.sleep(800);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "testA-----";
}
When you click continuously to see the following current limit prompt (the number of 1s requests exceeds the configured threshold)
5.3 Test correlation current limit
The configuration is as follows.
Use postman to simulate and /testA
associate with the /testB
threshold
reached. After calling postman, /testA
you can see that the interface is limited.
5.4 Test Warm up (current limit cold start)
The configuration is as follows (when the access traffic suddenly increases, starting from the threshold/cold load factor, the warm-up time reaches the access threshold per second, that is, it can support 2 accesses per second from the beginning of the traffic increase, and it can support per second after 3s 6 access interfaces), the default cold factor (coldFactor) is 3,
you can click to access the /testA
interface test, start slowly and slowly click no problem, and then increase the speed will appear current limit, after a while, the current limit will disappear.
5.5. Waiting in line
The configuration is as follows
In order to facilitate the viewing of the call, the thread name is printed in the interface
@GetMapping("/testB")
public String testB(){
log.info(Thread.currentThread().getName() + "...testB ");
return "testB -----";
}
Restart the project call, you can see the call record in the console
6. Test the downgrade rules
- RT:
- When the average response time of the resource exceeds the threshold (here the threshold is the millisecond value configured by yourself) and the request passed within the time window is >= 5, the two conditions are met at the same time to trigger the fuse degradation
- Close the circuit breaker after the window period.
- RT maximum 4900 (larger through -Dcsp.sentinel.statistic.max.rt=xxx to configure)
- Abnormal proportion: When
QPS>=5 and the abnormal proportion (second-level statistics) exceeds the threshold, the downgrade is triggered; after the time window ends, the downgrade is closed. - Number of exceptions: the number of
exceptions (statistics in minutes) exceeds the threshold, triggering the downgrade; after the time window ends, the downgrade is closed
Sentienl fuse downgrade will limit the call of this resource when a certain resource in the call link is unstable (for example, call timeout or abnormal ratio increase), so that the request will fail quickly and avoid affecting other resources and causing the level Link error.
When the resource is degraded, the call to the resource is automatically fused within the next degrading time window (the default behavior is to throw DegradeException)
6.1 Test RT
1. Add test interface
@GetMapping("/testD")
public String testD(){
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("testD 测试RT");
return "testD -----";
}
In order to increase the average response time, add sleep to the code.
2. Use JMater to stress test
1s 10 thread access /testD
interfaces
. 3. The configuration is as follows
. 4. Start JMeter and call /testD
it yourself . You can see that the interface has been degraded by fuse.
Fuse analysis: 1. The average response time (1000ms) exceeds the threshold (200ms) 2. Pass the request within the time window 10*5=50>=5. Two conditions are met, so fuse degradation occurs
6.2 Test anomaly ratio
Resource requests per second >= 5&& The ratio of the total number of exceptions per second to the throughput exceeds the threshold , the resource enters a degraded state, that is, within the next time window, calls to this method will automatically return (service fuse). The abnormal rate threshold range is [0.0,1.0], which represents 0%-100%.
1. Provide an interface for testing abnormal proportions
@GetMapping("/testException")
public String testException(){
log.info("testException 异常比例");
int age = 10 /0 ;
return "testException -----";
}
2. Use JMater to perform stress test, except for the interface, other configurations are the same as the above test RT
3. Sentinel configuration
4. Restart the project and start JMeter for testing, call the /testException
service fuse prompt message
6.3 Number of test exceptions
When the number of abnormal resources in the last 1 minute exceeds the threshold, it will be fused. Note that because the statistical time window is at the minute level, if the time window is less than 60s, it may enter the fusing state again after the fusing state is ended.
1. Provide test interface
@GetMapping("/testExceptionCount")
public String testExceptionCount(){
log.info("testExceptionCount 异常数");
int age = 10 /0 ;
return "testExceptionCount -----";
}
2. Sentinel configuration
3. Restart the project for testing. The
first 5 visits all reported errors, and the subsequent visits were degraded after the fuse was entered.
Degrade after fusing as shown below
7. Hotspot parameter current limit
7.1 Current limit of common hotspot parameters
1. Provide an interface for testing
@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey", blockHandler = "dealTestHotKey")
public String testHotKey(@RequestParam(value = "p1", required = false) String p1,
@RequestParam(value = "p2", required = false) String p2){
return "testHotKey -----";
}
public String dealTestHotKey(String p1, String p2, BlockException blockException){
return "dealTestHotKey---------";
}
2. Sentinel configuration
The first parameter p1 in the above configuration, when the QPS exceeds 1 click in 1 second, the current will be limited immediately.
3. Restart the project test
7.2 Parameter exception hot spot current limit
1. The sentinel configuration is as follows
. The meaning of the above configuration is that when the value of the first parameter p1 is 5, /testHotKey
the traffic threshold of the interface is 200
note:
@SentinelResource deals with the violation of the console configuration, which is handled by the blockHandler method configuration.
But @SentinelResource does not care about runtime exceptions in the code (RuntimeException)
8.@SentinelResource configuration
8.1 Limit flow by resource name or URL address plus follow-up processing
1. Provide interface
/**
* (违反sentinel配置)手动配置兜底处理blockHandler
* @return
*/
@GetMapping(value = "/byResource")
@SentinelResource(value = "byResource", blockHandler = "handleException")
public CommonResult byResource(){
return new CommonResult(200, "按资源名称限流测试OK");
}
public CommonResult handleException(BlockException blockException){
return new CommonResult<>(444, blockException.getClass().getCanonicalName()+"\t服务不可用" );
}
/**
* 默认处理
* @return
*/
@GetMapping("/rateLimit/byUrl")
@SentinelResource(value = "byUrl")
public CommonResult byUrl(){
return new CommonResult(200, "by url限流测试OK");
}
2. Sentinel configuration
Resource name:
url:
3. Restart test
access byResource
when accessing more than once per second, using a custom fallback process.
Access /rateLimit/byUrl
when accessing more than once per second, using the default process.
There are problems with the above configuration:
- 1. The system default does not reflect our own business needs
- 2. According to existing conditions, our custom processing method and business code are coupled together, which is not intuitive
- 3. Every business method has a bottom line, and the code expansion increases
- 4. The global same processing method is not reflected
8.1 Solve existing problems
1. Provide interface
public class CustomerBlockHandler {
public static CommonResult handlerException(BlockException exception) {
return new CommonResult(444, "客户自定义,global handlerException---1");
}
public static CommonResult handlerException2(BlockException exception) {
return new CommonResult(444, "客户自定义,global handlerException---2");
}
}
@GetMapping("/rateLimit/customerBlockHandler")
@SentinelResource(value = "customerBlockHandler",
blockHandlerClass = CustomerBlockHandler.class, blockHandler = "handlerException2")
public CommonResult customerBlockHandler(){
return new CommonResult(200, "客户自定义 限流测试OK");
}
2. Configuration in sentinel
3. Restart test
9. Integrate Ribbon and OpenFeign
9.1 Preparation
1. Create three springboot projects, namely alibaba-consumer2, alibaba-provider3, and alibaba-provider4 (alibaba-provider3/alibaba-provider4 is the same)
because there are too many things, not listed here, please refer to https://github.com/xiaoxiaoshou /springclouddemo
9.2Ribbon series
Main sample code:
@RestController
@Slf4j
@RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE)
public class CircleBreakerController {
private static final String SERVICE_URL = "http://nacos-payment-provider";
@Resource
private RestTemplate restTemplate;
@RequestMapping("/consumer/fallback/{id}")
// @SentinelResource(value = "fallback") //没有配置
// @SentinelResource(value = "fallback",fallback = "handlerFallback") //配置了fallback的,fallback只负责业务异常
// @SentinelResource(value = "fallback",blockHandler = "blockHandler") // 配置了blockHandler,只负责sentinel控制台配置违规
@SentinelResource(value = "fallback",fallback = "handlerFallback", blockHandler = "blockHandler") // 配置了blockHandler和fallback
// @SentinelResource(value = "fallback",fallback = "handlerFallback", blockHandler = "blockHandler", exceptionsToIgnore = {IllegalArgumentException.class}) // 忽略运行时IllegalArgumentException异常不进行自定义处理
public CommonResult<Payment> fallback(@PathVariable("id") Long id){
CommonResult<Payment> commonResult = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/" + id, CommonResult.class);
if(id == 4){
throw new IllegalArgumentException("IllegalArgumentException,非法参数异常");
}else if(commonResult.getData() == null){
throw new NullPointerException("NullPointerException,该ID没有记录,空指针异常");
}
return commonResult;
}
// 本例是fallback
public CommonResult handlerFallback(Long id, Throwable e){
Payment payment = new Payment(id, null);
return new CommonResult(444, "兜底异常handler,exception内容"+e.getMessage(), payment);
}
public CommonResult blockHandler(Long id, BlockException exception){
Payment payment = new Payment(id, null);
return new CommonResult<>(445, "blockHandler-sentinel 限流,无此流水号:blockException" + exception.getMessage(), payment);
}
}
fallback
The corresponding method (handlerFallback method) handles exceptions during code runtimeblockHandler
Corresponding method (blockHandler) handles violations in SentinelexceptionsToIgnore
Ignore an exception during runtime without custom processing
Configure Sentinel (the resource fallback threshold is 1) and start the project test. You can see that it can handle Sentinel violations during the invocation process and also handle exceptions during runtime.
9.3 OpenFeign series
1. Main configuration
#激活sentinel对feign的支持
feign:
sentinel:
enabled: true
2. Binding the corresponding service
@FeignClient(value = "nacos-payment-provider", fallback = PaymentFallbackService.class)
public interface PaymentService {
@GetMapping("/paymentSQL/{id}")
CommonResult<Payment> paymentSQL(@PathVariable("id") Long id);
}
@Component
public class PaymentFallbackService implements PaymentService {
@Override
public CommonResult<Payment> paymentSQL(Long id) {
return new CommonResult<>(444, "fallback");
}
}
3. Provide access interface
@Resource
private PaymentService paymentService;
@GetMapping("/consumer/paymentSQL/{id}")
public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id){
return paymentService.paymentSQL(id);
}
4. Restart the project to bypass the consumer interface and call the third-party interface
Comparison of various fuses:
10. Rule persistence
When you restart the corresponding service every time, you will find that the corresponding rules configured in Sentinel are gone. In the production environment, we need to configure the persistence of the rules (persistence tools are available, and Nacos is officially recommended).
1. Introduce dependencies
<!-- sentinel-datasource-nacos 后续持久化用 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
2. Configuration file configuration
spring.cloud.sentinel.datasource.dsl.nacos.server-addr=localhost:8848
spring.cloud.sentinel.datasource.dsl.nacos.data-id=${spring.application.name}
spring.cloud.sentinel.datasource.dsl.nacos.group-id=DEFAULT_GROUP
spring.cloud.sentinel.datasource.dsl.nacos.data-type=json
spring.cloud.sentinel.datasource.dsl.nacos.rule-type=flow
3. Configure in nacos
[
{
"resource":"/rateLimit/byUrl",
"limitApp":"default",
"grade":1,
"count":1,
"strategy":0,
"controlBehavior":0,
"clusterMode":false
}
]
Configuration item meaning:
- resource: resource name
- limitApp: source application
- grade: threshold type, 0 means the number of threads, 1 means QPS
- count: stand-alone threshold
- strategy: flow control mode, 0 means direct, 1 means cascade, 2 means link
- controlBehavior: flow control effect, 0 means fast failure, 1 means Warm Up, 2 means waiting in line
- clusterMode: whether to cluster