Spring cloud Alibaba sentinel realizes fusing and current limiting

In the previous article, we introduced sentinel, including installing sentinel console, initializing demonstrator and process flow control rules
Next, learn the fusing rules, hotspot key current limiting, system rules, @ SentinelResource annotation, service fusing function and rule persistence.

Fusing rules

Official introduction

  • Basic introduction

    Fusing strategy

Sentinel provides the following fusing strategies:

  • Slow_request_ratio: select the slow call ratio as the threshold, and set the allowed slow call RT (i.e. the maximum response time). If the response time of the request is greater than this value, it will be counted as slow call. When the number of requests in the unit statistical duration (statIntervalMs) is greater than the set minimum number of requests, and the proportion of slow calls is greater than the threshold, the next fusing duration requests will be automatically fused. After fusing for a long time, the fuse will enter the detection recovery state (HALF-OPEN state). If the response time of the next request is less than the set slow call RT, the fusing will be ended. If it is greater than the set slow call RT, it will be blown again.
  • Error_ratio: when the number of requests in the unit statistical duration (statIntervalMs) is greater than the set minimum number of requests, and the proportion of exceptions is greater than the threshold, the requests in the next fusing duration will be blown automatically. After fusing for a long time, the fuse will enter the detection recovery state (HALF-OPEN state). If the next request is successfully completed (no error), the fusing will be ended, otherwise it will be blown again. The threshold range of abnormal ratio is [0.0, 1.0], representing 0% - 100%.
  • Error_count: when the number of exceptions in the unit statistical time exceeds the threshold, it will automatically fuse. After fusing for a long time, the fuse will enter the detection recovery state (HALF-OPEN state). If the next request is successfully completed (no error), the fusing will be ended, otherwise it will be blown again.
    Note that exception degradation is only for business exceptions, and does not take effect for the exception (BlockException) of Sentinel current limiting degradation itself.
  • RT (average response time in seconds)
    The average response time exceeds the threshold and the request passed within the time window is > = 5. The degradation is triggered after the two conditions are met at the same time
    Close the circuit breaker after the window period
    RT maximum 4900 (larger ones can only take effect through - DCSP. Sentinel. Statistical. Max.rt = XXXX)

The DegradeRule contains the following important attributes:

FieldexplainDefault value
resourceResource name, that is, the object of the rule
gradeFusing strategy, supporting slow call proportion / exception proportion / different constant strategySlow call ratio
countIn slow call proportional mode, it is slow call critical RT (exceeding this value is counted as slow call); It is the corresponding threshold in the exception proportion / exception number mode
timeWindowFusing duration, unit: s
minRequestAmountThe minimum number of requests triggered by fusing. When the number of requests is less than this value, it will not fuse even if the abnormal ratio exceeds the threshold (introduced by 1.7.0)5
statIntervalMsStatistical duration (unit: ms), for example, 60 * 1000 represents minute level (introduced in 1.8.0)1000 ms
slowRatioThresholdSlow call proportional threshold. Only slow call proportional mode is valid (introduced in 1.8.0)

Sentinel's circuit breaker is not half open
In the half open state, the system automatically detects whether the request is abnormal,
If there is no abnormality, close the circuit breaker and resume use,
If there is any abnormality, continue to open the circuit breaker and it is unavailable. Refer to Hystrix for details

(1) Slow call ratio

Select the slow call proportion as the threshold. You need to set the allowed slow call RT (i.e. the maximum response time). If the response time of the request is greater than this value, it will be counted as slow call. When the number of requests in the unit statistical duration (statIntervalMs) is greater than the set minimum number of requests, and the proportion of slow calls is greater than the threshold, the next fusing duration requests will be automatically fused. After fusing for a long time, the fuse will enter the detection recovery state (HALF-OPEN state). If the response time of the next request is less than the set slow call RT, the fusing will be ended. If it is greater than the set slow call RT, it will be blown again.

  • Add a test interface and sleep for 2 seconds when calling the interface, so that the response time of this interface is more than 1 second
