SpringCloud Netflix integrates Sentinel limited learning

Keywords: Java Spring Cloud

1, Abstract

1.1 introduction to sentinel

Sentinel is an open source project of Alibaba. It provides multiple dimensions such as flow control, fuse degradation and system load protection to ensure the stability between services. Official website: Home · alibaba/Sentinel Wiki · GitHub

Sentinel was born in Alibaba in 2012. Its main goal is flow control. From 2013 to 2017, sentinel developed rapidly and became a basic part of all micro services of Alibaba. It has been used in more than 6000 applications and covers almost all core e-commerce scenarios. In 2018, sentinel evolved into an open source project. In 2020, Sentinel Golang was released.

1.2 sentinel features

Rich application scenarios  : Sentinel has undertaken the core scenes of Alibaba's double eleven traffic promotion in recent 10 years, such as secsha (i.e
Burst flow control (within the range of system capacity), message peak shaving and valley filling, cluster flow control, real-time fuse, downstream unavailable applications, etc.
Complete real-time monitoring  : Sentinel also provides real-time monitoring function. You can see the single machine connected to the application in the console
Second level data, and even the summary operation of clusters with a scale of less than 500.
Extensive open source ecology  : Sentinel provides out of the box integration modules with other open source frameworks / libraries, such as Spring
Integration of Cloud, Dubbo and gRPC. You can quickly access Sentinel by introducing corresponding dependencies and simple configuration.

Perfect SPI extension point: Sentinel provides simple, easy-to-use and perfect SPI extension interface. You can quickly customize logic by implementing extension interfaces. For example, custom rule management, adapting dynamic data sources, etc.

Sentinel's ecosystem

2, Learning objectives

2.1. Complete the construction of springcloud netflix framework

2.2. Complete the integration of springCloud and Sentinel

2.3. Use Jemeter to test the current limiting function

2.4 summarize Sentinel current limiting principle

3.5. Services include: a cluster of eureka services (two deployed), a product service product server, an order service order server, and sentinel service. For eureka service deployment, see Eureka Server cluster service setup_ DayDayUp blog - CSDN blog.

 

3, Implementation steps

  3.3. Create a new project product server.

        3.3.1,New->File->Project->Spring Initializr

  Enter the project name and select the configuration.

   Select the dependent jar (product server lombok, spring boot starter web, spring cloud starter Netflix Eureka client):

Knowledge development:  

  1. Developer tools - > check Lombok. Function: Lombok provides some annotations to help us simplify and eliminate some necessary but bloated java code, such as   getting, setting, toString, equals, etc
  2. Web - > check Spring web, function: spring boot starter Web - > provide servlet container - tomcat, webmvc (restFul api), spring core jar, spring bean loading jar, log jar and other dependencies (without it, the project cannot be started)
  3. Spring cloud discovery - > check Eureka Discovery client: register the dependent jar of eureka's client
  4. Spring cloud Routing - > check OpenFeign. Function: jar. On which Feign interface depends

  3.4. Create a new order server service module in the same steps; Order server needs to rely on openFeign.

  3.5. Realize product query interface

q3.5.1. Create a new basic class request object ProductResponse and Response object Response.

package com.example.product.response;

import lombok.AllArgsConstructor;
import lombok.Data;

import java.math.BigDecimal;

@Data
@AllArgsConstructor
public class ProductResponse {


    private Integer id;

    private String name;

    private Integer num;

    private BigDecimal price;

}
package com.example.product.response;

import lombok.Getter;
import lombok.Setter;

@Setter
@Getter
public class Response<T>{

    private Integer errorCode;

    private String errorMsg;

    private T data;

    public Response(Integer errorCode, String errorMsg, T data) {
        this.errorCode = errorCode;
        this.errorMsg = errorMsg;
        this.data = data;
    }

    public static <T> Response<T> success(T data){
        return new Response<>(null, null, data);
    }


}

            3.5.3. application.yml configuration of product server.

spring:
  application:
    name: product-server
server:
  port: 8081
  servlet:
    context-path: /product
#Configure registered eureka address (with user name and password)
eureka:
  client:
    serviceUrl:
      defaultZone: http://eureka:eureka@localhost:8671/eureka,http://eureka:eureka@localhost:8672/eureka

        3.5.4,   pom.xml configuration of product server.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>product-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>product-server</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>2020.0.4</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </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>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

        3.5.5 simple implementation of product query interface

package com.example.product.controller;

import com.example.product.response.ProductResponse;
import com.example.product.response.Response;
import com.example.product.service.ProductService;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

@RestController
public class ProductController {

    @Resource
    private ProductService productService;

    @RequestMapping(value = "/select/{id}")
    public Response<ProductResponse> selectById(@PathVariable Integer id){
        return Response.success(productService.queryById(id));
    }

}
package com.example.product.service;

import com.example.product.response.ProductResponse;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

@Service
public class ProductService {

