Springcloud Day12 - spring cloud Alibaba sentinel service fusing and current limiting

Posted by wstran on Thu, 03 Feb 2022 11:22:52 +0100

15. Spring cloud Alibaba sentinel realizes fusing and current limiting

15.1 general

15.1.1 official website

english: https://github.com/alibaba/Sentinel

chinese: https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D

15.1.2 introduction

In one sentence, we explained the Hystrix before

15.1.3 where to go

https://github.com/alibaba/Sentinel/releases

15.1.4 what can I do

15.1.5 how to play

Official website: https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html#_spring_cloud_alibaba_sentinel

Various problems in service use:

  • Service avalanche
  • service degradation
  • Service fuse
  • Service current limiting

15.2 installation of Sentinel console

15.2.1 sentinel assembly consists of two parts

15.2.2 installation steps

1. Download

https://github.com/alibaba/Sentinel/releases

2. Run command

Premise:

  • java8 environment OK

  • Port 8080 cannot be occupied. There is Tomcat inside sentinel

Start:

java -jar sentinel-dashboard-1.7.0.jar

If the port is occupied, you can: Java - dserver port=8888 -jar sentinel-dashboard-1.7.0. jar

3. Access sentinel management interface

visit: http://localhost: The port number, login account and password are sentinel

15.3 initialization demonstration project

15.3.1 preconditions

Start Nacos and access http://192.168.174.128:8848/nacos/#/login Visit successful

15.3.2 establishment of sentinel8041

  • Build Module - cloudalibaba-sentinel-service8401
  • POM
<dependencies>
    <!--SpringCloud ailibaba nacos -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    <!--SpringCloud ailibaba sentinel-datasource-nacos For subsequent persistence-->
    <dependency>
        <groupId>com.alibaba.csp</groupId>
        <artifactId>sentinel-datasource-nacos</artifactId>
    </dependency>
    <!--SpringCloud ailibaba sentinel -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    </dependency>
    <!--openfeign-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    <!-- SpringBoot integration Web assembly+actuator -->
    <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>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
        <version>4.6.3</version>
    </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>
  • YML
server:
  port: 8401

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

management:
  endpoints:
    web:
      exposure:
        include: '*'
  • Main start
@EnableDiscoveryClient
@SpringBootApplication
public class MainApp8401
{
    public static void main(String[] args) {
        SpringApplication.run(MainApp8401.class, args);
    }
}
  • Business class FlowLimitController
@RestController
public class FlowLimitController
{

    @GetMapping("/testA")
    public String testA()
    {
        return "------testA";
    }

    @GetMapping("/testB")
    public String testB()
    {
        return "------testB";
    }
}

15.3.3 test results

  • Start Sentinel8888
  • Start microservice 8401
  • Start 8401 microservice and view sentienl console

Empty, nothing

The reason is that Sentinel uses lazy loading

Perform one visit: http://localhost:8401/testA And http://localhost:8401/testB

Conclusion: sentinel 8080 is monitoring microservice 8401

15.4 flow control rules

15.4.1 basic introduction

Further explanation

Difference between QPS and number of threads

QPS: resist the enemy outside the country, that is, there can only be QPS requests at a time
Number of threads: after entering, close the door and beat the dog. Only a few threads can be processed at a time, and the redundant tasks will not be processed

15.4.2 flow control mode

1. Direct (default)

Direct - > quick failure

  • Configuration and Description:

It means that one query within one second is OK. If it exceeds one, it will fail directly - quickly and report a default error

  • Test:

Quick click access http://localhost:8401/testA

Result: Blocked by Sentinel (flow limiting)

  • reflection

Directly call the default error message, which is technically OK. but, should we have our own follow-up processing? Similar to a fallback method?

2. Association

  • What is it?

When the associated resource reaches the threshold, it limits itself

When the resource B associated with A reaches the threshold, it limits the flow of A itself

B gets into trouble and A hangs up. For example, the payment interface reaches the threshold limit and the interface for placing orders

  • Configuration A

When the qps threshold of the associated resource / testB exceeds 1, the Rest access address of the current / testA is limited. When the associated resource reaches the threshold, the configured resource name is limited

  • postman simulates concurrent intensive access to testB