@GetMapping("/testD")
public String testD()
{
    //Pause the thread for a few seconds
    try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); }
    log.info("testD Test call ratio");
    return "------testD";
}
  • Add test interface rule to console
  • Maximum RT: slow call critical RT, exceeding this value is counted as slow call. Unit: ms
  • Proportional threshold: the threshold of slow request ratio in RT mode. Default 1.0d
  • Fusing duration: recovery timeout (in seconds) when the circuit breaker is open. After the timeout, the circuit breaker will switch to the half open state to try some requests. The unit is second. The figure shows that after triggering the fusing, the request will be blown automatically in the next 10 seconds. After 10S, the fuse will enter the detection recovery state (HALF-OPEN state). If the response time of the next request is less than the set slow call RT, the fusing will be ended. If it is greater than the set slow call RT, it will be blown again.
  • Minimum number of requests: the minimum number of requests that can trigger fuse interruption (within the effective statistical time range). The default value is 5
  • StatIntervalMs: statistical duration (unit: ms). For example, 601000 represents minute level (introduced in 1.8.0). It defaults to 1000. There is no option on the console and needs to be implemented in code.

Test with jemeter

Use the pressure test tool to access the test interface and view the current limiting effect diagram. The specific current limiting process is roughly as follows:
(1) When the request enters the background, sentinel will count the total number of requests in the time period according to the set statistical duration (1S by default)
(2) First, judge whether the total number of requests counted is less than the minimum number of requests set by the user (5 by default). If it is less than, it will not be fused. Otherwise, go to the next step
(3) Then, according to the maximum RT set by the user, judge whether the request in the statistics is a slow call. If it is greater than the set value, it is a slow call request
(4) Calculate the proportion of slow call requests / total statistical requests again, and whether it exceeds the set proportion threshold.
(5) When the number of requests in the statistical time and the slow call proportion threshold exceed the set threshold, the requests in the next fusing time will be automatically fused
(6) After the fusing duration ends, the fuse will enter the detection recovery state (HALF-OPEN state). If the response time of the next request is less than the set slow call RT, the fusing will end. If it is greater than the set slow call RT, it will be blown again.
--------
Copyright notice: This is the original article of CSDN blogger "cloud smoke into rain CSDN", which follows the CC 4.0 BY-SA copyright agreement. Please attach the original source link and this notice for reprint.
Original link: https://blog.csdn.net/qq_43437874/article/details/111475762

Conclusion:
Always call in 10 threads (more than 5) to call testD in one second. We hope to complete this task in 200 milliseconds,
If the process is not completed for more than 200 milliseconds, the circuit breaker opens (fuse trips), the microservice is unavailable and the fuse trips and de energizes within the next 1 second time window
Subsequently, I stopped jmeter and there was no such a large number of visits. The circuit breaker was closed (the fuse was restored) and the microservice was restored to OK

(2) Abnormal proportion

Error_ratio: when the number of requests in the unit statistical duration (statIntervalMs) is greater than the set minimum number of requests, and the proportion of exceptions is greater than the threshold, the requests in the next fusing duration will be blown automatically. After fusing for a long time, the fuse will enter the detection recovery state (HALF-OPEN state). If the next request is successfully completed (no error), the fusing will be ended, otherwise it will be blown again. The threshold range of abnormal ratio is [0.0, 1.0], representing 0% - 100%.

  • Add the following methods in the controller
@GetMapping("/testE")
public String testE()
{
    log.info("testE Test exception ratio");
    int age = 10/0;
    return "------testE";
}
  • Add test interface rule to console

    visit http://127.0.0.1:8401/testE

    If an error is reported directly, refresh it directly.

    Because many calls have reached our configured fuse degradation conditions, the circuit breaker is opened (fuse trips), the microservice is unavailable, no error is reported, but the service is degraded.

(3) Different constant

Error_count: when the number of exceptions in the unit statistical time exceeds the threshold, it will automatically fuse. After fusing for a long time, the fuse will enter the detection recovery state (HALF-OPEN state). If the next request is successfully completed (no error), the fusing will be ended, otherwise it will be blown again.
test
Or the testE path just now

  • Console modification test interface fusing rules

visit http://127.0.0.1:8401/testE

Within 5s, visit 5 times first. When you visit the fifth time, visit once, that is, the sixth time.

Because the statistical duration we configured is 5s, when the number of exceptions in 5s reaches 5, the sixth fuse degradation will be carried out, and the degradation lasts for 2s.

Hot spot current limiting

