SpringBoot e-Commerce project mall (20K + STAR) address: github.com/macrozheng/…

Abstract

Spring Cloud Alibaba is committed to providing a one-stop solution for micro-service development. Sentinel, as one of its core components, has a series of service protection functions such as fusing and current limiting. This article will introduce its usage in detail.

Sentinel, a brief introduction to

With the popularity of microservices, stability between services becomes increasingly important. Sentinel takes flow as the entry point to protect the stability of service from multiple dimensions such as flow control, fusing downgrading and system load protection.

Sentinel has the following characteristics:

  • Rich application scenarios: the core scenarios of alibaba’s double Eleven traffic promotion in the past 10 years, such as Seckill, can fuse the downstream applications that are not available in real time;
  • Complete real-time monitoring: it also provides real-time monitoring function. In the console, you can see the second level data of a single machine connected to the application, or even the summary operation of a cluster of less than 500 machines.
  • Extensive open source ecosystem: provides out-of-the-box integration modules with other open source frameworks/libraries, such as Spring Cloud, Dubbo, gRPC integration;
  • Comprehensive SPI extension points: Provide easy-to-use, comprehensive SPI extension points. You can quickly customize logic by implementing extension points.

Install Sentinel console

Sentinel console is a lightweight console application that can be used to view stand-alone resource monitoring and cluster resource summary in real time, and provides a series of rule management functions such as flow control rules, degrade rules, hotspot rules, etc.

  • This is the Sentinel dashboard-1.6.3.jar file that can be downloaded from github.com/alibaba/Sen…

  • Enter the following command on the command line to run the Sentinel console:

Java jar sentinel - dashboard - 1.6.3. JarCopy the code
  • The Sentinel console runs on port 8080 by default, and the login account and password are bothsentinel, can be accessed through the following address:http://localhost:8080

  • The Sentinel console can view real-time monitoring data from a single machine.

Example Create the sentinel-service module

Here we create a sentinel-service module to demonstrate the fusing and limiting functions of Sentinel.

  • Add dependencies to pom.xml. Here we use Nacos as the registry, so we need to add Nacos dependencies as well:
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
Copy the code
  • Add the relevant configuration in application.yml, mainly configuring the address of Nacos and Sentinel console:
server:
  port: 8401
spring:
  application:
    name: sentinel-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 Configure the Nacos address
    sentinel:
      transport:
        dashboard: localhost:8080 # Configure the sentinel Dashboard address
        port: 8719
service-url:
  user-service: http://nacos-user-service
management:
  endpoints:
    web:
      exposure:
        include: The '*'
Copy the code

Current limiting function

Sentinel Starter provides limiting burials for all HTTP services by default, but we can also customize limiting traffic behaviors by using @SentinelResource.

Create RateLimitController class

Used to test fusing and current limiting functions.

/** * Created by macro on 2019/11/7. */
@RestController
@RequestMapping("/rateLimit")
public class RateLimitController {

    /** * Limit traffic by resource name. You need to specify flow limiting logic */
    @GetMapping("/byResource")
    @SentinelResource(value = "byResource",blockHandler = "handleException")
    public CommonResult byResource(a) {
        return new CommonResult("Limiting traffic by Resource Name".200);
    }

    /** * stream limiting by URL, with default stream limiting logic */
    @GetMapping("/byUrl")
    @SentinelResource(value = "byUrl",blockHandler = "handleException")
    public CommonResult byUrl(a) {
        return new CommonResult("Limiting traffic by URL".200);
    }

    public CommonResult handleException(BlockException exception){
        return new CommonResult(exception.getClass().getCanonicalName(),200); }}Copy the code

Traffic limiting by resource name

We can limit the flow according to the value (resource name) defined in the @SentinelResource annotation, but we need to specify the limiting logic.

  • Flow control rules can be configured on the Sentinel console. Since we use the Nacos registry, we start Nacos and Sentinel-Service first.

  • Because of using Sentinel lazy loading rules need us to access the interface, Sentinel console will have corresponding information service, the interface under our first visit: http://localhost:8401/rateLimit/byResource

  • Configure the flow control rule on the Sentinel console according to the value of the @sentinelResource annotation:

  • Quick access to the above interface, you can find that the return of their own defined flow limiting information:

Traffic limiting by URL

We can also limit the stream by the URL we visit, which will return the default stream limiting information.

  • Configure flow control rules on the Sentinel console using the URL accessed:

  • Many times to access the interface, will return the default current-limiting processing results: http://localhost:8401/rateLimit/byUrl