Normal access to testB succeeded

Create a new multithreaded collection group in postman

Add access address to new thread group

RUN

  • Click to visit http://localhost:8401/testA , test

Results: due to the high concurrency of a large number of threads accessing B, it was found that testA hung

3. Link

Multiple requests call the same microservice

15.4.3 flow control effect

1. Direct - > quick failure (default flow control processing)

Direct failure, throw an exception: Blocked by Sentinel (flow limiting)

Source code: com alibaba. csp. sentinel. slots. block. flow. controller. DefaultController

2. Preheating

  • Formula: divide the threshold value by coldfactor (the default value is 3), and the threshold value will not be reached until it is preheated for a long time

  • Official website: https://github.com/alibaba/Sentinel/wiki/%E6%B5%81%E9%87%8F%E6%8E%A7%E5%88%B6

The default coldFactor is 3, that is, the requested QPS starts from threshold / 3 and gradually rises to the set QPS threshold after preheating.

Current limiting cold start: https://github.com/alibaba/Sentinel/wiki/%E9%99%90%E6%B5%81 —%E5%86%B7%E5%90%AF%E5%8A%A8

  • Source code

com.alibaba.csp.sentinel.slots.block.flow.controller.WarmUpController

  • WarmUp configuration

The default coldfactor (threshold value of system initialization) is 3, that is, how long it takes to warm up the QPS from (threshold / 3) to the set QPS threshold.

In case, the threshold value is 10 and the preheating time is set to 5 seconds.
The threshold value of system initialization is 10 / 3, which is about 3, that is, the threshold value is 3 at the beginning; Then it took 5 seconds for the threshold to rise slowly and return to 10

  • test

Visit: multiple clicks http://localhost:8401/testB , not at the beginning, but gradually OK in the follow-up

  • Application scenario

For example, when the second kill system is turned on, there will be a lot of flow, which is likely to kill the system. The preheating method is to slowly put the flow in to protect the system and slowly increase the threshold to the set threshold.

3. Wait in line

  • Queue at a uniform speed to allow requests to pass at a uniform speed. The threshold type must be set to QPS, otherwise it is invalid.

Setting Meaning: / testA requests once per second. If it exceeds, it will queue up and wait. The waiting timeout is 20000 milliseconds

  • Official website:

https://github.com/alibaba/Sentinel/wiki/%E6%B5%81%E9%87%8F%E6%8E%A7%E5%88%B6

  • Source code

com.alibaba.csp.sentinel.slots.block.flow.controller.RateLimiterController

  • test

In the background print log, you can see that the 1s request is executed once

15.5 degradation rules

15.5.1 official website

https://github.com/alibaba/Sentinel/wiki/%E7%86%94%E6%96%AD%E9%99%8D%E7%BA%A7

15.5.2 basic introduction

RT (average response time in seconds)
The average response time exceeds the threshold and the request passed within the time window > = 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)

Abnormal ratio column (in seconds)
When QPS > = 5 and the abnormal proportion (second level statistics) exceeds the threshold, the degradation is triggered; When the time window is over, turn off the downgrade

Different constant (minute level)
When the abnormal constant (minute Statistics) exceeds the threshold, the degradation is triggered; After the demotion window is closed

  • Further explanation

Sentinel degradation will limit the call of a resource when it is in an unstable state in the call link (for example, the call timeout or the abnormal proportion increases), so as to make the request fail quickly and avoid affecting other resources and causing cascading errors.

When a resource is downgraded, calls to the resource will automatically fuse within the next downgrade time window (the default behavior is to throw DegradeException).

  • Sentinel's circuit breaker is not half open

In the half open state, the system will automatically detect whether there is any abnormality. 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. For details, please refer to Hystrix

15.5.3 actual combat of degradation strategy

1.RT

  • What is it?

  • test

Controller code addition

@GetMapping("/testD")
public String testD()
{
    //Pause the thread for a few seconds
    try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
    log.info("testD test RT");
    return "------testD";
}

to configure

jmeter pressure measurement

Access testD

Conclusion:

According to the above configuration, always call 10 threads (more than 5) to call testD in one second. We hope to finish 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

  • What is it?

  • test

Code modification:

@GetMapping("/testD")
public String testD()
{
    log.info("testD test RT");
    int age = 10/0;
    return "------testD";
}

to configure

jmeter

Conclusion:

According to the above configuration, if you access it alone, you must report an error once (int age = 10/0) and adjust it once;

After jmeter is enabled, the request is sent directly with high concurrency, and the multiple calls meet our configuration conditions. When the circuit breaker is opened (the fuse trips), the microservice is unavailable, and the error is no longer reported, but the service is degraded.

3. Different constants

  • What is it?

The time window must be greater than or equal to 60 seconds.

  • test

code:

@GetMapping("/testE")
public String testE()
{
    log.info("testE Abnormal test proportion");
    int age = 10/0;
    return "------testE Test exception ratio";
}

to configure:

Conclusion:

visit: http://localhost:8401/testE , the first access will definitely report an error because the divisor cannot be zero,
We see the error window, but after five times of error reporting, we enter the fuse and degrade.

15.6 current limiting

15.6.1 basic introduction

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

15.6.2 official website

https://github.com/alibaba/Sentinel/wiki/%E7%83%AD%E7%82%B9%E5%8F%82%E6%95%B0%E9%99%90%E6%B5%81

15.6.3 connecting the preceding and the following review start

There are two ways to find out the details: system default and customer customization

  • In the previous case s, the default prompt of sentinel system is Blocked by Sentinel (flow limiting)

  • Can we decide for ourselves? Similar to hystrix, if there is a problem with a certain method, find the corresponding downgrading method?

Conclusion: from HystrixCommand to @ SentinelResource

15.6.4 modifying 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)

Bottom source code: com alibaba. csp. sentinel. slots. block. BlockException

15.6.5 configuration

Current limiting mode only supports QPS mode, which is fixed and dead. (this is the hot spot)
@The method parameter index of SentinelResource annotation. 0 represents the first parameter, 1 represents the second parameter, and so on
The single machine threshold and the duration of the statistical window indicate that the current is limited when the time in this window exceeds the threshold.
The picture above is that if the first parameter has a value, the QPS of one second is 1, exceeding the current limit, and calling dealHandler_ after the current limit. Testhotkey supports methods.

Compare before and after using blockHandler:

  • @SentinelResource(value = "testHotKey"): the exception hits the foreground user interface, which is unfriendly
  • @SentinelResource(value = "testHotKey", blockHandler = "dealHandler_testHotKey"), the first parameter in the method testHotKey will be degraded as soon as the QPS exceeds 1 time per second And it uses our own definition, which is more flexible

15.6.6 testing

The following visits are non-stop

  • visit http://localhost:8401/testHotKey?p1=abc ===> error ×

  • visit http://localhost:8401/testHotKey?p1=abc&p2=33 ===> error ×

  • visit http://localhost:8401/testHotKey?p2=abc ===> right √

Conclusion: the first parameter p1 is current limited immediately after one click of QPS for more than 1 second

15.6.7 parameter exceptions

1. The above case demonstrates the first parameter p1. When the QPS is clicked once for more than 1 second, the current is limited immediately

2. Special cases

Generally, the current will be limited immediately after reaching the threshold value of 1 second

We expect that when p1 parameter is a special value, its current limit value is not the same as usual

If the value of p1 is equal to 5, its threshold can reach 200

3. Configuration

Click the Add button

4. Test

visit: http://localhost:8401/testHotKey?p1=5 , the system does not report an error no matter whether the mode exceeds 1s once

visit: http://localhost:8401/testHotKey?p1=3 , when the mode exceeds 1s once, an error is reported

Reason: when p1 equals 5, the threshold becomes 200 When p1 is not equal to 5, the threshold is the usual 1

5. Preconditions

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

15.6.8 others - add exceptions (described in detail later)

@SentinelResource
It deals with the violation of Sentinel console configuration, including the bottom handling configured by blockHandler method;

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

15.7 system rules

Because global configuration is effective for all requests of the system, there are few scenarios used in this chapter

15.7.1 what is it