What are hot spots?
Hot spots are frequently accessed data. Many times, we want to count or limit the TopN data with the highest access frequency in a hot spot data, and limit its access or other operations

Official description

  • Add the following methods in the controller
@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey",blockHandler = "dealHandler_testHotKey")
public String testHotKey(@RequestParam(value = "p1",required = false) String p1, 
                         @RequestParam(value = "p2",required = false) String p2){
    return "------testHotKey";
}
public String dealHandler_testHotKey(String p1,String p2,BlockException exception)
{
    return "-----dealHandler_testHotKey";
}

Sentinel system default prompt: Blocked by Sentinel (flow limiting)

  • Configuration description

    Normal access http://127.0.0.1:8401/testHotKey

    visit http://127.0.0.1:8401/testHotKey?p1=1 , and constantly refresh

    visit http://127.0.0.1:8401/testHotKey?p2=1 , and constantly refresh

    visit http://127.0.0.1:8401/testHotKey?p2=1&p1=1 , and constantly refresh

    Conclusion: as long as the parameter p1 is used and the QPS exceeds 1 time per second, it will be degraded.
@SentinelResource(value = "testHotKey")//The exception hit the foreground user interface and was not friendly
//The first parameter in the testHotKey method will be degraded as soon as the QPS exceeds 1 time per second
@SentinelResource(value = "testHotKey",blockHandler = "dealHandler_testHotKey")//With our own definition

The above case demonstrates that the first parameter p1 is current limited immediately after one click of QPS for more than 1 second, but we expect that when p1 parameter is a special value, its current limit value is different from that in normal times. For example, if the value of p1 is equal to 5, its threshold can reach 200

  • Modify configuration

    Configuration Description: when p1 is equal to 5, the threshold becomes 200. When p1 is not equal to 5, the threshold is the usual 1.

Note: the hotspot parameter must be a basic type or String

other:
@SentinelResource
It deals with violations of Sentinel console configuration, including the details of blockHandler method configuration;

RuntimeException
int age = 10/0, this is the runtime exception RunTimeException reported by java runtime, regardless of @ SentinelResource

summary
@SentinelResource supervisor has an error in configuration and operation. This is an exception

System rules

The system protection rule is to control the entrance flow at the application level, and monitor the application indicators from the dimensions of load, CPU utilization, average RT, entrance QPS and the number of concurrent threads of a single machine, so as to make the system run at the maximum throughput and ensure the overall stability of the system.

System protection rules apply the overall dimension, not the resource dimension, and are only effective for inlet traffic. For example, entrytype refers to the incoming traffic of the application (e.g. the incoming traffic of the application) or the incoming traffic of the application.

System rules support the following modes:

  • Load adaptation (only valid for Linux / Unix like machines): load1 of the system is used as the heuristic index for adaptive system protection. When system load1 exceeds the set heuristic value and the current number of concurrent threads exceeds the estimated system capacity, system protection will be triggered (BBR stage). The system capacity is estimated from the maxQps * minRt of the system. The setting reference value is generally CPU cores * 2.5.
  • CPU usage (version 1.5.0 +): when the system CPU utilization exceeds the threshold, the system protection is triggered (value range 0.0-1.0), which is sensitive.
  • Average RT: when the average RT of all inlet flows on a single machine reaches the threshold, the system protection is triggered, and the unit is milliseconds.
  • Number of concurrent threads: system protection is triggered when the number of concurrent threads of all inlet traffic on a single machine reaches the threshold.
  • Inlet QPS: when the QPS of all inlet flows on a single machine reaches the threshold, the system protection is triggered.

Official documents

@Use of SentinelResource

1. Current limiting and subsequent processing by resource name

  • Add a new RateLimitController
@RestController
public class RateLimitController
{
    @GetMapping("/byResource")
    @SentinelResource(value = "byResource",blockHandler = "handleException")
    public CommonResult byResource()
    {
        return new CommonResult(200,"Current limit test by resource name OK",new Payment(2020L,"serial001"));
    }
    public CommonResult handleException(BlockException exception)
    {
        return new CommonResult(444,exception.getClass().getCanonicalName()+"\t Service Unavailable");
    }
}
  • Start nacos, start sentinel, and go to sentinel console to add flow control rules

    Configuration Description:
    It means that if the number of queries is greater than 1 in 1 second, it will run to our custom flow, and the current is limited

    Click once a second, and no degradation can occur.

    Beyond the above, click crazy and return the self-defined current limit processing information. The current limit occurs

