preface
- The previous chapter provides a quick introduction. What you can know is:
- Using sentinel is mainly to define resources, configure resource rules and verify the effectiveness of configuration
- In sentinel, "a resource can be anything, a service, a method in a service, or even a piece of code."
- This article will use sentinel annotation to define resources, which needs to introduce aspect related dependencies. The monitoring and rule configuration of flow control is through sentinel dashboard.
Spring boot application integration sentinel
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>${sentinel.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-annotation-aspectj</artifactId>
<version>${sentinel.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>${sentinel.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
- Inject sentinel resource registration facet SentinelResourceAspect
@Configuration
public class SentinelAspectConfiguration {
@Bean
public SentinelResourceAspect sentinelResourceAspect() {
return new SentinelResourceAspect();
}
}
- Use @ SentinelResource to define resources
@Service
public class TestService {
@SentinelResource(value = "resource1")
public String resource1() {
System.out.println("resource1");
return "resource1";
}
public String notResource() {
System.out.println("notResource");
return "resource1";
}
}
@RestController
public class Demo1Controller {
@Autowired
private TestService service;
@GetMapping("/resource1")
public String resource1() {
return service.resource1() + " " + LocalDateTime.now().toString();
}
@GetMapping("/notResource")
public String notResource() {
return service.notResource() + " " + LocalDateTime.now().toString();
}
}
- Start the application (start parameter configuration - Dcsp.sentinel.dashboard.server=localhost:8080 or set the system parameter System.setProperty("csp.sentinel.dashboard.server", "localhost:8080") with the main method of springboot startup class)
- Request target resources intensively and observe the dashboard resource request. Because no flow control rules are configured, it is only monitored without blocking effect. The figure shows ↓
- The flow rule of the dashboard configuration resource is limited to QPS=1. View the effect of intensive requests, as shown in the figure ↓
- The code configures the blocking handler and or fallback of resources and verifies them
@Service
public class TestService {
@SentinelResource(value = "resource1", blockHandler = "handleException", blockHandlerClass = { ExceptionUtil2.class })
public String resource1() {
System.out.println("resource1");
return "resource1";
}
public String notResource() {
System.out.println("notResource");
return "notResource";
}
@SentinelResource(value = "test", blockHandler = "handleException", blockHandlerClass = { ExceptionUtil.class })
public void test() {
System.out.println("Test");
}
@SentinelResource(value = "hello", fallback = "helloFallback")
public String hello(long s) {
if (s < 0) {
throw new IllegalArgumentException("invalid arg");
}
return String.format("Hello at %d", s);
}
@SentinelResource(value = "helloAnother", defaultFallback = "defaultFallback", exceptionsToIgnore = {
IllegalStateException.class })
public String helloAnother(String name) {
if (name == null || "bad".equals(name)) {
throw new IllegalArgumentException("oops");
}
if ("foo".equals(name)) {
throw new IllegalStateException("oops");
}
return "Hello, " + name;
}
public String helloFallback(long s, Throwable ex) {
// Do some log here.
ex.printStackTrace();
return "Oops, error occurred at " + s;
}
public String defaultFallback() {
System.err.println("Go to default fallback");
return "default_fallback";
}
}
public final class ExceptionUtil2 {
public static String handleException(BlockException ex) {
// Handler method that handles BlockException when blocked.
// The method parameter list should match original method, with the last additional
// parameter with type BlockException. The return type should be same as the original method.
// The block handler method should be located in the same class with original method by default.
// If you want to use method in other classes, you can set the blockHandlerClass
// with corresponding Class (Note the method in other classes must be static).
System.err.println("Oops: " + ex.getClass().getCanonicalName());
return ex.getClass().getSimpleName();
}
}
- Precautions for stepping on the pit:
- 1) blockHandler's method must be static and return value is same as "resource"
- 2) The fallback method needs to be in the same class as the "resource" (unless fallbackClass is specified), and the parameters and return types must be consistent
- 3) If blockHandler and fallback are configured at the same time, only blockHandler will work
- 4) In terms of use, blockHandler emphasizes fast exceptions for flow restriction (clearly tells the caller that this is not available); fallback aims at degradation and emphasizes friendly standby response (maintaining call link integrity). In the final analysis, it is high availability protection for target resources! (PS: if blockHandler is used, it is more convenient to use global exception handling - ControllerAdvice instead)
- Reference to official instructions: https://sentinelguard.io/zh-cn/docs/annotation-support.html
Effective reference