https://github.com/alibaba/Sentinel/wiki/%E7%B3%BB%E7%BB%9F%E8%87%AA%E9%80%82%E5%BA%94%E9%99%90%E6%B5%81

Sentinel system's adaptive flow restriction controls the application inlet flow from the overall dimension. Combined with the monitoring indicators of application Load, CPU utilization, overall average RT, inlet QPS and the number of concurrent threads, the system inlet flow and system Load are balanced through adaptive flow control strategy, Let the system run at the maximum throughput as far as possible while ensuring the overall stability of the system.

15.7.2 description of various configuration parameters

15.7.3 configure global QPS

... slightly

15.8 @SentinelResource

15.8.1 current limiting by resource name + subsequent processing

1. Modify Module - cloudalibaba sentinel service8401

  • POM
<dependency><!-- Introduce self defined api General package, you can use Payment payment Entity -->
    <groupId>com.rg.springcloud</groupId>
    <artifactId>cloud-api-commons</artifactId>
    <version>${project.version}</version>
</dependency>
  • Business class 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");
    }

2. Configure flow control rules

  • Configuration steps

  • Graphic configuration and code relationship

  • It means that if the number of queries is greater than 1 in one second, we will run to our customized method to limit the current

3. Test

  • Click once in 1 second, OK
  • Beyond the above, click madly and return the self-defined current limit processing information, and the current limit occurs

4. Additional issues

At this time, close the query service 8401 and see that the sentinel console shows that the flow control rules disappear = = = > indicating that the configuration on sentinel is temporary

15.8.2 current limiting according to Url address + subsequent processing

If you limit the flow by accessing the URL, the default flow limiting processing information of Sentinel will be returned

  • Business 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"));
}
  • to configure:

  • test

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

The current limiting processing result of Sentinel will be returned

15.8.3 problems faced by the above scheme

1. The system is default and does not reflect our own business requirements.

2 according to the existing conditions, our customized processing method is coupled with the business code, which is not intuitive.

3 each business method adds a bottom-up, which aggravates the code inflation.

4. The overall unified processing method is not reflected.

15.8.4 customer defined current limiting processing logic

  • 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");
    }
}

  • Modify RateLimitController
	/**
     * Customize the general current limiting processing logic,
     blockHandlerClass = CustomerBlockHandler.class
     blockHandler = handleException2
     The above configuration: find the handleException2 method in the CustomerBlockHandler class for bottom handling
     */
	/**
     * Custom general current limiting processing logic
     */
@GetMapping("/rateLimit/customerBlockHandler")
@SentinelResource(value = "customerBlockHandler",
                  blockHandlerClass = CustomerBlockHandler.class, blockHandler = "handleException2")
public CommonResult customerBlockHandler()
{
    return new CommonResult(200,"Customized current limiting processing logic by customer");
}
  • Sentinel console configuration:

  • Test:

Crazy access: http://localhost:8401/rateLimit/customerBlockHandler , we customized it after the test

  • Further explanation

15.8.5 more annotation attribute descriptions

1.Sentinel mainly has three core APIs

  • SphU define resources
  • Tracer definition statistics
  • ContextUtil defines the context

2. Customize Resource

All code should be processed in a try catch finally manner, o(╥﹏╥) o

15.9 service fuse function

15.9.1 sentinel integration + Ribbon+fallback

1. Start nacos and sentinel

2. Build provider 9003 / 9004

  • Build Module - cloudalibaba provider payment9003 / 9004
  • POM
<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.rg.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>
  • YML
server:
  port: 9003

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

management:
  endpoints:
    web:
      exposure:
        include: '*'
  • Main start
@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain9003
{
    public static void main(String[] args) {
            SpringApplication.run(PaymentMain9003.class, args);
    }
}
  • Business class
@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;
    }
}
  • Test address: http://localhost:9003/paymentSQL/1 , can be accessed normally

3. Consumers 84

  • Build Module - cloudalibaba-consumer-nacos-order84
  • POM
<dependencies>
    <!--SpringCloud ailibaba nacos -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    <!--SpringCloud ailibaba sentinel -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    </dependency>
    <!-- Introduce self defined api General package, you can use Payment payment Entity -->
    <dependency>
        <groupId>com.rg.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>
  • YML
