This article is the fifth part of SpringCloud Alibaba micro-service practice series. The main content is to use Sentinel to add the current limiting circuit breaker function to micro-service to prevent abnormal conditions from dragging down the application service. A series of articles, welcome to continue to pay attention.

Introduction to the

Sentinel is a lightweight flow control framework for distributed service framework. It mainly takes flow as the entry point to maintain system stability from multiple dimensions such as flow control, fusing degradation and system load protection. Sentinel is designed to replace Hystrix’s capabilities in SpringCloud. Sentinel has a more refined isolation level than Hystrix, and provides a Dashboard that can change current limiting circuit breakers online and is easier to use. To learn more, go to the Sentinel website.

Basis of preparation

To use the current limiting fusing capability provided by Sentinel, the following preparations are required:

  • I have already mentioned the installation of Sentinel in the first phase of SpringCloud Alibaba micro-service practice I – Basic environment preparation, you can check it out.
  • Importing Sentinel Imports Sentinel components into POM files that need to be configured with current limiting fuses
<! --Sentinel--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency>Copy the code

  • Custom Resources@SentinelResource

    We just have to add it to the relevant method@SentinelResourceAnnotated so that it can be used as a sentinel identification resource. Such as:
@GetMapping("/account/getByCode/{accountCode}")
@SentinelResource(value = "getByCode")
public ResultData<AccountDTO> getByCode(@PathVariable(value = "accountCode") String accountCode){
    log.info("get account detail,accountCode is :{}",accountCode);
    AccountDTO accountDTO = accountService.selectByCode(accountCode);
    return ResultData.success(accountDTO);
}Copy the code

  • Add the server address of Sentinel to the configuration file
server: port: 8010 spring: application: name: account-service cloud: nacos: discovery: server-addr: 192.168.0.107:8848/ sentinel: transport: # sentinel Server address Dashboard: 192.168.0.107:8858 # Cancel lazy loading and eager: trueCopy the code

After these steps we are ready to use the basic environment of Sentinel, let’s look at the specific configuration of current limiting fuses.

Current limiting

The concept that

producersaccout-serviceIt is a core service, and the maximum load capacity of the service is 60. If at some pointaccount-serviceWhen the number of requests spiked to 600, the service was definitely gg. So in order to protect ouraccout-serviceIf there are more than 60 requests per second, I’ll just throw it away and throw an exception to the consumer. No way! .

In a nutshell, limiting traffic protects one’s system by limiting what the caller can call on it.

Current limiting configuration

Ideal is full, reality is skinny. Since I am not familiar with pressure measuring tools such as Jmeter, for the convenience of testing, we willaccout-serviceSet the single-node QPS threshold to 5. If the QPS per second exceeds 5, the system discards the QPS.

The resource names here are the ones we’ve customized using the @SentinelResource annotation.

Open the browser and refresh the browser quickly. If the number of requests per second exceeds 5, you will see the following error:

In the backend service log you will see the following error log:

2019-12-10 14:22:31,948 ERROR [dispatcherServlet]: 755 - servlet.service () for Servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed;  nested exception is java.lang.reflect.UndeclaredThrowableException] with root cause com.alibaba.csp.sentinel.slots.block.flow.FlowException: nullCopy the code

Don’t panic. It means we’ve done what we came for. Limit the flow!

Custom exception

You can add custom exception methods to @SentinelResource by adding the blockHandler parameter. Such as:

@GetMapping("/account/getByCode/{accountCode}") @SentinelResource(value = "getByCode",blockHandler = "handleException") public ResultData<AccountDTO> getByCode(@PathVariable(value = "accountCode") String accountCode){ log.info("get account detail,accountCode is :{}",accountCode); AccountDTO accountDTO = accountService.selectByCode(accountCode); return ResultData.success(accountDTO); } /** * Custom exception policy * return values and parameters as the target function, Parameters may add BlockException * / public ResultData < AccountDTO > handleException (String accountCode, BlockException exception) { log.info("flow exception{}",exception.getClass().getCanonicalName()); Return resultdata. fail(900," The threshold is reached, do not access again!" ); }Copy the code

Note that the parameters and return values of the custom exception method must be the same as those of the target method. Blockexceptions can be appended to the parameters

The effect is as follows:

It’s so much more elegant than the previous error page, isn’t it?

Persistent configuration

Because the Sentinel configuration is stored in memory by default, data will be lost whenever the application is restarted or Sentinel is restarted. Nacos is used as the configuration center here to persist the traffic limiting configuration.

  • Modify the POM filesentinel-datasource-nacoscomponent
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>Copy the code

  • Modify application.yml to configure the data source for Sentinel
Spring: Cloud: Sentinel: datasource: DS: NACOS: server-addr: 10.0.10.48:8848 data-id: ${spring.application.name}-sentinel group-id: DEFAULT_GROUP rule-type: flowCopy the code

  • Establish a traffic limiting configuration in NACOSaccount-service-sentinel(Set the configuration format to JSON)
[
    {
        "resource": "getByCode",
        "limitApp": "default",
        "grade": 1,
        "count": 3,
        "strategy": 0,
        "controlBehavior": 0,
        "clusterMode": false
    }
]Copy the code

As you can see, the configuration rule above is an array type. Each object in the array is a configuration object for each protected resource. The attributes in each object are explained as follows:

Resource: indicates the name of the resource, which is the object of the traffic limiting rule

LimitApp: call source of flow control. If it is default, call source is not differentiated

Grade: indicates the type of traffic limiting threshold (QPS or number of concurrent threads). 0 indicates that traffic is limited based on the number of concurrent requests, and 1 indicates that traffic is controlled based on QPS

Count: traffic limiting threshold

Strategy: Invokes the relational traffic limiting policy

ControlBehavior: Flow control effect (direct reject, Warm Up, uniform queuing)

ClusterMode: indicates whether the clusterMode is used

  • Enter thesentinelLooking at the dashboard, sentinel automatically gets the configuration of NACOS

  • Refresh the browser call interface frequently to verify that the interface is normal for traffic limiting

fusing

The concept that

The consumer order-service needs to call product-Service to get the specific product before processing the rest of the business logic. But the product-service interface is not very stable and often throws exceptions; Alternatively, the response of the ORDER service is slow. If left unchecked, the order-service may be overwhelmed by the product-service. In order to protect the order-service, we need to fuse the product-Service interface.

In a word, fusing saves response time and maintains link stability by limiting calls to external systems.

Fusing configuration

There are three de-escalation strategies in Sentinel:

  • RT(Average response time) : When the average response time of a resource exceeds the threshold, the resource enters the quasi-degraded state. If five consecutive requests continue and their RT continues to exceed this threshold, calls to this method will automatically throw a DegradeException in the next time window. When the next time window arrives, five more requests are put in, and the judgment above is repeated.
  • Exception Ratio When the ratio of the number of exceptions per second to the number of passes of a resource exceeds the threshold, the resource enters the degraded state. That is, in the next time window, all calls to this method will automatically throw a DegradeException exception. The threshold range for the abnormal ratio is [0.0, 1.0], representing 0-100%.
  • Number of exceptions When the number of exceptions in the last one minute exceeds the threshold, the system fuses the resource.

First we modify the original interface to throw a Runtimeexception directly:

@GetMapping("/product/getByCode/{productCode}")
@SentinelResource(value = "/product/getByCode",fallback = "fallbackHandler")
public ResultData<ProductDTO> getByCode(@PathVariable String productCode){
    log.info("get product detail,productCode is :{}",productCode);
    ProductDTO productDTO = productService.selectByCode(productCode);
    throw new RuntimeException("error");
//        return ResultData.success(productDTO);
}Copy the code

Here we are going toproduct-serviceSet the following circuit breaker rules:

If the exception rate of /product/getByCode exceeds 50%, the fuse downgrade will be triggered within the next 2 seconds. By default, a DegradeException exception will be thrown, such as:

2019-12-10 19:35:53,764 ERROR [dispatcherServlet]: 755 - servlet.service () for Servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed;  nested exception is java.lang.reflect.UndeclaredThrowableException] with root cause com.alibaba.csp.sentinel.slots.block.degrade.DegradeException: nullCopy the code

Custom exception

Custom fusing exceptions are similar to current-limiting exceptions. We use the fallback attribute to specify the method for custom exceptions, such as:

@SentinelResource(value = "/product/getByCode",fallback = "fallbackHandler") public ResultData<ProductDTO> getByCode(@PathVariable String productCode){ ... } /** * Return values and parameters the same as the target function */ public ResultData<ProductDTO> fallbackHandler(String productCode){return Resultdata. fail(800," Service is fusioned, do not call!" ); }Copy the code

Note that the parameters and return values of the custom exception method are the same as those of the target method

The effect is as follows:

Persistent configuration

  • The introduction ofsentinel-datasource-nacosComponents can be configured as flow limiting
  • Modify application.yml to configure the data source for Sentinel
Spring: Cloud: Sentinel: datasource: DS: nacOS: server-addr: 192.168.0.106:8848 data-id: ${spring.application.name}-sentinel-degrade group-id: DEFAULT_GROUP rule-type: degradeCopy the code

  • Create a configuration file in NACOSproduct-service-sentinel-degradeTo perform the following configuration
[{"resource": "/product/getByCode", "count": 0.5, "grade": 1, "passCount": 0, "timeWindow": 2}]Copy the code

As you can see, the configuration rule above is an array type. Each object in the array is a configuration object for each protected resource. The attributes in each object are explained as follows:

Resource: Indicates the name of the resource, which is the object of the degradation rule

Count: the threshold

Grade: degraded mode 0:RT 1: abnormal ratio 2: abnormal number

TimeWindow: timeWindow in seconds

  • The sentinel automatically obtains the configuration of NACOS

Blood and tears

If the error Failed to fetch metric from occurs during the use of Sentinel, the specific performance is as follows:

Failed to fetch metric from < http://192.168.136.1:8719/metric? startTime=1563865044000&endTime=1563865050000&refetch=false> (ConnectionException: Connection refused: no further information)Copy the code

At this point you need to check the sentinel console service list to see if it matches your IP address. (I have installed virtual machines before, sentinel has been grabbing my virtual IP, I don’t know why…)

If you find that the listening address is not correct, you can add the client IP configuration to the Sentinel client configuration

Spring: Cloud: sentinel: transport: client-IP: 192.168.0.108Copy the code

At this point, we have added the current limiting fuse protection to our micro service, so we no longer need to worry about the impact of abnormal flow and the instability of the downstream system leading to their own services unavailable. So this period of “SpringCloud Alibaba micro-service actual combat five – current limit fuse” is the end, let’s see you next time!

Let me ask for one more wave of attention before I see you again!

series

  • SpringCloud Alibaba micro-service practice I – basic environment preparation
  • SpringCloud Alibaba micro-service practice ii – service registration
  • SpringCloud Alibaba micro-service practice 3 – service invocation
  • SpringCloud Alibaba Micro service practice 4 – version management

Please scan the code to follow the wechat public account or personal blog