2. Current limiting and subsequent processing according to Url address

Add the following methods to the newly created class RateLimitController

@GetMapping("/rateLimit/byUrl")
    @SentinelResource(value = "byUrl")
    public CommonResult byUrl()
    {
        return new CommonResult(200,"Press url Current limiting test OK",new Payment(2020L,"serial002"));
    }

Sentinel console configuration, add the following configuration

visit http://localhost:8401/rateLimit/byUrl
Very slow access

Crazy Click http://localhost:8401/rateLimit/byUrl

Current limiting was successfully carried out

3. Customer defined current limiting processing logic

Problems with the above code:

  • By default, the system does not reflect our own business requirements.
  • According to the existing conditions, our customized processing method is coupled with the business code, which is not intuitive.
  • Each business method adds a bottom-up, which aggravates the code inflation.
  • The globally unified processing method is not reflected.

Create a CustomerBlockHandler class to customize the flow limiting processing logic

public class CustomerBlockHandler
{
    public static CommonResult handleException(BlockException exception){
        return new CommonResult(2020,"Customized current limiting processing information......CustomerBlockHandler");
    }
}


Add a new method in RateLimitController

     /**
     * Custom general current limiting processing logic
     blockHandlerClass = CustomerBlockHandler.class
     blockHandler = handleException
     The above configuration: find the handleException method in the CustomerBlockHandler class to handle it
     */
    @GetMapping("/rateLimit/customerBlockHandler")
    @SentinelResource(value = "customerBlockHandler",
            blockHandlerClass = CustomerBlockHandler.class, blockHandler = "handleException")
    public CommonResult customerBlockHandler()
    {
        return new CommonResult(200,"Custom current limiting processing logic by customer");
    }

Configuration further description

Access the microservice once after starting it http://localhost:8401/rateLimit/customerBlockHandler
Sentinel console configuration

Crazy access after starting the microservice http://localhost:8401/rateLimit/customerBlockHandler

More annotation attribute descriptions

The two main uses of @ SentinelResource annotation: current limiting control and fuse degradation are introduced. In addition, there are other more refined configurations in this annotation, such as ignoring some abnormal configurations, default degradation functions, etc. see the following description for details:

  • value: resource name, required (cannot be empty)
  • entryType: entry type, optional (EntryType.OUT by default)
  • blockHandler / blockHandlerClass:blockHandler corresponds to the name of the function handling BlockException. Optional. The access scope of the blockHandler function needs to be public, the return type needs to match the original method, the parameter type needs to match the original method, and finally add an additional parameter with the type of BlockException. The blockHandler function needs to be in the same Class as the original method by default. If you want to use functions of other classes, you can specify blockHandlerClass as the Class object of the corresponding Class. Note that the corresponding function must be a static function, otherwise it cannot be parsed.
  • Fallback: name of the fallback function, optional, used to provide fallback processing logic when throwing exceptions. The fallback function can handle all types of exceptions (except those excluded in exceptionsToIgnore). Fallback function signature and location requirements:
    • The return value type must be consistent with the return value type of the original function;
    • The method parameter list needs to be consistent with the original function, or an additional Throwable parameter can be used to receive the corresponding exception.
    • The fallback function needs to be in the same Class as the original method by default. If you want to use functions of other classes, you can specify fallbackClass as the Class object of the corresponding Class. Note that the corresponding function must be a static function, otherwise it cannot be parsed.
  • defaultFallback (since 1.6.0): the default fallback function name, which is optional. It is usually used for general fallback logic (that is, it can be used for many services or methods). The default fallback function can handle all types of exceptions (except those excluded in exceptionsToIgnore). If both fallback and defaultFallback are configured, only fallback will take effect. defaultFallback function signature requirements:
    • The return value type must be consistent with the return value type of the original function;
    • The method parameter list needs to be empty, or an additional Throwable parameter can be used to receive the corresponding exception.
    • The defaultFallback function needs to be in the same Class as the original method by default. If you want to use functions of other classes, you can specify fallbackClass as the Class object of the corresponding Class. Note that the corresponding function must be a static function, otherwise it cannot be parsed.
  • It is used to specify which exceptions will not be thrown in exception.0, but will not be included in exception.0