Custom flow limiting logic

You can customize the generic stream limiting logic and specify it in @sentinelResource.

  • Create the CustomBlockHandler class to customize the flow limiting logic:
/** * Created by macro on 2019/11/7. */
public class CustomBlockHandler {

    public CommonResult handleException(BlockException exception){
        return new CommonResult("Custom Flow limiting Information".200); }}Copy the code
  • Using custom stream limiting logic in RateLimitController:
/** * Created by macro on 2019/11/7. */
@RestController
@RequestMapping("/rateLimit")
public class RateLimitController {

    /** * Custom general flow limiting logic */
    @GetMapping("/customBlockHandler")
    @SentinelResource(value = "customBlockHandler", blockHandler = "handleException",blockHandlerClass = CustomBlockHandler.class)
    public CommonResult blockHandler(a) {
        return new CommonResult("Flow limiting succeeded".200); }}Copy the code

Function of fusing

Sentinel supports protection of inter-service calls and fusing of failed applications. Here we use RestTemplate to invoke the interface provided by the nacos-user-Service service to demonstrate this function.

  • First we need to wrap the RestTemplate instance with @SentinelRestTemplate:
/** * Created by macro on 2019/8/29. */
@Configuration
public class RibbonConfig {

    @Bean
    @SentinelRestTemplate
    public RestTemplate restTemplate(a){
        return newRestTemplate(); }}Copy the code
  • Add the CircleBreakerController class to define a call to the interface provided by nacos-user-Service:
/** * Created by macro on 2019/11/7. */
@RestController
@RequestMapping("/breaker")
public class CircleBreakerController {

    private Logger LOGGER = LoggerFactory.getLogger(CircleBreakerController.class);
    @Autowired
    private RestTemplate restTemplate;
    @Value("${service-url.user-service}")
    private String userServiceUrl;

    @RequestMapping("/fallback/{id}")
    @SentinelResource(value = "fallback",fallback = "handleFallback")
    public CommonResult fallback(@PathVariable Long id) {
        return restTemplate.getForObject(userServiceUrl + "/user/{1}", CommonResult.class, id);
    }

    @RequestMapping("/fallbackException/{id}")
    @SentinelResource(value = "fallbackException",fallback = "handleFallback2", exceptionsToIgnore = {NullPointerException.class})
    public CommonResult fallbackException(@PathVariable Long id) {
        if (id == 1) {
            throw new IndexOutOfBoundsException();
        } else if (id == 2) {
            throw new NullPointerException();
        }
        return restTemplate.getForObject(userServiceUrl + "/user/{1}", CommonResult.class, id);
    }

    public CommonResult handleFallback(Long id) {
        User defaultUser = new User(-1L."defaultUser"."123456");
        return new CommonResult<>(defaultUser,"Service degraded return".200);
    }

    public CommonResult handleFallback2(@PathVariable Long id, Throwable e) {
        LOGGER.error("handleFallback2 id:{},throwable class:{}", id, e.getClass());
        User defaultUser = new User(-2L."defaultUser2"."123456");
        return new CommonResult<>(defaultUser,"Service degraded return".200); }}Copy the code
  • Start nacos-user-Service and Sentinel-Service services:

  • Because we are not in nacos – user – defined service id for 4 users, all access to the following interface will return service degradation results: http://localhost:8401/breaker/fallback/4

{
	"data": {
		"id": - 1."username": "defaultUser"."password": "123456"
	},
	"message": "Service degraded return"."code": 200
}
Copy the code
  • Because we ignored NullPointerException with the exceptionsToIgnore parameter, service degradation did not occur when we accessed the interface null pointer: http://localhost:8401/breaker/fallbackException/2

Used in conjunction with Feign

Sentinel also ADAPTS to the Feign component, which can also be used for fuses when we use Feign for inter-service calls.

  • First we need to add Feign dependencies to pom.xml:
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
Copy the code
  • Turn on Sentinel support for Feign in application.yml:
feign:
  sentinel:
    enabled: true # Enable Sentinel support for Feign
Copy the code
  • Add @enableFeignClients to the application startup class.

  • Create a UserService interface that defines a call to the nacos-user-service service:

/** * Created by macro on 2019/9/5. */
@FeignClient(value = "nacos-user-service",fallback = UserFallbackService.class)
public interface UserService {
    @PostMapping("/user/create")
    CommonResult create(@RequestBody User user);