server:
  port: 84


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


##The name of the micro service that the consumer will visit (the micro service provider that has successfully registered into nacos)
service-url:
  nacos-user-service: http://nacos-payment-provider
  • Main start
@EnableDiscoveryClient
@SpringBootApplication
public class OrderNacosMain84
{
    public static void main(String[] args) {
            SpringApplication.run(OrderNacosMain84.class, args);
    }
}
  • Business class

ApplicationContextConfig

@Configuration
public class ApplicationContextConfig
{
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate()
    {
        return new RestTemplate();
    }
}

4.CircleBreakerController + test

Purpose: to verify that the fallback tube runs abnormally and the blockHandler tube configuration is illegal

  • Write basic 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") 
	public CommonResult <Payment> fallback(@PathVariable Long id){
        CommonResult result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/" + id, CommonResult.class, id);
        if(id==4){
            System.out.println("44444444444");
            throw new IllegalArgumentException("IllegalArgumentException,Illegal parameter exception...");
        }else if(result.getData()==null){
            System.out.println("111111111111111");
            throw new NullPointerException("NullPointerException,Should ID No corresponding record,Null pointer exception...");
        }
        return result;
    }
}
  • visit: http://localhost:84/consumer/fallback/1 Test, test successful! visit http://localhost:84/consumer/fallback/4 Jump to the error page But the error page is not user-friendly
  • Configure fallback only

code:

@RequestMapping("/consumer/fallback/{id}")
@SentinelResource(value = "fallback",fallback = "handlerFallback") //fallback is responsible for business exceptions
public CommonResult <Payment> fallback(@PathVariable Long id){
    CommonResult 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);
}

result:

Illustration:

  • Configure blockHandler only

code:

@RequestMapping("/consumer/fallback/{id}")
//@SentinelResource(value = "fallback",fallback = "handlerFallback") //fallback is responsible for business exceptions
@SentinelResource(value = "fallback",blockHandler = "blockHandler") //blockHandler is responsible for the degraded current limit configured in sentinel
public CommonResult <Payment> fallback(@PathVariable Long id){
    CommonResult 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);
}

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);
}

In this example, sentinel needs to be configured:

After the abnormality exceeds 2 times, the circuit breaker is opened, the power is cut off and the system is protected

result:

Illustration:

  • Both fallback and blockHandler are configured

code:

@RequestMapping("/consumer/fallback/{id}")
//@SentinelResource(value = "fallback")
//@SentinelResource(value = "fallback",fallback = "handlerFallback") //fallback is responsible for business exceptions
//@SentinelResource(value = "fallback",blockHandler = "blockHandler") //blockHandler is responsible for the degraded current limit configured in sentinel
@SentinelResource(value = "fallback",fallback = "handlerFallback",blockHandler = "blockHandler")
public CommonResult <Payment> fallback(@PathVariable Long id){
    CommonResult result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/" + id, CommonResult.class, id);
    if(id==4){
        System.out.println("44444444444");
        throw new IllegalArgumentException("IllegalArgumentException,Illegal parameter exception...");
    }else if(result.getData()==null){
        System.out.println("111111111111111");
        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);
}

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);
}

In this example, sentinel needs to be configured:

result:

If both blockHandler and fallback are configured, it will only enter the blockHandler processing logic when being degraded by current limiting and throwing BlockException. If the current limit rule is not exceeded, the fallback logic is followed

Illustration:

  • Ignore attribute - exceptionsToIgnore

code:

@RequestMapping("/consumer/fallback/{id}")
    //@SentinelResource(value = "fallback")
    //@SentinelResource(value = "fallback",fallback = "handlerFallback") //fallback is responsible for business exceptions
    //@SentinelResource(value = "fallback",blockHandler = "blockHandler") //blockHandler is responsible for the degraded current limit configured in sentinel
    @SentinelResource(value = "fallback",fallback = "handlerFallback",blockHandler = "blockHandler",exceptionsToIgnore = {IllegalArgumentException.class})
    public CommonResult <Payment> fallback(@PathVariable Long id){
        CommonResult result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/" + id, CommonResult.class, id);
        if(id==4){
            System.out.println("44444444444");
            throw new IllegalArgumentException("IllegalArgumentException,Illegal parameter exception...");
        }else if(result.getData()==null){
            System.out.println("111111111111111");
            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);
    }

    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);
    }

