Sentinel flow control

Sentinel Flow Control & Introduction to Service fuse Downgrading

Flow Control Introduction

Here I use the example of scenic spots to explain

A scenic spot receives 8K tourists a day, after 8K tourists can not buy tickets to enter the scenic spot.

For programming purposes, an interface has a maximum QPS (number of requests per second) of 100, after which we restrict access and give friendly hints.

An unlimited number of QPS can cause server downtime.

The service fuse is degraded

When the system is called, if a resource in the call link is unstable, requests will eventually pile up, resulting in cascading errors

And fusing the drop can solve this problem, the so-called fusing the drop is detected when calling a resource in the link appear unstable performance, such as the request and response time is long or abnormal ratio increases, the call of the resource constraints, make requests fail fast, avoid to affect other resources and cause cascading failure

Sentinel Flow control primer

Creating a Local Application

Overall process analysis

  1. Create a springBoot project
  2. Import the coordinates of Sentinel (used here as gradle)
  3. Create a Controller test interface, define and reference traffic limiting rules

Importing core dependencies

implementation("com.alibaba.cloud:spring-cloud-starter-alibaba-sentinel")
Copy the code

## Local Sentinel console

Download the Sentinel Console JAR package

Download address

### Start Sentinel console

JDK version 1.8 or later is required to start the Sentinel console.

Use the following command to start

Java -dserver. port= port number -jar sentinel-dashboard-1.8.0.jar

Access the console

The console can be accessed via the browser at http://localhost: port number. The default user name and password are both ‘sentinel’

Sentinel custom resource mode

  1. Resources are defined by the way exceptions are thrown
  2. Returns a boolean-defined resource
  3. Asynchronous invocation support
  4. Annotations define resources
  5. Default adaptation of mainstream frameworks

Resources are defined by the way exceptions are thrown

SphU of Sentinel species includes a try-catch style API. In this way, a BlockException is thrown when a resource is restricted.

At this time you can catch exceptions, after limiting the logical operation, in the entry case is the use of this way to achieve, the key code:

fun hello(a): String {
        // Use traffic limiting rules
        try {
            SphU.entry("Hello")}catch (e: Exception) {
            return "System busy, please try again later!!"
        }
        return "Hello Sentinel"
    }
Copy the code

In particular, if a hotspot parameter is passed in entry, the corresponding parameter (exit(count, args)) must also be entered in exit. Otherwise, statistics errors may occur. You can’t use try-with-resources at this point. In addition, when using tracer.trace (ex) to collect exception information, the number of exceptions cannot be counted correctly because of the call order of catch in the try-with-resources syntax. Therefore, tracer.trace (ex) cannot be called in the catch block of try-with-resources to count exceptions.

Example of manual exit:

Entry entry = null;
// Ensure that finally is executed
try {
  The resource name can be any string with business semantics. The number should not be too large (more than 1K). If the number exceeds several thousand, please pass it in as a parameter rather than as the resource name directly
  // EntryType indicates the traffic type (inbound/outbound). System rules only apply to buried points of the IN type
  entry = SphU.entry("Custom resource name");
  // Protected business logic
  // do something...
} catch (BlockException ex) {
  // Resource access blocked, traffic restricted or degraded
  // Perform the corresponding processing operation
} catch (Exception ex) {
  // To configure degradation rules, record service exceptions in this way
  Tracer.traceEntry(ex, entry);
} finally {
  // Be sure to ensure exit. Be sure to pair each entry with exit
  if(entry ! =null) { entry.exit(); }}Copy the code

Hotspot parameter burying point example:

Entry entry = null;
try {
    // If you need to configure exceptions, only basic types are supported.
    // EntryType indicates the traffic type. System rules take effect only for buried points of the IN type
    // count in most cases is 1 to count a call.
    entry = SphU.entry(resourceName, EntryType.IN, 1, paramA, paramB);
    // Your logic here.
} catch (BlockException ex) {
    // Handle request rejection.
} finally {
    // Note: Exit must also be accompanied by the corresponding parameter, otherwise there may be statistical errors.
    if(entry ! =null) {
        entry.exit(1, paramA, paramB); }}Copy the code

Parameter descriptions of sphu.entry () :

Parameter names type explain The default value
entryType EntryType The traffic type of the resource invocation is the incoming traffic (EntryType.IN) or outlet flow (EntryType.OUT), note that the system rule applies only to IN EntryType.OUT
count int Token number of the resource invocation request 1
args Object[] Parameter passed in for hotspot parameter limiting There is no

Note: Sphu.entry (XXX) needs to be paired with the entry.exit() method to match the call, otherwise it will cause the call chain to record an exception, throwing an ErrorEntryFreeException. Common mistakes:

  • Custom buried points are only calledSphU.entry(), no callentry.exit()
  • Out of order, for example:entry1 -> entry2 -> exit1 -> exit2, should beentry1 -> entry2 -> exit2 -> exit1

Returns a boolean-defined resource