Note: the fallback function before 1.6.0 only handles DegradeException, not business exception.

In particular, if both blockHandler and fallback are configured, only blockHandler processing logic will be entered when BlockException is thrown due to current limiting degradation. If blockHandler, fallback and defaultFallback are not configured, BlockException will be thrown directly when current limiting is degraded

Service fuse function

  • sentinel integration ribbon+openFeign+fallback
  • Start nacos and sentinel

Create service provider cloudalibaba provider payment9003 / 9004

  • Create a new cloudalibaba provider payment9003

  • Modify the pom file and add the following dependencies

 <dependencies>
        <!--SpringCloud ailibaba nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency><!-- Introduce self defined api General package, you can use Payment payment Entity -->
            <groupId>com.zhubayi.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!-- SpringBoot integration Web assembly -->
        <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>
        <!--Daily general jar Package configuration-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
  • Add application YML profile
 
server:
  port: 9003

spring:
  application:
    name: nacos-payment-provider
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #Configure Nacos address

management:
  endpoints:
    web:
      exposure:
        include: '*'
  • Main startup class
@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain9003
{
    public static void main(String[] args) {
            SpringApplication.run(PaymentMain9003.class, args);
    }
}
  • controller
 
package com.zhubayi.springcloud.alibaba.controller;

import com.zhubayi.springcloud.entities.CommonResult;
import com.zhubayi.springcloud.entities.Payment;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;

@RestController
public class PaymentController
{
    @Value("${server.port}")
    private String serverPort;

    public static HashMap<Long,Payment> hashMap = new HashMap<>();
    static
    {
        hashMap.put(1L,new Payment(1L,"28a8c1e3bc2742d8848569891fb42181"));
        hashMap.put(2L,new Payment(2L,"bba8c1e3bc2742d8848569891ac32182"));
        hashMap.put(3L,new Payment(3L,"6ua8c1e3bc2742d8848569891xt92183"));
    }

    @GetMapping(value = "/paymentSQL/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id)
    {
        Payment payment = hashMap.get(id);
        CommonResult<Payment> result = new CommonResult(200,"from mysql,serverPort:  "+serverPort,payment);
        return result;
    }
}

  • 9004 module, too. Remember to change the port number and startup class



Start 9003 and 9004 and nacos
test http://127.0.0.1:9003/paymentSQL/1

test http://127.0.0.1:9004/paymentSQL/1

Create a new cloudalibaba consumer Nacos order84 service consumer module

  • Modify the pom file and add the following dependencies
<dependencies>
        <!--SpringCloud openfeign -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!--SpringCloud ailibaba nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>2.2.0.RELEASE</version>
        </dependency>
        <!--SpringCloud ailibaba sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
            <version>2.2.0.RELEASE</version>
        </dependency>
        <!-- Introduce self defined api General package, you can use Payment payment Entity -->
        <dependency>
            <groupId>com.zhubayi.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!-- SpringBoot integration Web assembly -->
        <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>
        <!--Daily general jar Package configuration-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
  • Create a new application YML profile
server:
  port: 8400


spring:
  application:
    name: nacos-order-consumer
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    sentinel:
      transport:
        #Configure Sentinel dashboard address
        dashboard: localhost:8080
        #The default port is 8719. If it is occupied, it will automatically start + 1 scanning from 8719 until an unoccupied port is found
        port: 8719

#The name of the microservice that the consumer will access (the microservice provider successfully registered in nacos)
service-url:
  nacos-user-service: http://nacos-payment-provider
  • Start class OrderNacosMain84
@EnableDiscoveryClient
@SpringBootApplication
public class OrderNacosMain84
{
    public static void main(String[] args) {
            SpringApplication.run(OrderNacosMain84.class, args);
    }
}

Ribbon collection

  • Create a new configuration class ApplicationContextConfig and inject beans into the container
@Configuration
public class ApplicationContextConfig
{
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate()
    {
        return new RestTemplate();
    }
}
  • controller
package com.zhubayi.springcloud.alibaba.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.zhubayi.springcloud.entities.CommonResult;
import com.zhubayi.springcloud.entities.Payment;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.sql.SQLException;
import java.util.concurrent.Executors;

@RestController
@Slf4j
public class CircleBreakerController
{
    public static final String SERVICE_URL = "http://nacos-payment-provider";