    private static Map<Integer, ProductResponse> productHashMap = new HashMap<>();
    static {
        productHashMap.put(1, new ProductResponse(1, "Refrigerator", 5, new BigDecimal(20000)));
        productHashMap.put(2, new ProductResponse(2, "air conditioner", 9, new BigDecimal(30000)));
        productHashMap.put(3, new ProductResponse(3, "Washing machine", 8, new BigDecimal(5000)));
    }

    public ProductResponse queryById(Integer id){
        return productHashMap.get(id);
    }
}

3.6. Order server uses feign to call the product server query interface

        3.6.1 create a new basic class request object ProductResponse and response object response (which can be made into jar dependent order).

package com.example.order.response;

import lombok.AllArgsConstructor;
import lombok.Data;

import java.math.BigDecimal;

@Data
@AllArgsConstructor
public class ProductResponse{

    private Integer id;

    private String name;

    private Integer num;

    private BigDecimal price;

}
package com.example.order.response;

import lombok.Getter;
import lombok.Setter;

@Setter
@Getter
public class Response<T>{

    private Integer errorCode;

    private String errorMsg;

    private T data;

    public Response(Integer errorCode, String errorMsg, T data) {
        this.errorCode = errorCode;
        this.errorMsg = errorMsg;
        this.data = data;
    }

    public static <T> Response<T> success(T data){
        return new Response<>(null, null, data);
    }


}

        3.6.2 implementation of feign interface

package com.example.order.feign;


import com.example.order.response.ProductResponse;
import com.example.order.response.Response;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(name = "product-server", path = "/product", fallbackFactory = ProductMicroServerFallbackFactory.class)
public interface ProductMicroServer {

    @GetMapping(value = "/select/{id}")
    Response<ProductResponse> selectById(@PathVariable Integer id);
}
package com.example.order.feign;

import com.example.order.response.ProductResponse;
import com.example.order.response.Response;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;

@Service
public class ProductMicroServerFallback implements ProductMicroServer{
    @Override
    public Response<ProductResponse> selectById(Integer id) {
        return Response.success(new ProductResponse(0, "lollipop(Bottom goods)", 1, new BigDecimal(0.5)));
    }
}
package com.example.order.feign;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Slf4j
@Service
public class ProductMicroServerFallbackFactory implements FallbackFactory<ProductMicroServer> {

    @Resource
    private ProductMicroServerFallback productMicroServerFallback;

    @Override
    public ProductMicroServer create(Throwable cause) {
        log.error("ProductMicroServerFallback->selectById(Integer id) exception:", cause);
        return productMicroServerFallback;
    }
}

  The startup class adds the annotation to activate feign interface and specifies the scanning package.

package com.example.order;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

@EnableFeignClients(value = "com.example.order.feign")
@SpringBootApplication
public class OrderServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(OrderServerApplication.class, args);
    }

}

     3.6.3. application.yml and pom.xml configuration

        application.yml adds sentinel configuration and support.

spring:
  application:
    name: order-server
  cloud:
    sentinel:
      transport:
        #Specify the communication port of the console. You can specify an unused port at will
        port: 8719
        #sentinel dashboard address
        dashboard: localhost:8080
server:
  port: 8082
  servlet:
    context-path: /order

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

#Configure registered eureka address (with user name and password)
eureka:
  client:
    serviceUrl:
      defaultZone: http://eureka:eureka@localhost:8671/eureka

  pom.xml adds sentinel's jar dependency.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>order-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>order-server</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>2020.0.4</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </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>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
            <version>2021.1</version>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

3.7 start the product server and order server services and check whether they are registered with eureka.

  Access the order server query interface and check that feign service is called successfully: http://localhost:8082/order/query/1

 

3.7. Download sentinel and start it.

        3.7.1. Download address: Console · alibaba/Sentinel Wiki · GitHub

        3.7.2 start sentinel

java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8719 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar

Startup log:

  Enter the port number 8080 when sentinel is started by the browser, http://localhost:8080 , as follows (the default login password is sentinel).

After successfully accessing the product query commodity interface once, refresh the sentinel panel again, and order server appears, indicating that the integration is effective.

  3.8. Download jemeter pressure measurement at: Apache JMeter - Apache JMeter™

        3.8.1 run bin\jemeter.bat file to start jemeter (Chinese operation interface can be selected).

          3.8.2 add thread group test.

        3.8.3. Add http request.

          3.8.4. View the number of added results.

          3.8.5. Add http interface configuration

        3.8.6. Set the number of concurrent threads.

3.9 find the specified interface on the sentinel panel and set the current limiting policy.

  3.10. QPS current limiting - we set the QPS of the query/{id} interface to 8 requests / second.

  Start jemeter pressure test.    ​​​​​​​

  After startup, check the number of results and find that the qps current limit of sentinel is effective.

  Check sentinel's current limiting data and monitoring.

  3.10 thread data flow restriction - set to 5 requests per second.

sentinel concurrent thread limit setting.

  The number of jemeter pressure measurement threads is set to 300 threads per second (my computer has 4 cores).

  Pressure test results:

 

 

  reference resources: Console · alibaba/Sentinel Wiki · GitHub

 

 

 

 

 

Posted by johncrook on Sat, 25 Sep 2021 11:06:23 -0700