The Sentinel SphO includes an IF-else style API. In this way, when a resource is curbed, it returns false, and the logical processing after curbed can be performed based on the return value.

  1. Define resources in creating TestBooleanController in the project by returning booelan

     @GetMapping("sentinel_boolean")
        fun hello(a): Boolean {
            // Configure the input-limiting interface. In this case, use the console to configure the traffic limiting rules
            return if (SphO.entry("Boolean")) {
                try {// Protected resources
                    println("Hello Sentinel Boolean")
                    true
                } finally {
                    // Limit the current outlet
                    SphO.exit()
                }
            } else {
                // Traffic limiting or degradation processing
                println("System busy, please try again later.")
                false}}Copy the code

** Configure flow control rules on the console **

Note that spho.entry (XXX) needs to be paired with the spho.exit () method, matching calls, and in the right place, otherwise it will cause the call chain to log an exception, throwing an ErrorEntryFreeException

### Asynchronous invocation support

Sentinel supports asynchronous call link statistics. In asynchronous calls, resources are defined through the sphu.asyncentry (XXX) method, and exit is usually called in an asynchronous callback function.

  1. The launch class enables asynchronous invocation@EnableAsync
  2. Turn on asynchronous calls to methods@Async

Sphu.asyncentry (XXX) does not affect the current (calling thread) Context, so the following two entries are flat on the call chain (at the same level) rather than nested:

// Call chain similar to:
// -parent
// ---asyncResource
// ---syncResource
asyncEntry = SphU.asyncEntry(asyncResource);
entry = SphU.entry(normalResource);
Copy the code

If you need to nest other resource calls (either Entry or asyncEntry) in an asynchronous callback, just use the context switch provided by Sentinel. Context transformation is performed using contextutil.runonContext (context, f) in the corresponding place, and the context at the corresponding resource invocation is switched to the generated asynchronous context to maintain the correct invocation link relationship. The following is an example:

public void handleResult(String result) {
    Entry entry = null;
    try {
        entry = SphU.entry("handleResultForAsync");
        // Handle your result here.
    } catch (BlockException ex) {
        // Blocked for the result handler.
    } finally {
        if(entry ! =null) { entry.exit(); }}}public void someAsync(a) {
    try {
        AsyncEntry entry = SphU.asyncEntry(resourceName);

        // Asynchronous invocation.
        doAsync(userId, result -> {
            The AsyncEntry getAsyncContext method is used to get the async Context
            ContextUtil.runOnContext(entry.getAsyncContext(), () -> {
                try {
                    // Normal resource calls are nested here.
                    handleResult(result);
                } finally{ entry.exit(); }}); }); }catch (BlockException ex) {
        // Request blocked.
        // Handle the exception (e.g. retry or fallback).}}Copy the code

The call chain looks like this:

-parent
---asyncInvocation
-----handleResultForAsync
Copy the code

For a more detailed example, see AsyncEntryDemo in Demo, which contains various nesting examples between normal and asynchronous resources.

Define resources with ### annotations

Sentinel supports the @SentinelResource annotation to define resources and configure blockHandler and fallback functions for post-limiting processing. The following dependencies need to be introduced when using the Sentinel Annotation AspectJ Extension

Implementation (" com. Alibaba. CSP: sentinel - the annotation - aspectj: 1.7.2 ")

@RestController
class TestAnnController {
    /** * SentinelResource: define support * value: Set the name of the resource * blockHandler: set the function to degrade or limit traffic */
    @SentinelResource(value = "sentinel_ann", blockHandler = "exceptionHandler")
    @GetMapping("ann")
    fun hello(a): String{
        return "hello Sentinel"
    }

    /** * limit or degrade the function */
    fun exceptionHandler(ex: BlockException) :String {
        ex.printStackTrace()
        return "System busy, please wait."}}Copy the code

@ SentinelResource annotations

Note: The annotation method does not support the private method.

@SentinelResource is used to define resources and provides optional exception handling and Fallback configuration items. The @sentinelResource annotation contains the following properties:

  • value: Resource name, required (cannot be empty)
  • entryType: Entry type. This parameter is optionalEntryType.OUT)
  • blockHandler / blockHandlerClass: blockHandlerCorresponding processingBlockExceptionThe optional function name of the The access range of the blockHandler function must bepublic, the return type needs to match the original method, and the parameter type needs to match the original method and add an extra parameter at the end, of typeBlockException. The blockHandler function needs to be in the same class as the original method by default. You can specify if you want to use a function from another classblockHandlerClassOf the corresponding classClassObject, note that the corresponding function must be static, otherwise it cannot be parsed.
  • fallback/fallbackClass: The optional fallback function name that provides fallback handling logic when an exception is thrown. The fallback function is available for all types of exceptions (exceptexceptionsToIgnoreThe type of exception that is excluded). Fallback function signature and position requirements:
    • The return value type must be the same as that of the original function;
    • The method argument list needs to be the same as the original function, or it can be an extra oneThrowableType to receive the corresponding exception.
    • The fallback function needs to be in the same class as the original method by default. You can specify if you want to use a function from another classfallbackClassOf the corresponding classClassObject, note that the corresponding function must be static, otherwise it cannot be parsed.
  • defaultFallback(since 1.6.0) : Default fallback function name, optional, usually used for generic fallback logic (that is, can be used for many services or methods). The default fallback function can be used for all types of exceptions (exceptexceptionsToIgnoreThe type of exception that is excluded). If both fallback and defaultFallback are configured, only fallback takes effect. DefaultFallback signature requirements:
    • The return value type must be the same as that of the original function;
    • The method parameter list needs to be empty, or you can have an extra parameterThrowableType to receive the corresponding exception.
    • DefaultFallback needs to be in the same class as the original method by default. You can specify if you want to use a function from another classfallbackClassOf the corresponding classClassObject, note that the corresponding function must be static, otherwise it cannot be parsed.
  • exceptionsToIgnore(since 1.6.0) : Specifies which exceptions are excluded, are not counted in the exception count, and are not included in fallback logic, but are thrown as is.

Starting with version 1.8.0, defaultFallback supports configuration at the class level.

Note: The fallback function before 1.6.0 only handles DegradeException, not service exception.

In particular, if blockHandler and Fallback are configured, only blockHandler processing logic will be entered when a BlockException is thrown due to traffic limiting demotion. If blockHandler, FallBack, and defaultFallback are not configured, BlockException thrown directly when they are current limiting the drop (if the method itself undefined throws BlockException packing layer would be JVM UndeclaredThrowableException).

Example:

public class TestService {

    / / function
    @SentinelResource(value = "hello", blockHandler = "exceptionHandler", fallback = "helloFallback")
    public String hello(long s) {
        return String.format("Hello at %d", s);
    }
    
    // Fallback is a function with the same signature as the original function or with a Throwable argument.
    public String helloFallback(long s) {
        return String.format("Halooooo %d", s);
    }

    // Block exception handler (); // Block exception handler ();
    public String exceptionHandler(long s, BlockException ex) {
        // Do some log here.
        ex.printStackTrace();
        return "Oops, error occurred at " + s;
    }

    // blockHandlerClass is configured separately.
    // The corresponding 'handleException' function needs to be in the 'ExceptionUtil' class and must be public static.
    @SentinelResource(value = "test", blockHandler = "handleException", blockHandlerClass = {ExceptionUtil.class})
    public void test(a) {
        System.out.println("Test"); }}Copy the code

Starting from version 1.4.0, annotated resources support automatic statistics of service exceptions. You do not need to manually call tracer.trace (ex) to record service exceptions. Sentinel versions prior to 1.4.0 required a call to tracer.trace (ex) to log service exceptions.

configuration

Spring Cloud Alibaba

If you are Sentinel connected through Spring Cloud Alibaba, you can use the @SentinelResource annotation without additional configuration.

Spring AOP

If your application uses Spring AOP (either Spring Boot or traditional Spring application), you need to register SentinelResourceAspect as a Spring Bean by configuration:

@Configuration
public class SentinelAspectConfiguration {

    @Bean
    public SentinelResourceAspect sentinelResourceAspect(a) {
        return newSentinelResourceAspect(); }}Copy the code

We provide examples of Spring AOP, see Sentinel-Demo-annotation-spring-AOP.

AspectJ

If your application uses AspectJ directly, you need to introduce the corresponding Aspect in the AOP.xml file:

<aspects>
    <aspect name="com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect"/>
</aspects>
Copy the code

### Default adaptation of mainstream frameworks

Document address: github.com/alibaba/Sen…

Types of rules

All Sentinel rules can be dynamically queried and modified in memory, and the changes take effect immediately. Sentinel also provides apis that allow you to customize your own rules policies.

Sentinel supports the following rules: flow control rules, fuse degrade rules, system protection rules, source access control rules, and hotspot parameter rules.

Flow Rules

Definition of traffic rules

Important attributes:

Field instructions The default value
resource The resource name is the object of the traffic limiting rule
count Current limiting threshold
grade Flow limiting threshold type, QPS mode (1) or Number of concurrent threads mode (0) QPS model
limitApp The source of the call for flow control default, indicates that the call source is not distinguished
strategy Call relationship traffic limiting policies: direct, link, and association According to the resource itself (direct)
controlBehavior Flow control effect (direct reject /WarmUp/ Constant speed + queuing), does not support traffic limiting by call relationship Direct refused to
clusterMode Whether to restrict traffic in a cluster no

A resource can have multiple traffic limiting rules at the same time. The rules are checked one by one.

Define flow control rules through code

When we understand the rules of the above definition, we can by calling FlowRuleManager. LoadRules () method to use hard-coded way defined flow control rules, such as:

private void initFlowQpsRule(a) {
    List<FlowRule> rules = new ArrayList<>();
    FlowRule rule = new FlowRule(resourceName);
    // set limit qps to 20
    rule.setCount(20);
    rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
    rule.setLimitApp("default");
    rules.add(rule);
    FlowRuleManager.loadRules(rules);
}
Copy the code