    @Resource
    private RestTemplate restTemplate;

    @RequestMapping("/consumer/fallback/{id}")
    @SentinelResource(value = "fallback") 
     public CommonResult<Payment> fallback(@PathVariable Long id)
    {
        CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/"+id,CommonResult.class,id);

        if (id == 4) {
            throw new IllegalArgumentException ("IllegalArgumentException,Illegal parameter exception....");
        }else if (result.getData() == null) {
            throw new NullPointerException ("NullPointerException,Should ID No corresponding record,Null pointer exception");
        }

        return result;
    }
}

Start port 84, test http://192.168.0.159:8400/consumer/fallback/1

It's refreshing

No configuration

When visiting http://192.168.0.159:8400/consumer/fallback/4

Give the customer the error page, unfriendly

Configure fallback only

Modify the controller and add a method to cover the bottom

public CommonResult handlerFallback(@PathVariable  Long id,Throwable e) {
        Payment payment = new Payment(id,"null");
        return new CommonResult<>(444,"Fundus abnormality handlerFallback,exception content  "+e.getMessage(),payment);
    }

Complete CircleBreakerController class

@RestController
@Slf4j
public class CircleBreakerController
{
    public static final String SERVICE_URL = "http://nacos-payment-provider";

    @Resource
    private RestTemplate restTemplate;

    @RequestMapping("/consumer/fallback/{id}")
    @SentinelResource(value = "fallback",fallback = "handlerFallback") //fallback is responsible for business exceptions
    public CommonResult<Payment> fallback(@PathVariable Long id)
    {
        CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/"+id,CommonResult.class,id);

        if (id == 4) {
            throw new IllegalArgumentException ("IllegalArgumentException,Illegal parameter exception....");
        }else if (result.getData() == null) {
            throw new NullPointerException ("NullPointerException,Should ID No corresponding record,Null pointer exception");
        }

        return result;
    }
    public CommonResult handlerFallback(@PathVariable  Long id,Throwable e) {
        Payment payment = new Payment(id,"null");
        return new CommonResult<>(444,"Fundus abnormality handlerFallback,exception content  "+e.getMessage(),payment);
    }
}

test

Successfully implemented the bottom method

Configure blockHandler only

Modify controller code

@RestController
@Slf4j
public class CircleBreakerController
{
    public static final String SERVICE_URL = "http://nacos-payment-provider";

    @Resource
    private RestTemplate restTemplate;

    @RequestMapping("/consumer/fallback/{id}")
    //@SentinelResource(value = "fallback",fallback = "handlerFallback") //fallback is only responsible for the business exception handlerFallback method
     @SentinelResource(value = "fallback",blockHandler = "blockHandler") //blockHandler is responsible for the degraded current limit configured in sentinel
    public CommonResult<Payment> fallback(@PathVariable Long id)
    {
        CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/"+id,CommonResult.class,id);
        if (id == 4) {
            throw new IllegalArgumentException ("Illegal parameter exception....");
        }else if (result.getData() == null) {
            throw new NullPointerException ("NullPointerException,Should ID No corresponding record");
        }
        return result;
    }
    public CommonResult handlerFallback(@PathVariable  Long id,Throwable e) {
        Payment payment = new Payment(id,"null");
        return new CommonResult<>(444,"fallback,No such flow,exception  "+e.getMessage(),payment);
    }
    public CommonResult blockHandler(@PathVariable  Long id,BlockException blockException) {
        Payment payment = new Payment(id,"null");
        return new CommonResult<>(445,"blockHandler-sentinel Current limiting,No such flow: blockException  "+blockException.getMessage(),payment);
    }
}

Add flow control rule

Crazy visit http://192.168.0.159:8400/consumer/fallback/1

Both fallback and blockHandler are configured

  • Modify @ SentinelResource annotation
 @SentinelResource(value = "fallback",fallback = "handlerFallback",blockHandler = "blockHandler")

If both blockHandler and fallback are configured, only blockHandler processing logic will be entered when BlockException is thrown due to current limiting degradation. Fallback is only responsible for the business exception handler fallback method, and blockHandler is responsible for the degraded current limit configured in sentinel

Ignore properties