In this example, sentinel is not configured

Illustration:

Result: the program exception hit the front desk and was not friendly to users

15.9.2 sentinel integration + Feign+fallback

1. Modify module 84: 84 consumers call provider 9003, and feign components are generally on the consumer side

2. Modify code

  • POM
<!--SpringCloud openfeign -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
  • YML - activate Sentinel support for Feign
server:
  port: 84


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


##The name of the micro service that the consumer will visit (the micro service provider that has successfully registered into nacos)
service-url:
  nacos-user-service: http://nacos-payment-provider

# Activate Sentinel support for Feign

management:
  endpoints:
    web:
      exposure:
        include: '*'
feign:
  sentinel:
    enabled: true
  • Business class

Business interface with @ FeignClient annotation

@FeignClient(value = "nacos-payment-provider",fallback = PaymentFallbackService.class)//Close 9003 service provider in call
public interface PaymentService
{
    @GetMapping(value = "/paymentSQL/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id);
}

PaymentFallbackService class

@Component
public class PaymentFallbackService implements PaymentService
{
    @Override
    public CommonResult<Payment> paymentSQL(Long id)
    {
        return new CommonResult<>(444,"Service degradation return,There is no such flow information",new Payment(id, "errorSerial......"));
    }
}

controller

@RestController
@Slf4j
public class CircleBreakerController
{
//========================Sentinel combined with OpenFeign
@Resource
private PaymentService paymentService;

    @GetMapping(value = "/consumer/paymentSQL/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id){
        // if(id==4){
        //     throw new RuntimeException("no such id");
        // }
        return paymentService.paymentSQL(id);
    }
}
  • Main startup - add @ EnableFeignClients to launch the function of Feign
@EnableDiscoveryClient
@SpringBootApplication
@EnableFeignClients
public class OrderNacosMain84
{
    public static void main(String[] args) {
            SpringApplication.run(OrderNacosMain84.class, args);
    }
}

3. Test

visit: http://localhost:84/consumer/paymentSQL/1

Test 84 calls 9003. At this time, the 9003 micro service provider is deliberately closed. You can see that the 84 consumer side is automatically degraded and will not be consumed

15.9.3 comparison of fuse frames

15.10 rule persistence

15.10.1 what is it

Once we restart the application, sentinel rules will disappear, and the production environment needs to persist the configuration rules

15.10.2 how to play

Persist the flow restriction configuration rules into Nacos and save them. As long as you refresh a rest address of 8401, you can see the flow control rules on sentinel console. As long as the configuration in Nacos is not deleted, the flow control rules on sentinel on 8401 will remain valid

15.10.3 implementation steps

  • Modify cloudalibaba-sentinel-service8401
  • POM
<!--SpringCloud ailibaba sentinel-datasource-nacos -->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
  • YML - add Nacos data source configuration

  • Add Nacos business rule configuration

Content analysis:

[
    {
        "resource": "/rateLimit/byUrl",
        "limitApp": "default",
        "grade": 1,
        "count": 1,
        "strategy": 0,
        "controlBehavior": 0,
        "clusterMode": false
    }
]
resource: Resource name;
limitApp: Source application;
grade: Threshold type, 0 indicates the number of threads and 1 indicates the number of threads 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,2 Indicates waiting in line;
clusterMode: Cluster or not.
  • After starting 8401, refresh sentinel and find that the business rules have changed

15.10.4 testing

  • Fast access test interface, http://localhost:8401/rateLimit/byUrl , display: Blocked By Sentinel(flow limiting) error, indicating that the configuration file is effective
  • Stop 8401 and look at sentinel

  • Restart 8401 and see sentinel again

    Not at first glance. Just a moment Multiple calls http://localhost:8401/rateLimit/byUrl The reconfiguration occurred and the persistence verification passed

Topics: Java Spring Cloud Microservices