    @GetMapping("/user/{id}")
    CommonResult<User> getUser(@PathVariable Long id);

    @GetMapping("/user/getByUsername")
    CommonResult<User> getByUsername(@RequestParam String username);

    @PostMapping("/user/update")
    CommonResult update(@RequestBody User user);

    @PostMapping("/user/delete/{id}")
    CommonResult delete(@PathVariable Long id);
}
Copy the code
  • Create the UserFallbackService class to implement the UserService interface to handle service degradation logic:
/** * Created by macro on 2019/9/5. */
@Component
public class UserFallbackService implements UserService {
    @Override
    public CommonResult create(User user) {
        User defaultUser = new User(-1L."defaultUser"."123456");
        return new CommonResult<>(defaultUser,"Service degraded return".200);
    }

    @Override
    public CommonResult<User> getUser(Long id) {
        User defaultUser = new User(-1L."defaultUser"."123456");
        return new CommonResult<>(defaultUser,"Service degraded return".200);
    }

    @Override
    public CommonResult<User> getByUsername(String username) {
        User defaultUser = new User(-1L."defaultUser"."123456");
        return new CommonResult<>(defaultUser,"Service degraded return".200);
    }

    @Override
    public CommonResult update(User user) {
        return new CommonResult("Call failed, service degraded".500);
    }

    @Override
    public CommonResult delete(Long id) {
        return new CommonResult("Call failed, service degraded".500); }}Copy the code
  • Using UserService in UserFeignController to call the interface in nacos-user-service through Feign:
/** * Created by macro on 2019/8/29. */
@RestController
@RequestMapping("/user")
public class UserFeignController {
    @Autowired
    private UserService userService;

    @GetMapping("/{id}")
    public CommonResult getUser(@PathVariable Long id) {
        return userService.getUser(id);
    }

    @GetMapping("/getByUsername")
    public CommonResult getByUsername(@RequestParam String username) {
        return userService.getByUsername(username);
    }

    @PostMapping("/create")
    public CommonResult create(@RequestBody User user) {
        return userService.create(user);
    }

    @PostMapping("/update")
    public CommonResult update(@RequestBody User user) {
        return userService.update(user);
    }

    @PostMapping("/delete/{id}")
    public CommonResult delete(@PathVariable Long id) {
        returnuserService.delete(id); }}Copy the code
  • Call the following interface will happen service downgraded, return service degradation process information: http://localhost:8401/user/4
{
	"data": {
		"id": - 1."username": "defaultUser"."password": "123456"
	},
	"message": "Service degraded return"."code": 200
}
Copy the code

Use Nacos to store rules

By default, when we configure rules in the Sentinel console, the console pushes the rules to the client via the API and updates them directly into memory. Once we restart the application, the rule will disappear. Let’s take a look at how to persist configuration rules, using Nacos as an example.

Schematic diagram of principle

  • First, we directly create rules in the configuration center, and the configuration center pushes the rules to the client.

  • The Sentinel console also gets configuration information from the configuration center.

Function demonstration

  • Start by adding dependencies to pom.xml:
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
Copy the code
  • Modify the application.yml configuration file to add the Nacos data source configuration:
spring:
  cloud:
    sentinel:
      datasource:
        ds1:
          nacos:
            server-addr: localhost:8848
            dataId: ${spring.application.name}-sentinel
            groupId: DEFAULT_GROUP
            data-type: json
            rule-type: flow
Copy the code
  • Add configuration in Nacos:

  • Add the following configuration information:
[{"resource": "/rateLimit/byUrl"."limitApp": "default"."grade": 1."count": 1."strategy": 0."controlBehavior": 0."clusterMode": false}]Copy the code
  • Related parameters:

    • Resource: indicates the name of the resource.
    • LimitApp: Source app;
    • Grade: indicates the threshold type. 0 indicates the number of threads and 1 indicates QPS.
    • Count: single-node 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: Indicates whether to cluster.
  • It is found that the Sentinel console already has such lower limit flow rules:

  • Quick access to the test interface, it can be found that the flow limiting information is returned:

The resources

Spring Cloud Alibaba official documentation: github.com/alibaba/spr…

The module used

Springcloud - learning ├ ─ ─ nacos - user - serviceA service registered with NACOS that provides the CRUD interface to the User object└ ─ ─ sentinel - service-- Sentinel Functional Testing service
Copy the code

Project source code address

Github.com/macrozheng/…

The public,

Mall project full set of learning tutorials serialized, attention to the public number the first time access.