 @SentinelResource(value = "fallback",fallback = "handlerFallback",blockHandler = "blockHandler",
            exceptionsToIgnore = {IllegalArgumentException.class}) //exceptionsToIgnore ignores this exception, that is, this exception is not handled

Feign series

  • Remember to add openfeign dependency to pom file
<!--SpringCloud openfeign -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
  • Modify the configuration file to activate Sentinel's support for Feign
# Activate Sentinel support for Feign
feign:
  sentinel:
    enabled: true  
  • Business class IPaymentService
/**
 * You cannot get exception information by using fallback,
 * If you want to get exception information, you can use the fallbackFactory parameter
 */
@FeignClient(value = "nacos-payment-provider",fallback = PaymentFallbackService.class)//Close 9003 service provider in call
public interface IPaymentService
{
    @GetMapping(value = "/paymentSQL/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id);
}
 

PaymentFallbackService

@Component
public class PaymentFallbackService implements IPaymentService{
    /**
     * Remote call
     *
     * @param id
     * @return
     */
    @Override
    public CommonResult<Payment> paymentSQL(Long id) {
        return new CommonResult<>(444,"Service degradation return",new Payment(id,"error"));
    }
}

controller

//==================OpenFeign
//terms of settlement https://blog.csdn.net/kongliand/article/details/108058831
    @Resource
    private IPaymentService ipaymentService;
    @GetMapping(value = "/consumer/openfeign/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id)
    {
        if(id == 4)
        {
            throw new RuntimeException("No this id");
        }
        return ipaymentService.paymentSQL(id);
    }
  • Add the EnableFeignClients annotation on the main startup class to start the remote call

Test: turn off 9003 and 9004, and then visit http://192.168.0.159:8400/consumer/openfeign/1

Downgrade succeeded.

Rule persistence

  • Once we restart the application, sentinel rules will disappear, and the production environment needs to persist the configuration rules
  • Persist the flow restriction configuration rules into Nacos and save them. Just refresh 8401 a rest address and the sentinel console
    You can see that as long as the configuration in Nacos is not deleted, the flow control rules on sentinel on 8401 remain valid
  • Modify cloudalibaba-sentinel-service8401
  • Add dependency
<!--SpringCloud ailibaba sentinel-datasource-nacos -->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
  • Modify profile
 
spring:
  cloud:
    sentinel:
      datasource:
        ds1:
          nacos:
            server-addr: localhost:8848
            dataId: ${spring.application.name}
            groupId: DEFAULT_GROUP
            data-type: json
            rule-type: flow

Full profile

 
server:
  port: 8401

spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #Nacos service registry address
    sentinel:
      transport:
        dashboard: localhost:8080 #Configure Sentinel dashboard address
        port: 8719
      #sentinel persistence
      datasource:
        ds1:
          nacos:
            server-addr: localhost:8848
            dataId: cloudalibaba-sentinel-service
            groupId: DEFAULT_GROUP
            data-type: json
            rule-type: flow

management:
  endpoints:
    web:
      exposure:
        include: '*'

feign:
  sentinel:
    enabled: true # Activate Sentinel support for Feign

  • Add Nacos business rule configuration

    Origin of configuration dataId, configuration group and configuration format


Configuration Description:

Resource: resource name;
limitApp: source application;
grade: threshold type, 0 indicates the number of threads, 1 indicates QPS;
count: single machine threshold;
strategy: flow control mode, 0 indicates direct, 1 indicates association, and 2 indicates link;
controlBehavior: flow control effect, 0 indicates rapid failure, 1 indicates Warm Up, and 2 indicates queuing;
clusterMode: whether to cluster.

After starting 8401, refresh sentinel and find that the business rules have changed

test
Quick access test interface http://192.168.0.159:8401/rateLimit/byUrl

Stop 8401 and look at sentinel

It is found that there are no flow control rules. Restart 8401 and see sentinel again
At the beginning, I still didn't see it. I went to visit it http://192.168.0.159:8401/rateLimit/byUrl perhaps http://127.0.0.1:8401/rateLimit/byUrl , the reconfiguration occurred and the persistence validation passed

Keywords: Java Spring Cloud Microservices

Added by NuLL[PL] on Mon, 17 Jan 2022 23:52:38 +0200