sentinel Chapter 2 - use of resource annotations - combined with spring AOP

Posted by sualcavab on Thu, 11 Nov 2021 23:55:02 +0100

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

  • pom dependency
<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

Topics: Spring Spring Boot sentinel