SpringCloud Alibaba 초보자부터 숙련자까지 - Sentinel

SpringCloud Alibaba 초보자부터 숙련자까지 - Sentinel

1. 인프라 구축

여기에 표시된 데모는 Maven의 상위-하위 프로젝트를 통해 관리됩니다. 부모-자식 관찰 관리를 사용하면 다음과 같은 이점이 있습니다.

  • 1. 코드는 중앙 집중화되어 중앙 집중식 관리, 다운로드가 용이합니다.
  • 2. 중앙 집중식 관리로 학습 비용이 낮고 프로젝트를 더 쉽게 수용할 수 있습니다.

1. 상위 프로젝트 생성

IDEA를 사용하세요. file–>new–>project–>maven 상위 프로젝트를 생성합니다. 상위 프로젝트는 pom에 있어야 컴파일할 때 상위 프로젝트가 하위 프로젝트를 관리하는 목적을 달성할 수 있습니다. pom에 없으면 우리는 상위 프로젝트 아래에 생성할 수 없습니다. 하위 프로젝트가 올바르게 생성되었습니다.
이 데모는 중앙 집중식 버전 관리를 채택하고 있으며 다음 세 가지 버전만 제한하면 됩니다.버전을 지정하려면 이를 dependencyManagement에 넣고 유형과 범위를 동시에 선언하면 전역 구성 요소 버전 제어를 달성할 수 있습니다. 이 기능은 상위 태그와 비슷하지만 상위는 버전 종속성을 관리하기 위해 상위 프로젝트만 선언할 수 있습니다. dependencyManagement의 종속성은 여러 종속성을 지원할 수 있습니다.

  • SpringBoot 버전: 2.6.11
  • 스프링클라우드 버전: 2021.0.4
  • SpringCoul 알리바바 버전: 2021.0.4.0

alibaba, cloud 및 boot 간의 버전 대응이 명확하지 않은 경우 여기에서 확인할 수 있습니다. SpringCloud 구성 요소 버전 종속성

<dependencyManagement>
	<dependencies>
		<dependency>
		    <groupId>com.alibaba.cloud</groupId>
		    <artifactId>spring-cloud-alibaba-dependencies</artifactId>
		    <version>${Spring-cloud-alibaba-version}</version>
		    <type>pom</type>
		    <scope>import</scope>
		</dependency>
	<dependencies>	
</dependencyManagement>

다음은 상위 프로젝트의 전체 pom 파일입니다.

<?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来管理整体的jar的版本,统一放在dependencymanager中进行管理-->
    <!--<parent>-->
    <!--<groupId>org.springframework.boot</groupId>-->
    <!--<artifactId>spring-boot-starter-parent</artifactId>-->
    <!--<version>3.1.3.RELEASE</version>-->
    <!--<relativePath/> &lt;!&ndash; lookup parent from repository &ndash;&gt;-->
    <!--</parent>-->
    <groupId>com.cheng</groupId>
    <artifactId>spring-cloud-alibaba-base</artifactId>
    <packaging>pom</packaging>
    <version>1.0.0</version>
    <modules>
        <module>order-server</module>
        <module>stock-server</module>
    </modules>

    <name>spring-cloud-alibaba-base</name>
    <description>alibaba父工程</description>
    <properties>
        <java.version>8</java.version>
        <Spring-boot-version>2.6.11</Spring-boot-version>
        <Spirng-cloud-version>2021.0.4</Spirng-cloud-version>
        <Spring-cloud-alibaba-version>2021.0.4.0</Spring-cloud-alibaba-version>
    </properties>

    <dependencyManagement>
        <!--通过此模块来规范boot和cloud的所有组件版本,所有的子工程将不需要考虑组件的版本问题-->
        <dependencies>
            <!--这种写法和写在parent中作用一样,注意type和scope不可省略-->
            <!--这种写法的优点是可以声明多个父级的项目包版本依赖,而parent只能由一个-->
            <!--这是springboot相关包的版本管理-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-parent</artifactId>
                <version>${Spring-boot-version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!--这是alibaba组件的版本管理-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${Spring-cloud-alibaba-version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!--这是cloud的组件的版本管理,也可以使用pring-cloud-dependencies-parent,但是使用下面的更好-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${Spirng-cloud-version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>

    </dependencyManagement>


    <!--dependencies中的包会直接被子工程继承,而dependencyManagement的包不手动引入,则不会继承-->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2. 하위 프로젝트 생성

하위 프로젝트 생성도 동일합니다. 예를 들면 다음과 같습니다: 상위 프로젝트를 마우스 오른쪽 버튼으로 클릭->new->module->spring-initializr. 여기서는 Spring-initializr을 사용하지 않습니다. Maven도 사용 가능하지만 spring-initializr을 사용하는 것이 더 편리하며 시작 클래스, 구성 파일 등을 직접 만들 필요가 없습니다. 귀하의 IDEA가 비교적 새로운 경우(내가 아는 한 IDEA2021 이하에서는 사용할 수 없는 것 같습니다) spring-initializr를 사용하여 타사 스캐폴딩을 지정할 수도 있습니다. Alibaba의 타사 스캐폴딩 주소를 사용하는 것이 좋습니다. . https://start.aliyun.com , 이 스캐폴딩은 Springcloud 구성 요소에 더 친숙하며 더 많은 Alibaba 구성 요소도 포함합니다
( 참고: IDEA의 커뮤니티 버전은 Spring 초기화 기능을 지원하지 않습니다 )
여기에 이미지 설명을 삽입하세요.
. 다음은 다음의 pom 파일입니다. 하위 프로젝트:

<?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>com.cheng</groupId>
        <artifactId>spring-cloud-alibaba-base</artifactId>
        <version>1.0.0</version>
    </parent>
    <groupId>com.cheng</groupId>
    <artifactId>order-server</artifactId>
    <version>1.0.0</version>
    <name>order-server</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

이 시점에서는 간단히 선반을 구축한 다음 각 서비스에 대해 다양한 구성 요소와 종속성을 도입합니다.
위의 부모-자식 프로젝트 생성이 충분히 상세하지 않다고 생각되면 여기를 읽어보는 것이 좋습니다: Maven을 사용하여 부모-자식 프로젝트 생성에 대한 자세한 설명

2. Sentinel과 Spring Cloud의 통합

Sentinel에 대한 자세한 소개는 공식 문서를 참조하세요.
Sentinel 공식 웹사이트
Sentinel의 github에 대한 자세한 내용은 여기를 참조 하세요.

1. 마이크로서비스에 발생할 수 있는 문제

  • 1. 트래픽이 급증하고 CPU 용량이 너무 높아 요청을 정상적으로 처리할 수 없습니다.
  • 2. 데이터가 워밍업되지 않아 발생하는 캐시 손상
  • 3. 메시지가 너무 많으면 메시지 백로그가 발생합니다.
  • 4. 느린 SQL로 인해 데이터베이스 연결이 가득 찼습니다.
  • 5. 타사 시스템이 응답하지 않으며 반복적으로 클릭하면 스레드가 꽉 찼습니다.
  • 6. 시스템 비정상 메모리 OOM을 정상적으로 해제할 수 없습니다.
  • 7. 서버 메모리 병목 현상, 프로그램 비정상 종료

위의 문제는 서비스의 단일 장애 지점으로 이어질 수 있으며, 서비스에 추가 처리가 추가되지 않은 경우 특정 시스템이 중단되면 이를 의존하는 시스템에도 이상이 발생하게 되며 결과적으로 서비스에 문제가 발생하게 됩니다. 도미노처럼 차례로 발생하고, 결국에는 넓은 지역의 서비스를 이용할 수 없게 되는 현상을 흔히 서비스 사태라고 부른다. 서비스의 눈사태는 견딜 수 없으며 일단 발생하면 기본적으로 시스템을 사용할 수 없게 되어 사용자에게 매우 불친절하고 큰 사용자 손실로 이어질 것입니다.
따라서 서비스 비가용성 문제를 시나리오 기반으로 해결해야 하는데 이를 위해 Sentinel을 사용하는데 분산 시스템의 트래픽 가드라고 하며 시스템의 안정성(신뢰성)과 복구를 보장하는 것이 주요 역할이다.(복원력) ), 여러 시스템의 내결함성 메커니즘을 지원하며 일반적인 시스템에는 다음이 포함됩니다.

  • 1. 타임아웃 메커니즘
    : 타임아웃 시간을 설정하고, 지정된 시간 내에 처리하며, 타임아웃 이후에는 타임아웃 로직을 처리합니다.
  • 2. 전류 제한 메커니즘은
    QPS를 기반으로 서비스 프로세스를 제어할 수 있습니다.
  • 3. 스레드 격리 메커니즘은
    스레드 풀을 사용하여 요청을 관리하고, 초과 부분에 대해 다른 처리 전략을 정의할 수 있습니다.
  • 4. 서비스 회로 차단기:
    서비스가 정의된 회로 차단기 표준 또는 다운그레이드 표준에 도달하면 서비스에 대한 2차 정보 처리가 수행됩니다. 이는 메시지 대기열 처리일 수도 있고, 최종 일관성 처리를 기다리기 위해 데이터베이스에 저장될 수도 있습니다.
  • 5. 서비스 다운그레이드
    서비스 예외 처리 세분성에 서비스의 2차 처리가 필요하다는 점을 제외하면 이 정서가 실제로 서비스 서킷 브레이커와 유사하다고 생각합니다.

Sentiael은 위의 시나리오를 훌륭하게 처리했으며 높은 동시성 시나리오에서 서비스의 가용성과 안정성을 잘 보장할 수 있습니다. Alibaba에서 생산하는 제품은 품질이 좋아야 합니다. 그냥 사용하면 끝입니다. 현재 Sentinel은 시장에 나와 있는 유일한 오픈 소스입니다. 이전 버전인 hystrix는 업데이트를 중단했습니다. 다음은 간단한 비교입니다.
여기에 이미지 설명을 삽입하세요.

2.SpringCloud는 Sentinel을 통합하여 대시보드를 구축합니다.

Sentinel은 모든 Springboot 프로젝트에 통합될 수 있으며 alibaba는 sentinel의 빠른 통합을 용이하게 하기 위해 해당 스타터도 제공합니다. Alibaba에서 제공하는 스타터에는 우리가 사용해야 하는 모든 jar 패키지가 포함되어 있습니다(OpenFeign, Gateway 등을 통합하는 jar 제외). . 함께 경험해 보세요. 여기에 사용된 버전은 최상위 버전과 일치하도록 선언할 필요가 없습니다. 실제 사용된 것은 Sentinel1.8.5 입니다.

Dashboard 공식 문서 주소: Sentinel console
Dashboard 다운로드 주소: Sentinel-Dashboard 다운로드
Dashboard 기본 계정 비밀번호: sentinel/sentinel은
빌드가 매우 간단합니다. 공식 웹사이트에서 해당 jar을 다운로드하기만 하면 됩니다. Dashboard는 표준 SpringBoot 프로젝트입니다. java 명령을 사용하여 직접 시작할 수 있습니다.

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

기본 사용자 이름과 비밀번호를 변경하려면 사용자 이름과 비밀번호 매개변수를 추가하면 됩니다.

java -Dserver.port=8080 \
-Dcsp.sentinel.dashboard.server=localhost:8080 \
-Dproject.name=sentinel-dashboard \
-Dsentinel.dashboard.auth.username=admin \ 
-Dsentinel.dashboard.auth.password=admin \ 
-jar sentinel-dashboard-1.8.5.jar

빠르게 검증하고 싶다면 Git Bash로 로컬에서 시작해 빠르게 검증할 수 있고, 또
대시보드 자체가 대시보드에 표시되는 것을 원하지 않는 경우(사용하는 것을 제어하는 ​​것은 사실상 쓸모가 없다) project.name을 직접 취소할 수 있으며 다음과 같이 csp.sentinel.dashboard.server 구성이 정상입니다.

java -Dserver.port=8080 \
-Dsentinel.dashboard.auth.username=admin \
-Dsentinel.dashboard.auth.password=admin \
-jar sentinel-dashboard-1.8.5.jar

실제로 사용해보면 실제로 사용해도 괜찮습니다.
여기에 이미지 설명을 삽입하세요.
다양한 내부 구성에 대해서는 자세히 설명하지 않겠지만, 나중에 Zhuo Yi가 소개하겠습니다.

3 SpringCloud는 Sentinel을 통합합니다.

  • 1. 관련 jar 소개
    <!--sentinel依赖-->
    <dependency>
       <groupId>com.alibaba.cloud</groupId>
       <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    </dependency>
    
  • 2 설정 추가
    Sentinel이 Dashboard와 정상적으로 통신할 수 있도록 Dashboard의 주소를 지정하는 단계입니다.
    # 已省略关系不大的配置
    spring:
      application:
        # sennel使用该名称注册到Dashboard
        name: stock-server 
      cloud:
        sentinel:
          transport:
            port: 8719 # dashboard控制面版与sentinel通信的本地端口
            dashboard: 127.0.0.1:8080   # sentinel控制面板地址
    
  • 3. 서비스가 대시보드에 정상적으로 등록되었는지 테스트합니다.
    기본적으로 서비스가 시작된 후 대시보드에 직접 등록되지는 않습니다. 요청이 들어올 때만 서비스가 대시보드에 등록되므로 서비스가 필요합니다. 서비스 요청을 시뮬레이션한 후 정상적으로 진행되며, 대시보드에 서비스가 표시되면 각 서비스 아래에 다음과 같은 구성 모니터링 메뉴가 있습니다. 여기에 여러번 요청을 해서 실시간 모니터링 데이터를 볼 수 있게 되었는데, 실시간 데이터가 없으면 여기에는 표시가 되지 않습니다.
    여기에 이미지 설명을 삽입하세요.
    이로써 센티넬과 대시보드의 구축이 간단하게 완료되었습니다.

3. 서비스 다운그레이드

다섯 가지 규칙에 대해 자세히 설명하기 전에 먼저 서비스 저하에 대해 이야기해야 합니다.서비스 다운그레이드는 사용자 경험을 향상시키기 위한 방법으로, 시스템상의 이유로 사용자의 요청이 거부되면 시스템은 사용자가 수용할 수 있지만 사용자가 만족할 수 없는 미리 설정된 결과를 반환합니다.. 서비스 성능 저하가 임계값에 도달하면 서킷 브레이커가 발동되는데, 먼저 Spring Cloud의 일반적인 성능 저하 처리 방법을 살펴보자.

1 서비스 다운그레이드 - 센티넬

여기서는 Sentinel의 Annotation인 @SentinelResource를 사용해야 하는데, 이 Annotation이 Sentinel의 핵심 Annotation이다. 이 Annotation은 서비스 다운그레이드에만 사용되며, 리소스를 등록할 필요가 없습니다(값을 선언한 경우에만 등록됩니다). 이 주석에는 서비스 다운그레이드와 관련된 네 가지 속성이 있습니다.
@SentinelResource 주석에 대한 공식 세부 소개: Annotation @SentinelResource

  • fallback 및 fallbackClass 다운그레이드
  • defaultFallback 및 fallbackClass 다운그레이드
  • ExceptionsToIgnore 속성: 예외를 무시합니다. 무시된 예외는 다운그레이드를 트리거하지 않습니다.
  • 1. 다운그레이드: fallback
    fallback은 다운그레이드 처리 방법의 메서드 이름인 문자열을 전달해야 합니다. 그렇다면 이 메서드는 어떻게 작성해야 할까요? 다운그레이드 메서드는 다음 규칙을 따라야 합니다.

    • ① 반환 값 유형은 원래 함수 반환 값 유형과 일치해야 합니다.
    • ② 메소드 매개변수 목록은 원래 함수와 일치해야 하며, 해당 예외를 수신하기 위해 추가적인 Throwable 유형 매개변수를 추가할 수 있습니다.
    • ③ fallback 함수는 기본적으로 원래 메소드와 동일한 클래스에 있어야 합니다. 다른 클래스의 함수를 사용하려면 해당 클래스의 Class 객체에 fallbackClass를 지정하면 되는데, 해당 함수는 static 함수(fallbackClass 사용 시)여야 하며, 그렇지 않으면 파싱할 수 없다는 점에 유의하세요.

    다음은 샘플 코드이며 여기에 새로운 구성을 추가할 필요는 없으며 여전히 2.2 구성을 기반으로 합니다.

    import com.alibaba.csp.sentinel.annotation.SentinelResource;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.cloud.context.config.annotation.RefreshScope;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @author pcc
     */
    @Slf4j
    @RefreshScope // 动态刷新nacos配置注解
    @RestController
    @RequestMapping("/stock")
    public class StockController {
          
          
    
        @Value("${name}")
        String name;
    
    
    
        @RequestMapping("/addStock")
        @SentinelResource(fallback = "addStockFallBack")
        public void addStock() throws Exception{
          
          
            int i = 1/0;
            log.info("add stock start: {}",name);
    
        }
    
        /**
         * 这是方法降级的 方法
         * 这里可以不使用 static
         * @param throwable 触发的异常
         */
        public static void addStockFallBack(Throwable throwable){
          
          
            log.info("addStock 触发方法降级: {}", throwable.getMessage());
        }
    
    }
    

    아래는 실행 중인 스크린샷입니다.
    여기에 이미지 설명을 삽입하세요.

  • 2 다운그레이드: fallback은 fallbackClass 및ExceptionsToIgnore와 협력합니다.
    인터페이스가 많은 경우 모든 다운그레이드 방법을 인터페이스에 넣는 것은 매우 지저분해 보일 수 있으므로 확실히 부적절합니다.따라서 실제 시나리오에서는 항상 컨트롤러의 다운그레이드 방법을 넣습니다. in 별도의 클래스에서는 @SentinelResource의 fallbackClass를 사용하여 해당 클래스를 지정하고, fallback을 사용하여 다운그레이드 방법을 지정함으로써 다운그레이드 방법과 인터페이스 클래스 간의 결합을 분리할 수 있다. 함께 사용됩니다.
    서비스가 다운그레이드되는 클래스입니다.

    /**
     * @author pcc
     * 这是降级类
     */
    @Slf4j
    public class StockDegrade {
          
          
        /**
         * 这是类降级的 方法
         * @param a 触发的异常
         */
        public static void addStock(Throwable a) {
          
          
            log.info("add stock 类级降级: {}",a.getMessage());
    
        }
    }
    
    

    다운그레이드에 사용되는 인터페이스는 다음과 같습니다.

    import com.alibaba.csp.sentinel.annotation.SentinelResource;
    import com.cheng.stockserver.sentineldegrade.StockDegrade;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.cloud.context.config.annotation.RefreshScope;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @author pcc
     */
    @Slf4j
    @RefreshScope
    @RestController
    @RequestMapping("/stock")
    public class StockController {
          
          
    
        @Value("${name}")
        String name;
        
        @SentinelResource(fallback = "addStock",fallbackClass = StockDegrade.class,exceptionsToIgnore =  {
          
          ArithmeticException.class})
        @RequestMapping("/addStock")
        public void addStock() throws Exception{
          
          
            log.info("add stock start: {}",name);
            throw new RuntimeException("运行时异常");
    
        }
    
    }
    

    위와 같이 fallbackClass를 사용하여 다운그레이드 방법이 위치한 클래스를 지정하고, fallback을 사용하여 해당 다운그레이드 방법을 지정합니다. 이를 통해 다운그레이드 방법을 별도의 다운그레이드 클래스로 분리할 수 있습니다. 위 코드에서는 RuntimeException이 수동으로 발생하는데, ArithmeticException이 발생하면 서비스 다운그레이드 메소드에 진입하지 않고 직접 상위로 발생하며, 서비스에서 직접 예외가 발생합니다(통합 예외 처리가 없다고 가정). 그리고 여기서는 ArithmeticException만 무시되기 때문에 여전히 다운그레이드 방식으로 들어가게 됩니다.
    특별 참고 사항: 다운그레이드된 클래스를 지정할 때 다운그레이드된 메서드는 정적이어야 합니다. 그렇지 않으면 구문 분석할 수 없습니다.

  • 3 다운그레이드: defaultFallback은 fallback, fallbackClass,ExceptionsToIgnore와 협력합니다
    .defaultFallback을 메소드에 적용하면 fallback의 사용법과 완전히 일치합니다.필요한 규칙도 동일합니다.위에서 fallback을 defaultFallback으로 대체하는 것은 완전히 가능합니다. 두 가지 예. 여기서 언급해야 할 defaultFallback의 두 가지 특수 기능이 있습니다.

    • defaultFallback은 클래스를 수정할 수 있습니다. (공식 문서에는 1.8.0부터 지원된다고 나와 있습니다. 모든 인터페이스를 지원하는 기본 다운그레이드 방법이어야 합니다. 테스트 결과 지원되지 않습니다.)
    • defaultFallback과 fallback이 동시에 설정되면 fallback이 적용되고 defaultFallback은 실패합니다.

    다음은 defaultFallbck와 fallback이 동시에 인터페이스를 수정할 때 누가 적용되는지 보여줍니다.

    import com.alibaba.csp.sentinel.annotation.SentinelResource;
    import com.cheng.stockserver.sentineldegrade.StockDefaultDegrade;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.cloud.context.config.annotation.RefreshScope;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @author pcc
     */
    @Slf4j
    @RefreshScope
    @RestController
    @RequestMapping("/stock")
    public class StockController {
          
          
    
        @Value("${name}")
        String name;
    
    
        /**
         * 这里同时使用了fallback 、defaultFallback
         * 当同时使用时,只有fallback生效
         *
         */
        @SentinelResource(
                defaultFallback = "stockDefaultFallback",
                fallback = "addStockFallback",
                fallbackClass = StockDefaultDegrade.class,
                exceptionsToIgnore = ArithmeticException.class)
        @RequestMapping("/addStock")
        public void addStock(){
          
          
            log.info("add stock start: {}",name);
            throw new RuntimeException("运行时异常1");
    
        }
        
    }
    

    다음은 다운그레이드된 클래스와 해당 메서드입니다.

    import lombok.extern.slf4j.Slf4j;
    
    /**
     * @author pcc
     * 这是defaultFallback的降级类
     */
    @Slf4j
    public class StockDefaultDegrade {
          
          
    
        /**
         * 这是默认降级方法
         * @param throwable
         */
        public static void stockDefaultFallback(Throwable throwable){
          
          
            log.info("触发defaultFallback的降级方法:" + throwable.getMessage() + " ");
        }
    
        /**
         * 这是fallback用的指定降级方法
         * @param throwable
         */
        public static void addStockFallback(Throwable throwable){
          
          
            log.info("触发addStockFallback的降级方法:" + throwable.getMessage() + " ");
        }
    }
    

    해당 인터페이스를 호출할 때 실제로 트리거되는 유일한 다운그레이드 방법은 fallback으로 지정된 다운그레이드 방법임을 알 수 있습니다.
    여기에 이미지 설명을 삽입하세요.

2 Sentinel은 OpenFeign을 통합합니다.

OpenFeign은 여기에 Sentinel을 통합하여 서비스 저하 처리를 시연할 뿐이며 다른 기능을 확장하지는 않습니다. OpenFeign은 단 두 단계만으로 Sentinel을 통합합니다.

  • 1 Sentinel 종속성 가져오기
    <!--sentinel依赖-->
    <dependency>
       <groupId>com.alibaba.cloud</groupId>
       <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    </dependency>
    
  • 2 Sentinel의 OpenFeign 지원을 활성화
    하고 yml 또는 속성에서 구성합니다.
    # 已省略关系不大的配置
    feign:
      sentinel:
        enabled: true # 开启sentinel对feign的支持
    
    Sentinel에 추가적인 구성을 추가하지 않고도 바로 사용할 수 있습니다.

3 OpenFeign은 서비스 저하를 정의합니다.

OpenFeign은 서비스를 다운그레이드하는 두 가지 방법을 지원하지만 Sentinel 또는 Hystrix를 통합해야 합니다. 여기서는 Sentinel의 통합을 예로 들어보겠습니다.

  • 1 Fallback을 사용하여 FeignClient에서 다운그레이드 클래스를 지정합니다.
  • 2 fallbackFactory를 사용하여 FeignClient에서 다운그레이드 클래스를 지정합니다.

둘 다 지원하기 때문에 차이점이 있을 수밖에 없는데, 가장 큰 차이점은 fallback이 예외를 얻을 수 없다는 점이지만 fallbackFactory는 특정 예외를 알 수 있기 때문에 특정 예외를 알면 다른 예외에 따라 다른 처리를 수행할 수 있으므로 실제 시나리오에서는 대부분 fallbackFactory를 사용하세요(fallback을 사용하는 곳도 몇 개 있습니다). 아래에 자세히 설명되어 있습니다.

    1. fallback 서비스 다운그레이드
      fallback을 사용하려면 다음 조건을 충족해야 합니다.
      1. fallback으로 지정된 클래스는 Spring 컨테이너에서 관리되어야 합니다.
      1. fallback으로 지정된 클래스는 FeignClient로 수정된 feign 인터페이스를 구현해야 합니다.

    이러한 방식으로 클래스를 대체할 수 있으며, 예외가 발생하면 재정의한 해당 메서드에 해당 예외가 도입됩니다. 다음은 테스트 코드입니다.
    이것은 가짜 인터페이스 코드입니다.

    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    /**
     * @author pcc
     * url: 用于指定三方接口,通过url指定的接口不会从注册中心获取服务列表,而是直接通过接口名拼接地址
     * name:用以声明feign调用的服务,这个必须与注册中心服务名保持一致
     * path:控制器上的类路径,如果不写path在方法上写全路径也是一样的
     * configuration:配置类,可以配置一些公共的参数,只对当前类下的接口生效,属于局部配置
     * fallback : 声明降级类
     *
     */
    @FeignClient(name = "stock-server",path = "/stock",
            fallback = StockFeignControllerDegrade.class)
    public interface StockFeignController {
          
          
    
        @RequestMapping("/addStock")
        void addStock();
    }
    

    다음은 다운그레이드 클래스에 대한 코드로, 매우 간단하며 어떤 예외로 인해 서비스 다운그레이드가 발생했는지는 알 수 없습니다.

    import lombok.extern.slf4j.Slf4j;
    import org.springframework.stereotype.Component;
    
    /**
     * @author pcc
     */
    @Slf4j
    @Component
    public class StockFeignControllerDegrade implements StockFeignController{
          
          
        @Override
        public void addStock() {
          
          
            log.info("addStock: 降级方法处理中。。。");
        }
    }
    

    그런 다음 테스트해 보면 서버 예외가 발생하면 일반적으로 다운그레이드 방법에 들어가는 것을 알 수 있습니다(서비스 공급자 코드에서 예외가 발생함).
    여기에 이미지 설명을 삽입하세요.

    1. fallbackFactory 서비스 다운그레이드
      fallbackFactory를 사용하려면 다음 규칙을 따라야 합니다.
    • 1 구현 클래스는 Spring에 의해 관리되어야 합니다.
    • 2 구현 클래스는 FallbackFactory 인터페이스를 구현하고 Feign 인터페이스의 일반 유형을 전달해야 합니다.

    다음은 Feign 인터페이스의 코드입니다.

    /**
     * @author pcc
     * url: 用于指定三方接口,通过url指定的接口不会从注册中心获取服务列表,而是直接通过接口名拼接地址
     * name:用以声明feign调用的服务,这个必须与注册中心服务名保持一致
     * path:控制器上的类路径,如果不写path在方法上写全路径也是一样的
     * configuration:配置类,可以配置一些公共的参数,只对当前类下的接口生效,属于局部配置
     * fallback : 声明降级类
     * fallbackFactory: 声明降级工厂类
     *
     */
    @FeignClient(name = "stock-server",path = "/stock",
            fallbackFactory = StockFeignCallBackFactory.class)
    public interface StockFeignController {
          
          
    
        @RequestMapping("/addStock")
        void addStock();
    }
    

    다음은 다운그레이드 팩토리 구현 클래스입니다.

    import lombok.extern.slf4j.Slf4j;
    import org.springframework.cloud.openfeign.FallbackFactory;
    import org.springframework.stereotype.Component;
    
    /**
     * @author pcc
     */
    @Slf4j
    @Component
    public class StockFeignCallBackFactory implements FallbackFactory<StockFeignController> {
          
          
        @Override
        public StockFeignController create(final Throwable cause) {
          
          
            return new StockFeignController() {
          
          
                @Override
                public void addStock() {
          
          
                    log.info("addStock:fallbackFactroy降级中:{}",cause.getMessage());
                }
            };
        }
    }
    

    예외의 세부 사항을 보여주기 위해 위의 코드는 Throwable 원인을 최종 Throwable 원인으로 변경합니다. 그렇지 않으면 내부 클래스가 변수 원인을 조작할 수 없습니다(람다를 자주 작성할 때 이 문제에 대해 잘 알고 있어야 합니다). 실행 후, 다운그레이드 메소드에서 원격 인터페이스의 예외 정보를 얻은 것을 아래 그림에서 볼 수 있습니다.
    여기에 이미지 설명을 삽입하세요.
    추가해야 할 한 가지는 서비스 저하와 통합 예외 처리 간의 관계입니다.
    서비스 다운그레이드로 처리되는 예외는 당연히 전역 예외 처리로 포착될 수 없습니다. 전역 예외 처리는 은밀한 다운그레이드 프로세스로 볼 수 있습니다.

4. 전류 제한 회로 차단기 규칙: DegradeRule

참고: 현재 사용환경은 SringCloud 이며, 환경이 다를 경우 서킷브레이커의 사용법도 조금씩 달라질 수 있습니다.
서킷브레이커에 대해 이야기하기 전에 다운그레이드 처리에 대해 먼저 말씀드리겠습니다. 다운그레이드 방법을 선언하여 서비스 다운그레이드 처리를 구현하는데, 이전 섹션에서는 @SentinelResource 또는 @FeignClient를 사용하는 두 가지 처리 방법을 소개했습니다. 서비스 예외가 발생할 때 트리거되는 다운그레이드 메서드를 모두 구현할 수 있습니다. 그렇다면 서킷 브레이커와 서비스 저하 사이에는 어떤 관계가 있을까요? 서비스 서킷 브레이커에 대한 몇 가지 규칙을 구성해야 합니다.예를 들어 1초 내에 10개의 요청이 있고 그 중 5개가 비정상인 경우 서킷 브레이커를 실행합니다. 다운그레이드 메서드는 회로 차단기가 트리거될 때 호출됩니다. 여기에 질문이 있으신가요? 일반 예외는 다운그레이드 방식을 호출하고 서킷 브레이커도 예외 방식을 호출하는데 왜 서킷 브레이커를 설정해야 하는 걸까요? 기본적으로 다운그레이드 방식을 사용하는 것만으로도 충분하지 않을까요? 대답은 '아니오'입니다. 그렇지 않으면 회로 차단기가 필요한 이유는 무엇입니까? 회로 차단기는 높은 동시성 시나리오에서 서비스가 비정상적인 시나리오나 리소스 제한 시나리오(호출이 비정상적인 경우)에서 너무 많은 요청 리소스를 점유하는 것을 방지하기 위해 더 일반적으로 사용됩니다. 호출이 계속 호출됩니다) 사실 스레드 자원 낭비입니다. 응답이 느리고 여러 서비스가 여전히 이 인터페이스를 호출하는 경우에도 자원 낭비입니다. 물론 핵심 서비스라면, 별도로 논의해야 합니다.) 따라서 서킷 브레이커는 서킷 브레이커 타임(Circuit Breaker Time) 개념을 제공하며, 서킷 브레이커가 발동되면 서킷 브레이커 시간이 주어지며, 서킷 브레이커 기간 동안 현재 인터페이스나 리소스에서 수신한 요청은 다운그레이드 방식으로 진입하지 않고 직접 다운그레이드 방식으로 진입하게 된다. . 이를 통해 많은 문제를 해결할 수 있는데, 예를 들어 서비스가 비정상적인 상태인 경우 일련의 프로세스를 수행하고 리소스를 점유할 필요가 없으며 다운그레이드 프로세스만 수행하면 됩니다. 시간이 회로 차단기 시간 제한에 도달하면 다음 요청에서 메서드가 시작됩니다. 현재 메서드가 한 번 다운그레이드를 트리거하면 회로 차단기는 회로 차단기 규칙을 판단하는 대신 직접 회로 차단기가 됩니다. 정상이면 회로 차단기가 종료됩니다.
Sentinel의 서킷 차단기는 느린 호출 비율, 예외 비율, 예외 횟수의 세 가지 전략을 지원하며, 이 세 가지 유형에 대한 서킷 차단 규칙은 다음과 같습니다. 자세한 설명은 페이지 구성과 API 구성의 두 가지 형태로 제공됩니다.

1. 느린 통화 비율 퓨즈 페이지

느린 호출 비율은 말 그대로 총 요청 수에 대한 느린 호출의 비율을 기준으로 하는 서킷 브레이커를 의미하며, 페이지 구성 사용 시 주의할 점은 다음과 같습니다.

  • 페이지에서 회로 차단기 규칙을 구성할 때 메서드에 @SentinelResource 주석을 추가할 필요가 없으며, 추가하지 않는 경우 기본 다운그레이드 방법을 사용합니다.
  • 페이지에 구성된 회로 차단기 규칙은 대시보드를 다시 시작하거나 대상 서비스를 다시 시작하면 사라집니다.

다음으로 느린 통화 비율에 대한 회로 차단기 규칙을 구성하려면 먼저 "클러스터 포인트 링크" 페이지에 들어가야 합니다(클러스터 포인트 링크는 실제로 요청을 생성한 인터페이스이며 Sentinel의 리소스임). 예
여기에 이미지 설명을 삽입하세요.
보시다시피 위의 화면은 구성을 추가하지 않은 스크린샷입니다. 이때 "Circuit Break"를 클릭하여 회로 차단기 규칙을 추가할 수 있습니다.
여기에 이미지 설명을 삽입하세요.
위 그림은 느린 통화 비율 서킷 브레이커 규칙의 구성 페이지로, 총 5개의 비즈니스 매개변수를 볼 수 있습니다(느린 통화 비율 제외).

  • 최대 RT: 단위 ms, 인터페이스의 최대 응답 시간 이 시간을 초과하면 느린 호출로 간주됩니다.
  • 비율 임계값: 느린 통화 요청 수/총 요청 수, 최대 허용 값
  • 멜트다운 기간: 퓨즈를 트리거한 후 인터페이스 또는 리소스가 퓨즈 상태로 들어가는 데 걸리는 시간
  • 최소 요청 수: 동시 요청 수이며, 동시 요청 수가 이 수에 도달한 경우에만 느린 호출 비율을 계산하고 임계값에 도달하면 회로 차단기가 작동됩니다.
  • 통계 기간: 동시 요청 수를 계산하는 시간

위에 표시된 대로 다음과 같은 구성을 수행할 수 있습니다. 구성의 의미는 다음과 같습니다.
1초 이내 동시 요청 횟수가 3이 되는지 계산하고, 그렇다면 최대 RT를 기준으로 이들 요청 중 느린 호출의 비율을 계산하고 비율을 계산한 후 비율 임계값과 비교합니다.임계값에 도달한 경우 , 회로 차단기가 작동됩니다. 회로 차단기 시간은 10초입니다. 10초 이내에 모든 요청은 방법에 들어가지 않고 직접 다운그레이드 방법에 들어갑니다. 여기에 선언된 다운그레이드 방법이 없으면 기본 다운그레이드 방법에 들어갑니다. 회로 차단기 시간이 만료되면 다음 요청이 성공하면 계산이 다시 시작되고, 실패하면 회로 차단기에 직접 다시 진입합니다.
여기에 이미지 설명을 삽입하세요.
위의 구성이 완료되면 "Circuit Break Rules" 메뉴에서 방금 구성한 서킷 브레이커 규칙을 확인
여기에 이미지 설명을 삽입하세요.
하고 테스트해 볼 수 있습니다. 여기서는 느린 호출을 시뮬레이션해야 합니다. 100 이내의 난수를 생성한 후 Sleep을 하면 됩니다. 느린 통화를 시뮬레이션합니다.

    @RequestMapping("/addStock")
    public void addStock() throws Exception{
    
    
        log.info("add stock start: {}",name);

        // 随机休眠100ms以内的时间-用于测试: 熔断规则-慢调用
        String s = String.valueOf(Math.floor(Math.random() * 100));
        Thread.sleep(Integer.parseInt(s.split("\\.")[0]));

    }

그런 다음 트리거 결과를 살펴보십시오.
여기에 이미지 설명을 삽입하세요.
이는 기본 다운그레이드 방법의 반환입니다.
위에 표시된 예에서는 @SentinelResource를 사용하지 않으며 다운그레이드 방법을 지정하지 않습니다. @SentinelResource를 사용하고 동시에 다운그레이드 방법을 지정하는 방법에 대해 이야기해 보겠습니다. @SentinelResource를 사용하여 다운그레이드 방법을 지정하는 방법은 이전 섹션에서도 언급했는데, fallback이나 fallback+fallbackClass를 직접 사용하여 다운그레이드 방법을 지정할 수 있습니다. 여기서도 @SentinelResource라는 또 다른 속성 값을 사용해야 하는데, 이 속성의 기능은 해당 메소드를 Sentinel에 리소스로 등록하는 것입니다. Java 코드는 다음과 같습니다.@SentinelResource를 사용할 때 다운그레이드 방법을 지정해야 하며, 이 주석을 사용해야 하며 시스템은 기본 다운그레이드 방법을 사용하지 않습니다.):

	// 使用注解,表明Sentinel资源,同时指明降级方法
    @SentinelResource(
            value = "addStock",
            fallback = "addStockFallback",
            fallbackClass = StockDefaultDegrade.class,
            exceptionsToIgnore = ArithmeticException.class)
    @RequestMapping("/addStock")
    public void addStock() throws Exception{
    
    
        log.info("add stock start: {}",name);

        // 随机休眠100ms以内的时间-用于测试: 熔断规则-慢调用
        String s = String.valueOf(Math.floor(Math.random() * 100));
        Thread.sleep(Integer.parseInt(s.split("\\.")[0]));
    }

다운그레이드 방법에 대한 코드는 다음과 같습니다.

@Slf4j
public class StockDefaultDegrade {
    
    

    /**
     * 这是fallback用的指定降级方法
     * @param throwable
     */
    public static void addStockFallback(Throwable throwable){
    
    
        log.info("触发addStockFallback的降级方法:" + throwable.getMessage() + " ");
    }
}

페이지 구성 규칙은 다음과 같이 마지막으로 기본 다운그레이드 방법을 사용했을 때와 동일합니다.
여기에 이미지 설명을 삽입하세요.
다운그레이드 방법을 다시 시작하면 기본 다운그레이드 삭제가 없으며 자체 다운그레이드 방법을 입력하게 됩니다.
여기에 이미지 설명을 삽입하세요.

특별 참고 사항: 여기에서 빨간색 상자로 표시된 것만 서킷 브레이커가 시작될 때 실제로 실행되는 다운그레이드 방법입니다. 여기서 얻은 예외는 모두 null임을 알 수 있습니다. 이유는 무엇입니까? 서킷 브레이커 이후에 우리의 요청이 직접 다운그레이드 메소드에 들어갈 것이기 때문입니다. 이때 메소드는 오류를 보고하지 않으므로 여기에는 null이 있을 것입니다. 이때 메소드 내부에서 무작위로 예외가 발생하면 다음과 같은 문제가 발생할 수 있습니다. 예외를 인쇄하는 다운그레이드 방법이어야 합니다. 그러나 이는 회로 차단기에 의해 트리거되지 않습니다. 회로 차단기에 의해 트리거된 다운그레이드 방법이 느린 통화 비율, 예외 수 또는 예외 비율인지 여부에 관계없이 해당 예외 정보는 null이어야 합니다. 이는 메서드 예외에 의해 트리거된 다운그레이드인지 회로 차단기 트리거에 의해 트리거되었는지 구별하는 데에도 사용할 수 있습니다.

1. 저속통화율 차단기-API

위에서는 대시보드를 사용하여 느린 통화 비율의 회로 차단기, SentinelResource 주석을 사용하지 않을 때의 다운그레이드, 사용자 정의 다운그레이드 방법의 회로 차단기를 구성하는 방법을 소개합니다. API를 사용하여 회로 차단기를 구성하는 방법은 다음과 같습니다. 대부분의 실제 시나리오에서 API는 여전히 구성에 사용되며 특수 시나리오에서는 대시보드를 사용하여 조정됩니다. API를 사용할 때 다음 문제에 주의하세요.

  • API를 사용하여 회로 차단기를 구성하는 경우 대시보드를 전혀 사용할 필요가 없으며, 대시보드를 사용하는 목적은 API 구성 결과를 보다 명확하게 보기 위한 것입니다.
  • 회로 차단기 규칙을 구성하려면 리소스 이름 및 회로 차단기 정책 설정, 매개변수 구성, 규칙 관리자에 규칙 제출이라는 세 단계가 필요합니다.
  • API로 구성된 Circuit Breaker를 사용하며, 대시보드를 사용하면 대시보드가 ​​시작된 후 규칙을 볼 수 있습니다.
  • API로 구성된 Circuit Breaker를 이용하여 대시보드를 수정할 수도 있으며, 수정된 내용은 적용되지만 서비스나 대시보드를 다시 시작하면 무효화됩니다.
  • 마지막으로 관리를 위해 객체를 Spring 컨테이너에 넘겨주는 것을 잊지 마세요.

다운그레이드 방식과 인터페이스 방식의 코드는 위와 동일하므로 여기서는 다시 포스팅하지 않겠습니다.저속 통화율 서킷 브레이커 룰의 구성은 다음과 같습니다.비교를 용이하게 하기 위해 작성하는 방법은 3가지입니다. 세 가지 작성 방법의 차이점은 사실 모두 3단계가 필요하지만 후자의 두 번째 단계에는 매개변수가 4개만 있고 다른 단계에는 차이가 없습니다.

/**
 * @author pcc
 * 三种熔断规则不可以同时设置到一个资源上,若是同时作用到一个资源上,最后加载的规则会覆盖之前的规则
 * 最终只有一个生效
 */
@Configuration
public class FuseConfig {
    
    

    // 熔断规则-慢调用比例
    @Bean
    public DegradeRule degradeRule(){
    
    
        DegradeRule degradeRule = new DegradeRule();
        // 资源名,资源名是唯一的
        degradeRule.setResource("addStock");
        // 熔断策略-0 慢调用比例 ,1 异常比例 ,2 异常数
        degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_RT);

        // 熔断时长,单位为 s
        degradeRule.setTimeWindow(10);
        // 触发熔断的最小请求数,需要配合下面的时间一起,默认5
        degradeRule.setMinRequestAmount(3);
        // 触发熔断的最小请求数的单位时间ms默认1000ms(这个时间内请求数达到最小请求,才会进行计算时间超过阈值的请求,然后计算比例,比例达到后才会进行熔断)
        degradeRule.setStatIntervalMs(1000);
        // 慢调用比例模式下为慢调用临界 RT,单位ms(超出该值计为慢调用);异常比例/异常数模式下为对应的阈值
        degradeRule.setCount(40);
        // 慢调用比例阈值默认1.0,sentinel1.8.0加入,0.0-1.0 之间
        degradeRule.setSlowRatioThreshold(0.2);


        // 将熔断规则交给熔断规则管理器
        List<DegradeRule> rules = new ArrayList<DegradeRule>();
        rules.add(degradeRule);
        DegradeRuleManager.loadRules(rules);

        return degradeRule;
    }


    // 熔断规则-异常比例
    @Bean
    public DegradeRule exceptionRatioRule(){
    
    
        DegradeRule degradeRule = new DegradeRule();
        // 该熔断规则对应资源名
        degradeRule.setResource("addStock");
        // 熔断策略-异常比例
        degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO);

        // 异常比例阈值20%
        degradeRule.setCount(0.2);
        // 熔断时间单位s
        degradeRule.setTimeWindow(10);
        //  触发熔断的最小请求数,需要配合下面的时间一起,默认5
        degradeRule.setMinRequestAmount(3);
        // 触发熔断的最小请求数的单位时间ms默认1000ms(这个时间内请求数达到最小请求,才会进行计算时间超过阈值的请求,然后计算比例,比例
        degradeRule.setStatIntervalMs(1000);


        // 将熔断规则交给熔断规则管理器-这里可以使用单例集合,因为无论在哪里声明的规则都是要交给管理器的
        // 即使在这里将别的规则也加载了也没问题,所以可以使用单例集合
        DegradeRuleManager.loadRules(Collections.singletonList(degradeRule));
        return degradeRule;
    }

    // 熔断规则-异常数
    @Bean
    public DegradeRule execptionCountRule(){
    
    
        DegradeRule degradeRule = new DegradeRule();
        // 熔断资源
        degradeRule.setResource("addStock");
        // 熔断策略-异常数
        degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);

        // 异常数的阈值
        degradeRule.setCount(2);
        // 熔断触发最小请求数
        degradeRule.setMinRequestAmount(3);
        // 熔断最小请求书的统计时长,默认1000ms
        degradeRule.setStatIntervalMs(1000);
        // 熔断时间
        degradeRule.setTimeWindow(10);


        // 将熔断规则交给熔断规则管理器-这里可以使用单例集合,因为无论在哪里声明的规则都是要交给管理器的
        DegradeRuleManager.loadRules(Collections.singletonList(degradeRule));
        return degradeRule;
    }
}

결과가 위와 다르지 않으면 다시 게시하지 않겠습니다.

2. 차단기 비율 이상 - 페이지

페이지 구성이 약간 다른 점을 제외하면 나머지는 모두 느린통화비율 페이지 구성과 동일합니다.
여기에 이미지 설명을 삽입하세요.
페이지도 이해하기 쉽게 설명되어 있으며 비정상 비율의 임계값을 구성하는 것으로 임계값에 도달하면 회로 차단기가 작동되고 모든 다운그레이드 방법이 실행됩니다. 여기서 확인하려면 무작위성을 기반으로 직접 예외를 실행하면 됩니다. 다음은 Java 코드입니다.

    /**
     * 这里同时使用了fallback 、defaultFallback
     * 当同时使用时,只有fallback生效
     *
     */
    @SentinelResource(
            value = "addStock",
            defaultFallback = "stockDefaultFallback",
            fallback = "addStockFallback",
            fallbackClass = StockDefaultDegrade.class,
            exceptionsToIgnore = ArithmeticException.class)
    @RequestMapping("/addStock")
    public void addStock() throws Exception{
    
    
        log.info("add stock start: {}",name);

        // 随机休眠100ms以内的时间-用于测试: 熔断规则-慢调用
        String s = String.valueOf(Math.floor(Math.random() * 100));
        Thread.sleep(Integer.parseInt(s.split("\\.")[0]));

        // 随机产生异常用于测试:熔断规则-异常比例/异常数
        if(Integer.parseInt(s.split("\\.")[0])>50){
    
    
            throw new RuntimeException("运行异常哈");
        }

    }

이러한 방식으로 특정 비율의 요청에서 RuntimeException이 발생합니다. 요점은 요청이 충분히 빠르면 회로 차단기가 트리거된다는 것입니다. 발동 후에는 차이가 없습니다. 여기에는 다운그레이드 방법이 하나만 사용됩니다(동일한 리소스에는 다운그레이드 방법이 하나만 있을 수 있음).

2. 차단기-API 비율 이상

여기서 언급해야 할 것은 setCount 메소드이므로 더 이상 언급할 것이 없습니다. 이 방법은 세 가지 회로 차단기 전략에서 사용할 수 있지만 그 의미가 다르므로 특별한 주의가 필요합니다. RT에서는 느린 호출의 지속 시간을 나타내는 단위가 ms이고, 예외 비율에서는 단위 없는 예외 비율을 나타내며, 값은 0.0~1.0 사이이고, 예외 번호에서는 예외 횟수를 나타냅니다. 다른 API에 대해서는 별로 할 말이 없으므로 세 가지 API에 대한 코드는 모두 다음과 같습니다.

/**
 * @author pcc
 * 三种熔断规则不可以同时设置到一个资源上,若是同时作用到一个资源上,最后加载的规则会覆盖之前的规则
 * 最终只有一个生效
 */
@Configuration
public class FuseConfig {
    
    

    // 熔断规则-慢调用比例
    @Bean
    public DegradeRule degradeRule(){
    
    
        DegradeRule degradeRule = new DegradeRule();
        // 资源名,资源名是唯一的
        degradeRule.setResource("addStock");
        // 熔断策略-0 慢调用比例 ,1 异常比例 ,2 异常数
        degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_RT);

        // 熔断时长,单位为 s
        degradeRule.setTimeWindow(10);
        // 触发熔断的最小请求数,需要配合下面的时间一起,默认5
        degradeRule.setMinRequestAmount(3);
        // 触发熔断的最小请求数的单位时间ms默认1000ms(这个时间内请求数达到最小请求,才会进行计算时间超过阈值的请求,然后计算比例,比例达到后才会进行熔断)
        degradeRule.setStatIntervalMs(1000);
        // 慢调用比例模式下为慢调用临界 RT,单位ms(超出该值计为慢调用);异常比例/异常数模式下为对应的阈值
        degradeRule.setCount(40);
        // 慢调用比例阈值默认1.0,sentinel1.8.0加入,0.0-1.0 之间
        degradeRule.setSlowRatioThreshold(0.2);


        // 将熔断规则交给熔断规则管理器
        List<DegradeRule> rules = new ArrayList<DegradeRule>();
        rules.add(degradeRule);
        DegradeRuleManager.loadRules(rules);

        return degradeRule;
    }


    // 熔断规则-异常比例
    @Bean
    public DegradeRule exceptionRatioRule(){
    
    
        DegradeRule degradeRule = new DegradeRule();
        // 该熔断规则对应资源名
        degradeRule.setResource("addStock");
        // 熔断策略-异常比例
        degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO);

        // 异常比例阈值20%
        degradeRule.setCount(0.2);
        // 熔断时间单位s
        degradeRule.setTimeWindow(10);
        //  触发熔断的最小请求数,需要配合下面的时间一起,默认5
        degradeRule.setMinRequestAmount(3);
        // 触发熔断的最小请求数的单位时间ms默认1000ms(这个时间内请求数达到最小请求,才会进行计算时间超过阈值的请求,然后计算比例,比例
        degradeRule.setStatIntervalMs(1000);


        // 将熔断规则交给熔断规则管理器-这里可以使用单例集合,因为无论在哪里声明的规则都是要交给管理器的
        // 即使在这里将别的规则也加载了也没问题,所以可以使用单例集合
        DegradeRuleManager.loadRules(Collections.singletonList(degradeRule));
        return degradeRule;
    }

    // 熔断规则-异常数
    @Bean
    public DegradeRule execptionCountRule(){
    
    
        DegradeRule degradeRule = new DegradeRule();
        // 熔断资源
        degradeRule.setResource("addStock");
        // 熔断策略-异常数
        degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);

        // 异常数的阈值
        degradeRule.setCount(2);
        // 熔断触发最小请求数
        degradeRule.setMinRequestAmount(3);
        // 熔断最小请求书的统计时长,默认1000ms
        degradeRule.setStatIntervalMs(1000);
        // 熔断时间
        degradeRule.setTimeWindow(10);


        // 将熔断规则交给熔断规则管理器-这里可以使用单例集合,因为无论在哪里声明的规则都是要交给管理器的
        DegradeRuleManager.loadRules(Collections.singletonList(degradeRule));
        return degradeRule;
    }
}

3. 예외 번호 회로 차단기 - 페이지 및 API

여기는 별 차이가 없고 위의 내용과 비교하면 변화의 양도 아주 적습니다. 따로 얘기할 가치도 없고 그냥 같이 보시면 됩니다. 구성 페이지의 내용은 다음과 같습니다
여기에 이미지 설명을 삽입하세요.
. 비정상 비율은 비정상 비율만 변경되어 API 작성 방식에서도 비정상이 되었습니다. 비정상 비율의 비율 임계값과 비정상 비율의 예외 개수는 모두 개수로 표시됩니다. 따라서 API의 차이는 회로 차단기 전략의 차이이므로 여기서는 반복해서 표시하지 않습니다.

4. 기타 핵심 사항 추가

4.1 @SentinelResource 주석을 추가한 후에는 기본 다운그레이드가 적용되지 않습니다.

이 문제는 위에서 설명한 내용인데 실제로 @SentinelResource 애너테이션을 사용하지 않을 경우 서킷 브레이커가 발동되면 기본 다운그레이드 방식을 사용하게 되는데, 이 애노테이션을 추가한 후에는 다운그레이드 방식을 선언해야 한다. 그렇지 않으면 시스템의 기본 다운그레이드 방법을 거치지 않고 500을 보고합니다. 물론 실제 시나리오에서는 다운그레이드 대신 회로 차단기를 사용하는 사람은 아무도 없으므로 기능을 검증할 때에만 주의하면 됩니다.

4.2 통합된 다운그레이드 처리

위에서 언급한 기본 다운그레이드 방법은 실제로 Sentinel에서 제공하는 통합 예외 처리입니다(전역 예외 처리기와 다소 유사). 이것도 변경될 수 있으며, 이 통합 예외 처리를 사용하여 반환 정보를 지정하거나 페이지를 반환할 수 있습니다. 지정된 웹사이트나 정적 리소스로 리디렉션될 수 있습니다. 이는 기본 통합 다운그레이드 처리 방법입니다.
여기에 이미지 설명을 삽입하세요.

그렇다면 이 통합 예외 처리를 우리가 직접 구현한다면 어떻게 해야 할까요?실제로 그의 작성 방법을 다음과 같이 참고하면 됩니다.

import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author pcc
 */
@Component
public class GlobalDegradeConfig implements BlockExceptionHandler {
    
    

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
    
    
        response.setStatus(429);
        response.setHeader("Content-Type", "application/json");
        response.setCharacterEncoding("UTF-8");
        response.getWriter().write("{\"code\":429,\"msg\":\"请求过于频繁,请稍后再试\"}");
        response.getWriter().flush();
    }
}

검증도 매우 간단합니다. 인터페이스에서 @SentinelResource 주석을 제거한 다음 페이지에서 회로 차단기 규칙을 재구성하기만 하면 됩니다. 이때 테스트할 수 있습니다. 결과는 그림과 같습니다.
여기에 이미지 설명을 삽입하세요.

그러나 이 통합 다운그레이드 처리를 사용하는 데에는 문제가 있습니다. 즉, 예외 발생 시 다운그레이드 방법이 없으면 사용자에게 직접 전달됩니다. 왜냐하면 이 통합 방법은 회로 차단기에 의해 트리거된 다운그레이드 시나리오에만 적용 가능하기 때문입니다. . 따라서 이 통합 회로 차단기 다운그레이드 처리를 사용하는 것은 여전히 ​​권장되지 않으며, 대신 @SentinelResource를 사용하여 다운그레이드 방법을 지정합니다. 이런 방식으로 일반 예외를 처리할 수 없는 시나리오는 없습니다.

4.3 BLockException이 발생하면 회로 차단기 규칙이 트리거되지 않습니다.

이 시나리오는 실제 비즈니스 시나리오에서는 거의 발생하지 않지만 직접 테스트할 때 발생할 수 있습니다. 예외 비율 및 예외 수의 서킷 브레이커 전략을 사용하면 코드에서 발생하는 것은 BlockException 클래스의 하위입니다. 예외(5가지 규칙에 해당하는 예외)는 회로 차단기 규칙을 정상적으로 트리거할 수 없습니다. 관심 있으신 분들은 확인해보시면 됩니다.

4.4 배포 spring.cloud.sentinel.eager:true

Sentinel 로딩 서비스의 starvation 모드를 켜십시오. 기본적으로 Sentinel은 서비스 인터페이스가 호출된 후에만 대상 서비스를 로드합니다. starvation 로딩을 켜면 서비스가 시작될 때 바로 로드됩니다. 그러나 요청이 들어오지 않는 경우 , "실시간 모니터링"에서 로드할 예정이며 "클러스터 포인트 링크"에는 데이터가 여전히 표시되지 않습니다.

5. 현재 제한 흐름 제어 규칙: FlowRule

Current Limiting과 Circuit Breaking은 Sentinel의 가장 중요한 두 가지 규칙입니다. Circuit Break는 비정상적인 상황에서 서비스의 올바른 반환을 보장하고, 흐름 제어는 높은 동시성에서 서비스의 안정성을 보장합니다. 우리는 서비스가 보장되도록 적절한 흐름 제어 전략을 설정합니다. 높은 동시성 시나리오에서는 압도되지 않습니다.
어떤 회사도 제한 없이 서버를 확장할 수 없다는 것은 생각할 수 있으므로 제한된 서버 리소스 내에서 서버 클러스터에서 허용하는 동시성을 초과하는 요청을 처리하는 방법을 고려해야 합니다. 이때 흐름 제어를 사용해야 합니다. 규칙. . 센티널 흐름 제어 규칙은 유형에 따라 QPS(초당 쿼리 수)와 동시 스레드 수(동시 스레드 수는 TPS로 간주될 수 있음)의 두 가지 주요 범주를 지원합니다. 이는 오늘날 가장 인기 있는 두 가지 솔루션이기도 합니다. 차이점이 있는 경우 아래에서 자세히 설명하겠습니다.
1.
Sentinel Dashboard 흐름 제어 규칙을 구성하는 페이지입니다. 다음과 같은 내용이 포함되어 있습니다. 언뜻 보면 각 매개변수의 조합 시나리오가 많다고 느낄 수 있지만 실제로는 일반적으로 임계값 유형과 클러스터에 중점을 둘 수 있습니다. 특별한 요구 사항이 있는 경우 흐름 제어 모드 및 효과 설정을 고려할 수 있습니다.

  • 리소스 이름: Sentinel에 등록된 리소스는 @SentinelResource를 사용하여 선언해야 합니다.
  • 소스의 경우: Sentinel은 다양한 소스에 대한 흐름 제어를 지원합니다. 예를 들어 저는 서비스 제공자이고 Baidu, Alibaba, Tencent는 모두 내 서비스를 사용합니다. 저는 Tencent에 대한 흐름 제어 규칙만 설정합니다. 이때 이 속성을 사용할 수 있습니다. 그러나 이를 위해서는 코드에 대한 일부 변경이 필요하며 이에 대해서는 별도로 논의할 것입니다. 왜냐하면 QPS와 동시 스레드 수가 모두 소스별 지원을 지원하기 때문입니다. 이에 대해서는 별도로 논의할 것입니다.
  • 임계값 유형 및 단일 시스템 임계값: Sentinel에서 지원하는 두 가지 규칙입니다.
  • 클러스터링 여부: 서비스는 기본적으로 클러스터링되어 있으므로 기본적으로 필수 선택 사항입니다. 단, 클러스터 모드에서는 단일 머신인지 전체 임계값인지 설정해야 합니다. 이 역시 QPS와 개수가 다르기 때문에 별도로 논의하겠습니다. 의 동시 스레드가 모두 지원됩니다.
  • 흐름 제어 모드: 클러스터 모드에서는 지원되지 않습니다. 직접, 연관, 링크 설정이 지원됩니다. QPS와 동시 스레드 수 모두 지원됩니다. 자세한 내용은 별도로 소개하겠습니다.
  • 흐름 제어 효과: 클러스터 모드에서는 지원되지 않으며, QPS에서만 지원하며, fast Fail, Warm up, Queue Waiting을 선택할 수 있으며 이 부분도 별도로 소개하겠습니다.

위에서 언급한 것처럼 일부 구성은 QPS를 지원하며 동시 스레드 수를 설정할 수 있습니다. 이 매개변수는 소스, 클러스터, 흐름 제어 모드 등과 같은 시나리오 중 하나만 사용하여 설명됩니다.

1.QPS 흐름 제어 페이지

흐름 제어 규칙을 선언한 후 fallback으로 선언된 다운그레이드 메서드를 사용하면 회로 차단기든 흐름 제어든 fallback의 다운그레이드 메서드가 호출된다는 점에 유의해야 합니다. 회로 차단기 또는 흐름 제어인 경우 fallback에서 다운그레이드 메서드가 호출됩니다. 흐름 제어를 위해 blockhandler 메서드가 계속 호출됩니다. 물론 블록 핸들러의 일반적인 다운그레이드는 여전히 fallback을 사용한다고 선언됩니다. 또 한 가지 주의할 점은 Fusing과 Current Limiting을 동시에 선언하는 경우에는 먼저 Fusing이 Fusing 중인지 여부를 먼저 확인해야 하며, 이미 Fusing 중인 경우에는 Current Limiting이 적용되지 않습니다.

  • 1. fallback을 사용하여 다운그레이드, 회로 차단기, 흐름 제어 등을 처리하기 위한 다운그레이드 방법을 선언합니다
    . 페이지에서 흐름 제어 규칙을 구성하려면 먼저 관리를 위해 해당 방법을 Sentinel에 넘겨야 하며 그런 다음 필요합니다. 다운그레이드, 회로 차단기, 흐름 제어 등 다운그레이드 방법을 선언합니다. 흐름 제어는 일반적으로 대체 방법으로 들어갈 수 있습니다.
    Sentinel이 관리하는 리소스 코드는 다음과 같습니다.
package com.cheng.stockserver.flowrule.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.cheng.stockserver.flowrule.degradeclass.BlockMethod;
import com.cheng.stockserver.flowrule.degradeclass.DegradeMethod;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author pcc
 * 正常情况下sentinel应该使用在customer端,而不是server端,这里只是测试一下就无所谓了
 */
@Slf4j
@RestController
@RequestMapping("/flow")
public class controller {
    
    

    @Value("${name}")
    String name;

    @RequestMapping("/testFlowRule")
    @SentinelResource(
            value = "testFlowRule",
            fallback = "testFlowRule", // 降级配置
            fallbackClass = DegradeMethod.class
    )
    public String testFlowRule(){
    
    

        log.info("testFlowRule start, name : {}",name);

        // 产生一个100以内的随机数
        int i = Integer.parseInt(String.valueOf(Math.random() * 100).split("\\.")[0]);

        // 当随机数大于60时,抛出异常(值越大抛出异常概率越小) 方便验证降级、熔断
        if(i>60){
    
    
            throw new RuntimeException("testFlowRule error");
        }

        return "success";
    }

}

이것은 선언된 대체 메소드입니다. 어떤 시나리오가 메소드를 트리거했는지 확인하려면 여기에 Throwable의 실제 유형을 인쇄하십시오. 예외 클래스로 구별할 수 있는 다운그레이드, 회로 차단기 또는 흐름 제어일 수 있습니다.

import lombok.extern.slf4j.Slf4j;

/**
 * @author pcc
 */
@Slf4j
public class DegradeMethod {
    
    

    public static String testFlowRule(Throwable th){
    
    
        log.info("触发降级方法: {},异常:{}",th.getMessage(),th.getClass().getName());
        return "降级方法返回:success";
    }
}

회로 차단기 규칙 구성에는 위의 구성과 차이가 없으며 여기서는 비정상적인 비율을 사용하여 회로 차단기 규칙을 구성합니다.

import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
import java.util.List;

/**
 * @author pcc
 */
@Configuration
public class DegradeConfig {
    
    

    /**
     * 如果有多个熔断规则应该这么写
     * 或者是使用一个单例list,把所有的熔断规则都放进去,最后一次交给
     * 熔断规则管理器
     * @return
     */
    @Bean
    public DegradeRule getDegradeRule() {
    
    

        List<DegradeRule> lists = new ArrayList<DegradeRule>();

        /**
         * 这是第一个熔断规则,支持多个规则的配置
         */
        // 这里使用熔断规则的异常比例规则来处理降级
        // 使用异常比例更容易看到是普通降级还是熔断导致的降级(看异常信息有没有值就知道了)
        DegradeRule degradeRule = new DegradeRule();
        // 声明熔断对应的资源、sentinelresource中value声明
        degradeRule.setResource("testFlowRule");
        // 降级策略使用异常比例
        degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO);

        // 设置降级规则
        degradeRule.setCount(0.5); // 20%的异常会熔断
        degradeRule.setTimeWindow(10); // 熔断10s
        degradeRule.setMinRequestAmount(2);// 最小请求数
        degradeRule.setStatIntervalMs(1000);// 最小请求数的统计时间1s

        // 将降级规则交由熔断管理器
        // 以上配置,1s内有两次请求,其中只要有一个异常就会熔断10s
        lists.add(degradeRule);

        DegradeRuleManager.loadRules(lists);

        return degradeRule;
    }
}

이것만이 Fusing에 필요한데 실제로는 이전에 소개한 내용인데 여기서는 Fusing 설정과 Flow Control을 동시에 설정하는 효과를 보여주기 위한 것이 주 목적이므로 Fusing을 다시 설정해야 합니다. 여기서는 페이지를 사용하여 흐름 제어를 구성합니다. 방금 구성한 회로 차단기 규칙에 대해 리소스 testFlowRule을 구성한 후 다음과 같이 흐름 제어 규칙을 구성합니다. 이 규칙을 구성한 후 3보다 큰 QPS를 가진 요청은 바로 fallback에 들어갑니다
여기에 이미지 설명을 삽입하세요.
. 방법을 사용하면 QPS가 3개보다 크지 않으면 요청이 정상적으로 리소스에 들어갈 수 있습니다. 다음은 실행 중인 스크린샷입니다.
여기에 이미지 설명을 삽입하세요.
다운그레이드 방법에는 다운그레이드 출력, 흐름 제어 출력, 퓨즈 출력의 세 가지 출력이 있음을 알 수 있습니다. 여기서는 회로 차단기와 다운그레이드가 동시에 리소스에 적용될 때의 효과를 확인할 수 있습니다.
요약하자면, 다음 사항을 염두에 두어야 합니다:
① Fallback은 다운그레이드, 회로 차단기, 흐름 제어 등의 시나리오를 동시에 처리할 수 있습니다. 내부적으로는 instanceof를 사용하여 예외 클래스를 결정하여 다른 처리를 구현할 수 있습니다. 다른 시나리오 ②. 하나
의 자원에 대해 회로 차단기와 흐름 제어가 동시에 설정된 경우, 흐름 제어 규칙의 트리거는 해당 자원이 회로 차단기가 될 수 없으며, 회로 차단기 동안에는 흐름 제어가 정상적으로 트리거될 수 없다는 전제가 필요합니다. 이는 리소스에 이상이 있으면 접근할 필요가 없고, 접근이 없으면 흐름제어가 필요 없기 때문에 합리적이다. 일반적인 요청은 다음과 같아야 합니다.
여기에 이미지 설명을 삽입하세요.

요청이 들어오면 먼저 해당 리소스가 서킷 브레이커인지 확인하고, 서킷 브레이커인 경우 서킷 브레이커 방식을 실행합니다. 폴백에서 지정한 방식은 다음과 같습니다. 서킷 브레이커가 없는 경우에만 판단합니다. 흐름제어를 수행해야 하는지 여부, 흐름제어가 없으면 리소스를 입력할 수 있다.

  • 2. 블록 핸들러를 사용하여 다운그레이드 방법을 선언합니다.
    위에서 폴백은 회로 차단기 및 흐름 제어를 시연하는 데 사용됩니다. SentinelResource는 또한 회로 차단기 및 흐름 제어와 같은 5가지 규칙 시나리오를 구체적으로 처리할 수 있는 블록 핸들러를 제공합니다. 따라서 최선의 방법은 폴백을 사용하지 않는 것입니다. 흐름 제어를 처리하기 위해 회로 차단기를 사용하는 대신 블록 처리기가 사용되는 반면 폴백은 특히 다운그레이드를 처리하는 데 사용됩니다. 블록 핸들러 사용과 대체 사용에는 차이가 없습니다. 위의 fallback을 사용하는 전체 코드와의 차이점은 blockhandler의 구성만 추가하면 되고 나머지는 위와 완전히 일치한다는 것입니다. 다음은 변경 사항만 보여주는 리소스의 새 구성에 대한 코드입니다.
    @RequestMapping("/testFlowRule")
    @SentinelResource(
            value = "testFlowRule",
            fallback = "testFlowRule", // 降级配置
            fallbackClass = DegradeMethod.class,
            blockHandler = "testFlowRule", // 流控配置:配置熔断规则时若是增加了blockhandler,则熔断时进入的是该方法而不是fallback
            blockHandlerClass = BlockMethod.class
    )

다음은 흐름 제어 방법의 구현입니다.이 메소드는 BlockException을 전달해야 하며 그렇지 않으면 적용되지 않습니다. 이는 필수 요구 사항입니다., 메서드 내에서 실제 예외 유형을 기반으로 어떤 시나리오가 메서드를 트리거했는지 판단할 수 있습니다.

import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import lombok.extern.slf4j.Slf4j;

/**
 * @author pcc
 */
@Slf4j
public class BlockMethod {
    
    

    /**
     * 流控方法这里必须声明BlockException的,不然是无法进入流控方法的
     * 流控也不会生效
     * @param blockException 流控异常
     * @return
     */
    public static String testFlowRule(BlockException blockException){
    
    

        /**
         * 这里异常时没有异常信息的,只能通过异常的类型来判定是熔断还是流控等
         */
        if(blockException instanceof DegradeException){
    
    
            // 处理熔断
            log.info("block-熔断-方法: {}","DegradeException");
            return "block-熔断-方法返回:success";
        }
        if(blockException instanceof FlowException){
    
    
            // 处理流控
            log.info("block-流控-方法: {}","FlowException");
            return "block-流控-方法返回:success";
        }

        return "block方法返回:success";
    }
}

그 외의 코드는 위의 fallback 사용 예와 완전히 동일하므로 여기서는 다시 표시하지 않겠습니다.그럼 이때 인터페이스를 트리거한 결과를 보면 위 그림에서 여전히 서비스 저하를 볼 수 있습니다
여기에 이미지 설명을 삽입하세요.
. fallback을 사용하고, 회로 차단기 및 흐름 제어에 블록 핸들러가 추가되었으며, 앞으로는 fallback을 사용하지 않고 블록 핸들러에서 지정한 방법을 사용하게 됩니다.

1.QPS 흐름 제어-API

여기의 코드와 변경 사항은 위 시나리오에서 블록 핸들러를 사용하는 것을 기반으로 다음과 같은 구성이 추가되었습니다. 실제로 페이지의 구성 규칙이 코드에 담겨져 있으며 그 이상은 변경되지 않습니다.

import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Collections;

/**
 * @author pcc
 */
@Configuration
public class FlowConfig {
    
    

    @Bean
    public FlowRule getFlowRule() {
    
    
        FlowRule flowRule = new FlowRule();
        // 声明流控的资源
        flowRule.setResource("testFlowRule");
        // 声明使用的流控规则:0 并发线程数,1 QPS
        flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);

        // 流控规则设置-QPS阈值2
        flowRule.setCount(2);
        // 来源没有默认值,必须手动设定,default表示对所有来源生效
        flowRule.setLimitApp("default");


        // 将流控规则交给流控管理器
        FlowRuleManager.loadRules(Collections.singletonList(flowRule));
        return flowRule;
    }
}

위 구성을 추가한 후에는 로그인 페이지에서 구성된 흐름 제어 규칙이나 이전 회로 차단기 규칙도 볼 수 없지만 이러한 규칙은 클라이언트에 정상적으로 적용됩니다. 다음과 같이 표시됩니다:
여기에 이미지 설명을 삽입하세요.
위의 대시보드 버그는 회로 차단기 규칙 및 흐름 제어 규칙의 효율성에 영향을 미치지 않지만 때때로 우리 규칙이 대시보드에 표시되지 않는 원인이 됩니다. 버그). 이 문제를 해결하는 방법은 사실 간단합니다. 먼저 우리가 구성한 FlowRule을 주석 처리하고 다시 시작한 다음 주석 처리를 해제하고 다시 시작하여 우회합니다. 구체적인 이유는 모르겠습니다.
검증은 위와 다르지 않으므로 여기서는 반복하지 않겠습니다.

2. 동시 스레드 수-페이지/API

QPS 기반 흐름 제어는 단위 시간당 요청 수만 세면 이해하기 쉬워야 합니다. 또한 Sentinel은 흐름 제어를 위한 동시 스레드 수도 지원합니다. 동시 스레드 수는 Hystrix에서 처음 제공되었으며, Hystrix는 동시 스레드 수에 대해 스레드 풀 격리와 세마포 격리라는 두 가지 구현 방법을 제공합니다. 스레드 풀 격리는 리소스에 대한 스레드 풀을 미리 할당하는 것으로, 지정된 리소스는 지정된 스레드 풀의 스레드만 사용할 수 있으며 흐름 제어가 소진됩니다. 세마포어 격리는 들어오는 스레드의 총 개수만 계산합니다. 총 개수에 도달하면 흐름을 제어합니다. Sentinel의 동시 스레드 솔루션은 두 가지(스레드 풀 격리, 세마포 격리)를 통합한 것과 동일합니다. Sentinel은 요청 스레드와 실행 스레드를 분리한다는 점에서 스레드 풀 격리와 유사합니다. 세마포어와 유사하게 Sentinel은 스레드의 총 개수를 계산합니다. (이 양은 실행 스레드의 개수여야 합니다.) 스레드 개수가 흐름 제어에 도달하면.

그런 다음 동시 스레드 데이터의 페이지 구성을 살펴보겠습니다: 동시
여기에 이미지 설명을 삽입하세요.
여기에 이미지 설명을 삽입하세요.
스레드 수의 흐름 제어를 트리거하려면 여기의 리소스 코드를 약간 조정해야 하며, 프로그램을 잠시 동안 수동으로 절전 모드로 설정해야 합니다. 동시 스레드 수를 늘리십시오. 그렇지 않으면 요청이 들어올 때 요청이 차단됩니다. 처리 후에는 트리거하기 어렵습니다(휴면 시간이 퓨즈의 통계 시간을 초과하면 퓨즈가 트리거되지 않습니다).

위는 페이지 구성입니다.API도 매우 간단합니다.등급만 변경하면 됩니다.그 외 구성은 실제로 QPS와 다르지 않습니다. 다른 코드는 위와 다르지 않으며, 다음과 같이 페이지 구성을 API로 마이그레이션하는 것입니다.

import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Collections;

/**
 * @author pcc
 */
@Configuration
public class FlowConfig {
    
    

    @Bean
    public FlowRule getFlowRule() {
    
    
        FlowRule flowRule = new FlowRule();
        // 声明流控的资源
        flowRule.setResource("testFlowRule");
        // 声明使用的流控规则:0 并发线程数,1 QPS
        flowRule.setGrade(RuleConstant.FLOW_GRADE_THREAD);

        // 流控规则设置-线程并发阈值2
        flowRule.setCount(2);
        // 来源没有默认值,必须手动设定,default表示对所有来源生效
        flowRule.setLimitApp("default");


        // 将流控规则交给流控管理器
        FlowRuleManager.loadRules(Collections.singletonList(flowRule));
        return flowRule;
    }
}

참고:
QPS와 동시 스레드 수는 일부 시나리오에서 비슷한 효과를 가지지만 대부분의 시나리오는 다릅니다. 어떻게 말할까?
QPS는 단위 시간당 들어오는 요청 수를 의미하며 해당 요청이 단위 시간당 최대 임계값 요청 수를 수신하는 한 다른 요청은 들어올 수 없습니다.
동시 스레드 수는 현재 요청이 차지하는 스레드 수를 강조합니다. 1초 내에 3개의 요청이 들어오는 시나리오가 있습니다. 3개의 요청이 QPS의 임계값이라고 가정하면 QPS의 흐름 제어가 트리거됩니다. 요청이 들어오지만 이 세 가지 작업을 수행하는 데는 3개의 스레드가 있지만 두 가지 가능성이 있습니다. ① 이 세 가지 요청을 서버 측에서 처리하는 데 10초가 걸리므로 이 10초 내에 다른 요청이 들어오면 흐름 제어가 되지만 QPS는 그렇지 않습니다. 처리하는데 시간이 얼마나 걸리는지. ② 서버가 이 세 가지 요청을 처리하는 데는 0.5초밖에 걸리지 않았으므로 이 1초 내에 최대 6개의 요청이 들어올 수 있습니다. 이는 QPS와 동시 스레드 수의 차이입니다. 요약하자면, QPS는 유입 트래픽에 중점을 두고, 동시 스레드 수는 리소스 내 동시성에 중점을 둡니다.

3. 흐름 제어 모드 연결(QPS 사용)-페이지/API

실제 시나리오에는 이러한 시나리오가 있을 것입니다. 일부 핵심 인터페이스는 비활성화하면 안 되지만 일부 인터페이스는 문제 없이 짧은 시간 동안 비활성화될 수 있습니다.
이 시나리오에서는 연관된 흐름 제어 모드를 사용할 수 있습니다. 소위 연관된 흐름 제어 모드는 아래와 같습니다. 흐름 제어 모드에서 연관을 선택하고 연관된 리소스를 입력해야 리소스 addStock에 액세스할 수 있습니다. QPS 임계값 2에 도달하면 testFlowRule이 흐름 제어됩니다.
참고: 반대 방향으로 수행하지 마십시오. 첫 번째 줄에 선언된 리소스는 연결된 리소스에 액세스하여 QPS 임계값에 도달할 때 흐름이 제어됩니다.
여기에 이미지 설명을 삽입하세요.
여기서 확인하려면 Jemter(다른 http 클라이언트 도구도 사용할 수 있음)를 사용하여 스레드 그룹을 설정한 다음 초당 액세스 수가 2 이상에 도달해야 합니다. 다음 구성을 만듭니다.
여기에 이미지 설명을 삽입하세요.

그런 다음 addStock에 액세스하는 동안 testFlowRule에 대한 액세스는 아래와 같이 흐름을 제어해야 합니다.

(여기서의 addStock 인터페이스는 일반 인터페이스와 다르지 않으므로 코드를 게시하지 않습니다. 반드시 Sentinel 리소스로 등록하고 리소스 이름이 addStock이라고 선언해야 한다는 점에 유의해야 합니다.)
여기에 이미지 설명을 삽입하세요.
testFlowRule의 액세스 요청은 완전히 흐름 제어됩니다. 현재 addStock의 QPS가 10이고 이는 우리가 설정한 2를 초과하므로 testFlowRule에 대한 모든 액세스는 흐름 제어됩니다.

생각: addStock이 회로 차단기를 작동시키면 testFlowRule이 흐름을 정상적으로 제어할 수 있을까요?

addStock 서킷 브레이크 동안에는 시스템 자원이 소모되지 않으므로 흐름 제어를 해서는 안 되며, 이때 흐름 제어는 의미가 없으므로 흐름 제어를 해서는 안 되며, 실제로 흐름 제어를 해야 할지 여부를 결정하는 과정이 위에서 언급한 과정이 있습니다. 흐름 제어: 먼저 회로가 회로 차단기인지 확인합니다. 퓨즈는 자연스럽게 흐름을 제어하지 않습니다. ![여기에 그림 설명 삽입](https://img-blog.csdnimg.cn/0b42ce80d90a457ab8494c08684294ff.png) 위의 출력 방법에서 testFlowRule이 일반 데이터이고 흐름 제어되지 않았음을 알 수 있습니다. 기대와 함께.

------------------------------------- -------------API 구성--------- ------------------------------------------------
위의 모든 작업, API를 이용하여 관련 흐름 제어를 설정하는 방법은 다음과 같이 수정 가능하며, 다른 코드에 차이가 없으면 게시하지 않겠습니다.

import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Collections;

/**
 * @author pcc
 */
@Configuration
public class FlowConfig {
    
    

    @Bean
    public FlowRule getFlowRule() {
    
    
        FlowRule flowRule = new FlowRule();
        // 声明流控的资源
        flowRule.setResource("testFlowRule");
        // 声明使用的流控规则:0 并发线程数,1 QPS
        flowRule.setGrade(RuleConstant.FLOW_GRADE_THREAD);

        // 流控规则设置-线程并发阈值2
        flowRule.setCount(2);
        // 来源没有默认值,必须手动设定,default表示对所有来源生效
        flowRule.setLimitApp("default");
        // 流控模式-关联
        flowRule.setStrategy(RuleConstant.STRATEGY_RELATE);
        // 流控模式-关联-资源
        flowRule.setRefResource("addStock");


        // 将流控规则交给流控管理器
        FlowRuleManager.loadRules(Collections.singletonList(flowRule));
        return flowRule;
    }
}

테스트나 다른 것에는 차이가 없으므로 여기서는 반복하지 않겠습니다.

4. 흐름 제어 모드 - 링크(동시 사용 스레드 수) - 페이지/API

흐름 제어 리소스는 일반적으로 인터페이스에 추가되지만 일반 메서드에 추가할 수도 있습니다.이러한 시나리오가 있으면 인터페이스 A와 B가 동시에 동일한 리소스를 호출합니다. A 사업이 더 중요하고 B 사업이 그다지 중요하지 않은 경우, 자원이 제한되어 있을 때 자원을 A에 기울이고 B의 흐름을 제어할 수 있습니다.
이렇게 보면 링크 흐름 제어는 연관 흐름 제어와 비슷합니까? 링크 흐름 제어로 수행할 수 있는 작업은 연결된 흐름 제어를 통해서도 가능하지만 연결된 흐름 제어는 다양한 시나리오의 리소스를 대상으로 하는 반면, 링크 흐름 제어는 동일한 리소스에 대한 다양한 입구를 제한하는 것에 더 가깝습니다. 연관 흐름 제어와 링크 흐름 제어의 또 다른 차이점은 연관 흐름 제어 B 자원이 임계값, 흐름 제어 A에 도달하는 반면, 링크 흐름 제어는 자원 B가 임계값에 도달할 때 흐름 제어 B의 소스 중 하나라는 것입니다.
링크 흐름 제어를 사용하려면 다음과 같이 application.yml에 spring.cloud.sentinel.web-context-unify=false 구성을 추가해야 합니다.

spring:
  application:
    # 阿里系的组件好像都会使用这个作为默认名称:nacos、sentinel
    name: stock-server # nacos配置中心和注册中心默认都是用这个作为默认名称
  cloud:
    sentinel:
      transport:
        port: 8719 # dashboard控制面版与sentinel通信的本地端口
        dashboard: 127.0.0.1:8088   # sentinel控制面板地址
      eager: true # 是否饥饿加载,默认为false,开启后启动项目就会初始化,而不是在第一次调用,dashboard也可以直接就可以看到服务,不用等待接口调用后才可以看到
      web-context-unify: false # 默认true,收敛资源访问的所有入口,若是想要使用链路流控,必须关闭
      

/testFlowRule1 및 /testFlowRule2 인터페이스에서 동시에 참조되는 testChain 메소드가 있는데, testChainQPS 또는 동시 스레드가 임계값에 도달하면 /testFlowRule1에 대한 흐름 제어를 설정합니다. 코드는 다음과 같습니다.

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.cheng.stockserver.flowrule.degradeclass.BlockMethod;
import lombok.extern.slf4j.Slf4j;

/**
 * @author pcc
 */
@Slf4j
@org.springframework.stereotype.Service
public class serviceImpl implements ChainService {
    
    


    @Override
    @SentinelResource(
            value = "testChain",
            blockHandler ="testChainFlow",
            blockHandlerClass = BlockMethod.class
    )
    public void testChain() {
    
    
        log.info("testChain start");
        // 使用并发线程数模拟流控-加大方法响应时间,提高线程并发数
        try {
    
    
            Thread.sleep(1000);
        } catch (InterruptedException e) {
    
    
            throw new RuntimeException(e);
        }

    }
}

또한 흐름 제어 방식은 정적 메소드를 사용해야 하고, 반환 값이 일관적이어야 하며, BlockException을 선언해야 한다는 점 등이 모두 블록 핸들러를 사용할 때 따라야 하는 규정이다. 흐름 제어 방법은 다음과 같습니다.

    /**
     * 链路流控使用的流控方法
     */
    public static void testChainFlow(BlockException blockException) {
    
    

        if(blockException instanceof DegradeException){
    
    
            // 处理熔断
            log.info("链路流控-熔断-方法: {}","DegradeException");

        }
        if(blockException instanceof FlowException){
    
    
            // 处理流控
            log.info("链路流控-流控-方法: {}","FlowException");
        }

    }

페이지에 구성 추가:
여기에 이미지 설명을 삽입하세요.
다음은 테스트 스크린샷입니다. testFlowRule1 인터페이스에 의한 testChain 호출만 흐름 제어되고, testFlowRule2 호출은 흐름 제어되지 않는 것을 볼 수 있습니다.
여기에 이미지 설명을 삽입하세요.
************************************************** * ********** 다음은 APIj에 대한 소개입니다******************************** **** ************************
API를 사용하는 것은 페이지를 사용하는 것과 동일하며, 유일한 변경 사항은 코드를 사용하여 규칙을 구성하는 것입니다. else는 동일합니다. 변경된 점은 표시코드와 검증의 차이가 없습니다. API 사용 시 동작하는 속성 및 연관 모드는 동일하며, 속성값만 변경하면 다음과 같습니다.

import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Collections;

/**
 * @author pcc
 */
@Configuration
public class FlowConfig {
    
    

    @Bean
    public FlowRule getFlowRule() {
    
    
        FlowRule flowRule = new FlowRule();
        // 声明流控的资源
        flowRule.setResource("testChain");
        // 声明使用的流控规则:0 并发线程数,1 QPS
        flowRule.setGrade(RuleConstant.FLOW_GRADE_THREAD);

        // 流控规则设置-线程并发阈值2
        flowRule.setCount(3);
        // 来源没有默认值,必须手动设定,default表示对所有来源生效
        flowRule.setLimitApp("default");
        // 流控模式-链路
        flowRule.setStrategy(RuleConstant.STRATEGY_CHAIN);
        // 流控模式-链路-路径
        flowRule.setRefResource("/flow/testFlowRule1");



        // 将流控规则交给流控管理器
        FlowRuleManager.loadRules(Collections.singletonList(flowRule));
        return flowRule;
    }
}

5. 흐름 제어 효과-예열-페이지/API

흐름 제어 효과는 기본적으로 빠른 실패(QPS만이 흐름 제어 효과를 지원합니다.) 빠른 실패는 우리가 지정한 블록 핸들러 메소드를 호출합니다. 실제로 QPS가 순간적으로 증가하면 서버가 서비스를 직접적으로 압도할 수 있습니다. 스트레스 테스트 시 동시성은 100,000까지 허용되지만, 실제 비즈니스에서는 QPS가 매우 낮은 수준에서 10w로 떨어지면 서비스도 압도될 수 있는데, 이때 예열의 흐름 제어 효과를 활용하는 것을 고려해 볼 수 있다. 예열 흐름 제어는 예열 시간 동안 QPS를 천천히 증가시켜 시스템이 반응할 시간을 제공함으로써 시스템이 순간적인 피크로 인해 압도당하지 않도록 보장합니다.
이러한 시나리오가 있는 경우: 정상적인 상황에서 QPS가 10이고 갑자기 QPS가 1000에 도달하고 예열 모드를 사용하며 예열 시간이 10초인 경우 Sentinel은 10초 이내에 흐름 제어 QPS 값을 천천히 증가시킵니다. 100 QPS만 수신하고 나머지는 실패합니다. 두 번째 초에는 200 QPS를 수신하고 나머지도 실패합니다. 10초에는 1000 QPS를 처리할 수 있습니다. 이때 워밍업은 다음과 같습니다. 완전한.
예열 모드에는 작은 단점이 있습니다: 예열 기간 동안의 QPS 임계값은 실제로 우리가 설정한 최대값이 아니지만, 시간이 지남에 따라 점차적으로 우리가 설정한 최대값으로 증가합니다. 페이지 구성은 다음과 같습니다.
여기에 이미지 설명을 삽입하세요.

테스트를 위해서는 여기서 Jemeter를 사용해야 합니다. 왜냐하면 100 QPS는 사람이 도달할 수 없고 도구를 사용해야 하기 때문입니다. 위 그림과 같이 testChain에서 예열 흐름 제어를 수행합니다. 예상 효과: 처음에는 일부 요청이 흐름 제어되도록 메시지가 표시됩니다. 10초 후에는 모든 요청이 흐름 제어되지 않습니다. (jemeter는 동시성을 다음으로 설정합니다. 100): 여기에는 실제 스크린샷이 없습니다
여기에 이미지 설명을 삽입하세요.
. Sentinel의 예열 시간이 10초라는 점을 제외하면 효과는 실제로 우리가 예상한 것과 매우 가깝습니다. Sentinel의 QPS 임계값은 10초 이내에 상승하며 이는 선형이 아닙니다. 완료하는 데 10초가 걸리지 않을 수 있습니다. 예열은 가능하지만 10초를 보장할 수 있습니다. 최종 시스템의 QPS는 100이어야 합니다. 기본적으로 이는 우리의 모든 요구를 충족합니다.

************************************************** * ********** API 소개는 다음과 같습니다******************************** *** ************************
페이지에 비해 API는 구성 두 줄만 추가합니다. 매우 간단하고 다른 것은 없습니다. 차이점:
참고: 동시 스레드 수는 흐름 제어 효과를 지원하지 않습니다.

import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Collections;

/**
 * @author pcc
 */
@Configuration
public class FlowConfig {
    
    

    @Bean
    public FlowRule getFlowRule() {
    
    
        FlowRule flowRule = new FlowRule();
        // 声明流控的资源
        flowRule.setResource("testChain");
        // 声明使用的流控规则:0 并发线程数,1 QPS
        flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);

        // 流控规则设置-线程并发阈值2
        flowRule.setCount(100);
        // 来源没有默认值,必须手动设定,default表示对所有来源生效
        flowRule.setLimitApp("default");
        // 流控模式-链路
        flowRule.setStrategy(RuleConstant.STRATEGY_CHAIN);
        // 流控模式-链路-路径
        flowRule.setRefResource("/flow/testFlowRule1");
        // 流控效果-预热
        flowRule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_WARM_UP);
        // 流控效果-预热-预热时间: 10s
        flowRule.setWarmUpPeriodSec(10);


        // 将流控规则交给流控管理器
        FlowRuleManager.loadRules(Collections.singletonList(flowRule));
        return flowRule;
    }
}

6. 흐름 제어 효과 대기열 페이지/API

여기에 흐름 제어 효과가 있습니다. 줄을 서서 기다리는 경우, 그러한 시나리오가 있을 수 있습니다. 시스템은 1,000 QPS만 견딜 수 있지만 최대 QPS는 1,500입니다. 나머지 500개는 즉시 처리할 수 없지만 피크가 오래 지속되지 않거나 피크와 과소평가가 번갈아 나타나므로 현재로서는 최선의 좋은 솔루션입니다. 대기열 대기 흐름 제어 효과를 사용하는 것입니다. 큐잉 효과는 Peak Shaving 및 Valley Filling과 유사합니다. 즉각적으로 높은 트래픽을 Peak Shaving으로 처리할 수 없는 요청은 요청이 많지 않을 때 처리에 투입됩니다. 물론, 요청이 많지 않아 요청이 처리되지 않는 경우도 있는데, 이 경우에는 흐름 제어 방식의 블록 핸들러가 실행됩니다.
페이지 구성은 다음과 같습니다:
여기에 이미지 설명을 삽입하세요.
위 구성은 QPS가 100보다 큰 요청이 대기 대기열에 들어가 시스템이 실행될 때까지 대기한다는 의미입니다. 최대 대기 시간 제한은 5000ms입니다. 5초 후에 처리되지 않으면 흐름이 종료됩니다. 제어 메소드가 실행됩니다. 페이지 구성 코드를 사용할 때 아무것도 변경할 필요가 없습니다. 확인에도 jemeter의 도움이 필요합니다. 동시성을 150으로 설정하고 한 번만 실행할 수 있습니다. 시스템이 흐름 제어 방법을 실행하지 않으면 우리의 요청이 100개를 초과하는 경우 정상적으로 처리되며, 대기열 대기도 적용됩니다.

여기에 이미지 설명을 삽입하세요.
여기서는 사진의 일부만 촬영되었으며 실제로 모든 정보가 정상이므로 구성한 대기 대기열이 완전히 정상임을 증명합니다.
************************************************** * ********** API 소개는 다음과 같습니다******************************** *** **********************
페이지 구성과 비교했을 때 유일한 변경 사항은 흐름 제어 효과 대기열 및 대기를 코드에 넣은 것입니다. 다른 변경 사항은 없습니다. :

import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Collections;

/**
* @author pcc
*/
@Configuration
public class FlowConfig {
    
    

   @Bean
   public FlowRule getFlowRule() {
    
    
       FlowRule flowRule = new FlowRule();
       // 声明流控的资源
       flowRule.setResource("testChain");
       // 声明使用的流控规则:0 并发线程数,1 QPS
       flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);

       // 流控规则设置-线程并发阈值2
       flowRule.setCount(160);
       // 来源没有默认值,必须手动设定,default表示对所有来源生效
       flowRule.setLimitApp("default");
       // 流控模式-链路
       flowRule.setStrategy(RuleConstant.STRATEGY_CHAIN);
       // 流控模式-链路-路径
       flowRule.setRefResource("/flow/testFlowRule1");
       // 流控效果-排队等待
       flowRule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER);
       // 流控效果-排队等待-超时时间: 5s
       flowRule.setMaxQueueingTimeMs(5000);


       // 将流控规则交给流控管理器
       FlowRuleManager.loadRules(Collections.singletonList(flowRule));
       return flowRule;
   }
}

7. 소스 기반 제어 흐름

소스별 흐름 제어는 흐름 제어 모드의 링크 모드와 다소 유사하지만 서로 다른 위치에서 작동합니다. 소스를 타겟팅하는 것은 더 높을 것입니다. 요청 헤더의 서비스 호출자와 이 소스에 동의할 수 있습니다. 그런 다음 특정 소스에 대한 흐름 제어를 수행할 수 있습니다. 앞서 언급한 흐름 제어 모드의 링크는 서로 다른 인터페이스에서 동일한 리소스를 호출할 때 서비스 내부에서 수행되는 흐름 제어를 의미하며, 물론 소스를 다르게 제공하는 것만으로도 소스 제어와 동일한 효과를 얻을 수 있는 링크 모드도 사용할 수 있습니다. .입고별로 Link Flow Control이 가능하도록 다양한 출입구를 제공합니다. 그러나 이렇게 하면 의심할 여지 없이 코드의 양이 늘어나므로 소스를 제어하려면 소스 제한을 사용하는 것이 가장 좋습니다.
흐름 제어를 위해 소스를 사용하려면 Sentinel의 RequestOriginParser를 사용해야 합니다. 이는 소스를 구문 분석할 수 있는parseOrigin 메서드를 제공합니다. 소스를 어떻게 파싱할지는 우리 몫이고, Origin, Referer 등에 따라 지정할 수 있고, 요청 헤더를 커스터마이징할 수도 있습니다.
여기에서는 사용자 정의 요청 헤더를 사용하여 소스를 지정합니다. 요청 헤더에 매개변수 소스가 포함되어 있다고 가정합니다.

import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.util.Optional;


/**
 * @author pcc
 */
@Component
public class SentinelOriginRequestOriginParser implements RequestOriginParser {
    
    
    @Override
    public String parseOrigin(HttpServletRequest request) {
    
    
        String source = request.getHeader("source");
        /**
         * 当存在来源时我们直接设置来源为传入的值
         * 否则返回null
         */
        if (Optional.ofNullable(source).isPresent()) {
    
    
            return source;
        }
        return null;
    }
}

위의 코드에서는 요청 헤더의 소스를 소스로 가져온 다음 jemter를 사용하여 요청 헤더 매개변수 소스를 설정해야 합니다. 여기서는 두 개의 http 요청에 대해 jemeter를 사용했는데 하나의 요청 헤더 소스가 하나로 설정되고 하나의 소스를 2로 설정하고 페이지 구성은 다음과 같습니다:
여기에 이미지 설명을 삽입하세요.
위에서 구성한 것처럼 QPS가 100보다 큰 경우 testFlowRule1에서 흐름 제어가 수행되며 이때 소스 2가 있는 요청만 흐름 제어됩니다. 예를 들어, 소스가 2가 아니면 QPS가 100보다 크더라도 흐름 제어가 없습니다.
여기에 이미지 설명을 삽입하세요.
위는 요청 헤더에 source=two 로 설정하고 동시 요청 수를 160으로 설정한 경우의 요청입니다. 예상대로 흐름 제어가 발생합니다. test source=1 이고 동시성이 160일 경우 흐름이 발생하지 않습니다. 제어.

************************************************** * ********** API 소개는 다음과 같습니다******************************** *** **********************
API는 약간의 코드만 변경하면 되며 다른 페이지 구성은 변경할 필요가 없습니다.

import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Collections;

/**
* @author pcc
*/
@Configuration
public class FlowConfig {
    
    

   @Bean
   public FlowRule getFlowRule() {
    
    
       FlowRule flowRule = new FlowRule();
       // 声明流控的资源
       flowRule.setResource("testChain");
       // 声明使用的流控规则:0 并发线程数,1 QPS
       flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);

       // 流控规则设置-线程并发阈值2
       flowRule.setCount(100);
       // 来源没有默认值,必须手动设定,default表示对所有来源生效
       flowRule.setLimitApp("one");
       // 流控模式-链路
       flowRule.setStrategy(RuleConstant.STRATEGY_CHAIN);
       // 流控模式-链路-路径
       flowRule.setRefResource("/flow/testFlowRule1");


       // 将流控规则交给流控管理器
       FlowRuleManager.loadRules(Collections.singletonList(flowRule));
       return flowRule;
   }
}

8. 클러스터 구성

클러스터 모드를 사용하지 않고 클러스터 서비스인 경우 설정한 규칙은 단일 노드에 적용됩니다.
클러스터 모드를 사용합니다. 클러스터 서비스인 경우 설정한 규칙은 전체 클러스터에 적용할 수 있으며 단일 노드의 흐름 제어를 은폐 솔루션으로 사용할 수 있습니다. 이것이 실제로 마이크로서비스가 수행해야 하는 모드입니다. 사용 (클러스터의 로드가 라운드 로빈인 경우) 폴링을 사용하면 클러스터 모드와 독립형 모드의 차이가 특별히 크지 않으며, 폴링을 사용하지 않으면 차이가 매우 커집니다.
이 모드는 여기에 너무 많은 것을 담기에는 부담이 되기 때문에 따로 다루어야 하므로 당분간 소개하지 않겠습니다.
클러스터 모드 공식 소개: Sentinel 흐름 제어 클러스터 모드
여기에 이미지 설명을 삽입하세요.

6. 현재 제한 승인 규칙: AuthorityRule

권한 부여 규칙은 실제로 리소스에 대한 블랙리스트와 화이트리스트를 구성합니다. 리소스에 대해 화이트리스트가 구성된 경우 구성되지 않은 소스는 블랙리스트에 추가됩니다. 반대의 경우도 마찬가지입니다. 리소스에 대해 블랙리스트가 구성된 경우 구성되지 않은 소스는 화이트리스트입니다.

1.권한 부여 규칙-페이지/API

권한 부여 규칙을 사용하기 위한 전제 조건은 데이터 소스를 얻는 것입니다. 이는 흐름 제어의 소스와 동일하므로 RequestOriginParser를 사용하면 됩니다. 여기의 RequestOriginParser는 흐름 제어의 RequestOriginParser와 차이가 없으므로 반복하지 않겠습니다. 코드를 작성하면 구성해야 할 페이지도 매우 간단합니다.
참고: 작성자가 인증을 확인했을 때 인터페이스에 대한 인증은 성공했지만 일반적인 메소드에 대한 인증은 적용되지 않았습니다. 실제로 인터페이스가 들어온 것을 고려하면 메소드에 대한 접근을 허용하지 않는 것이 이상합니다. 따라서 일반적으로 인터페이스 수준에서도 가로채야 합니다.
여기에 이미지 설명을 삽입하세요.
이것이 구성되면 현재 인터페이스에 액세스할 때 다음과 같이 소스가 하나인 요청만 들어올 수 있고 다른 요청은 거부된다는 의미입니다.
여기에 이미지 설명을 삽입하세요.
화이트리스트가 두 개 이상 있으면 어떻게 되나요? 구성 중에 쉼표를 사용하여 여러 화이트리스트(또는 블랙리스트) 리소스를 다음과 같이 구분할 수 있습니다.
여기에 이미지 설명을 삽입하세요.
************************** ***** ******************************* API 소개는 다음과 같습니다************ * ***********************************************
API는 매우 유사합니다. 페이지 구성의 경우 구성이 코드로 이동되고 다른 변경 사항은 적용되지 않습니다. 새 코드는 다음과 같습니다.

  @Bean
  public AuthorityRule getAuthorityRule(){
    
    
      AuthorityRule rule = new AuthorityRule();
      // 授权规则管理的资源
      rule.setResource("/flow/testFlowRule1");
      // 授权策略:白名单0,黑名单1
      rule.setStrategy(RuleConstant.AUTHORITY_WHITE);
      //
      rule.setLimitApp("one,two");

      // 将授权规则交给授权管理器
      AuthorityRuleManager.loadRules(Collections.singletonList(rule));
      return rule;
  }

7. 현재 제한 핫스팟 규칙: ParamFlowRule

핫스팟 규칙은 리소스 흐름 제어를 기반으로 리소스 요청 매개변수의 흐름을 제어하기 때문에 실제로 흐름 제어 규칙에 핫스팟 규칙이 포함되어야 합니다. 실제로 핫스팟 규칙은 흐름 제어를 더욱 세부적으로 만듭니다. 따라서 그는 실제로 흐름 제어 규칙에 포함되어야 합니다. 또한 핫스팟 규칙은 QPS 모드의 핫스팟만 지원하고 동시 스레드 수는 지원하지 않으며, 흥미롭게도 제외도 지원합니다.
핫스팟 규칙의 적용 시나리오는 주로 특정 데이터에 너무 자주 액세스하거나 서버에 큰 부담을 주는 경우입니다. 이 데이터의 액세스 빈도를 제어해야 합니다. 예를 들어 상대적으로 큰 쿼리 작업이 있고 type=10은 아마도 type= 10은 데이터가 많을 것입니다. 항상 이렇게 확인하는 것을 원하지 않습니다. type만 흐름 제어를 할 수 있습니다. type=10일 때 흐름 제어가 수행됩니다. 동일할 때 다른 값으로 변경하려면 흐름 제어가 필요하지 않거나 통과하도록 허용된 QPS가 더 큽니다.

1. 핫스팟 규칙 페이지

이것은 핫스팟 규칙의 구성 페이지입니다. 매개변수 유형과 이름이 있는 인터페이스가 있다고 가정합니다.
여기에 이미지 설명을 삽입하세요.
위의 매개변수를 설명합니다.

  • 매개변수 색인: 인터페이스 매개변수 목록의 첨자, 여기서 입력하는 첫 번째 첨자는 0입니다.
  • 단일 머신 임계값: QPS 임계값
  • 통계 창 시간: 여기서 QPS의 기본값은 초당 요청 수이지만 통계의 단위 시간을 변경할 수도 있습니다. 여기서는 10초로 변경됩니다. 즉, 10초 이내에 유형을 전달하는 요청 매개변수가 3개 있는 경우 흐름 제어가 가능합니다. 트리거됩니다.
  • 클러스터 여부: 여기서 클러스터 모드는 흐름 제어의 클러스터 모드와 동일하므로 차이가 없으므로 여기서는 자세히 설명하지 않겠습니다.
  • 매개변수 예외: 이는 예외 규칙을 구성하는 것과 같습니다. 즉, 위의 흐름 제어 규칙은 예외 규칙을 기반으로 실행되어야 함을 의미합니다.
  • 매개변수 유형: 여기서 유형이 문자열인 매개변수 인덱스 유형과 일치해야 합니다.
  • 전류 제한 임계값: 매개변수 값에 대한 특정 임계값입니다. 이를 통해 특정 값에 대한 임계값을 구성할 수 있습니다. 예를 들어 유형이 10이고 동시성을 1로 제어하려는 경우 임계값을 다음과 같이 설정할 수 있습니다. 1입니다. 다른 값에는 이 제한이 적용되지 않습니다.

이러한 매개변수는 이해하기 더 쉽습니다. 센티널에 등록하려면 인터페이스를 추가해야 합니다.

@RequestMapping("/testParamFlowRule2")
@SentinelResource(
        value = "testParamFlowRule2",
        blockHandler = "testParamFlowRule2",
        blockHandlerClass = BlockMethod.class
)
public String testParamFlowRule2(@RequestParam("type") String type,@RequestParam("name") String name) throws Exception{
    
    
    log.info("{},{}",type,name);
    service.testChain();
    return "testFlowRule1 : success";
}

그런 다음 다음과 같이 리소스의 blockhandler 메서드도 제공해야 합니다.
참고: 정적이어야 하며 BlockException이 있어야 합니다.

/**
 * 热点流控
 * @param type
 * @param name
 * @return
 * @throws Exception
 */
public static String testParamFlowRule2(String type,String name,BlockException blockException) throws Exception{
    
    
    log.info("热点流控方法:{},{}",type,name);
    return "热点流控了 : success";
}

그러면 위의 구성에 따라 표시되어야 할 효과는 유형이 11이면 10초마다 최대 100번까지 접속이 가능하고(이 손 속도는 클릭하기 어렵다), 유형이 10이면 최대 10초에 한 번씩 접속 가능하며, 그 외의 경우에는 10초마다 접속 가능합니다. 3번 방문하고 취했습니다.

여기에 이미지 설명을 삽입하세요.
처음에 type=11이 전송되면 수동으로 클릭해도 흐름이 제어되지 않고, 10이 전송되면 네 번째로 흐름이 제어되는 것을 알 수 있습니다.

2. 핫스팟 규칙-API

API 구성과 페이지의 차이점은 구성 항목이 코드로 이동된다는 것입니다. 다른 차이점은 없습니다. 여기서는 코드 작성만 표시됩니다. 확인은 위와 다르지 않습니다. 참고: 대부분의 API 구성은 지원합니다. 페이지보다 약간 더 많은 기능이 있습니다
. 관심이 있으면 공부할 수 있지만 기본적으로 동일합니다.

    @Bean
    public ParamFlowRule getParamFlowRule(){
    
    
        ParamFlowRule paramFlowRule = new ParamFlowRule();
        // 热点流控-资源
        paramFlowRule.setResource("testParamFlowRule2");
        // 限流模式-必须QPS,默认就是QPS
        paramFlowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);


        // 参数索引: 方法参数列表下标
        paramFlowRule.setParamIdx(0);
        // 单机阈值
        paramFlowRule.setCount(3);
        // 单机阈值的统计时间:默认1s,支持更改单位秒
        paramFlowRule.setDurationInSec(10);



        // 参数例外项
        ParamFlowItem paramFlowItem = new ParamFlowItem();
        // 参数例外项-参数类型:必须与setParamIdx对应的参数保持一致
        paramFlowItem.setClassType("java.lang.String");
        // 参数例外项-参数值
        paramFlowItem.setObject("10");
        // 参数例外项-限流阈值
        paramFlowItem.setCount(1);

        ParamFlowItem paramFlowItem2 = new ParamFlowItem();
        // 参数例外项-参数类型:必须与setParamIdx对应的参数保持一致
        paramFlowItem2.setClassType("java.lang.String");
        // 参数例外项-参数值
        paramFlowItem2.setObject("11");
        // 参数例外项-限流阈值
        paramFlowItem2.setCount(101);

        List<ParamFlowItem> list = new ArrayList<>();
        list.add(paramFlowItem);
        list.add(paramFlowItem2);
        paramFlowRule.setParamFlowItemList(list);

        // 加载热点流控规则
        ParamFlowRuleManager.loadRules(Collections.singletonList(paramFlowRule));
        return paramFlowRule;
    }

8. 전류 제한 시스템 규칙: SystemRule

앞서 소개한 다양한 규칙은 단일 리소스나 단일 인터페이스에 대한 것이므로 현재 전체 시스템의 한계를 보장할 수는 없으며, 시스템 규칙 j는 시스템 전체에 대해 더 높은 수준의 보호를 제공하도록 설계되었습니다. , 단일 리소스의 흐름 제어는 은폐 솔루션으로 사용될 수 있으며 시스템 규칙은 전체 솔루션으로 사용될 수 있습니다(일부는 클러스터 모드와 유사하지만 동일하지는 않음).

1. 시스템 규칙 페이지/API

다음은 시스템 규칙의 구성 페이지입니다.
여기에 이미지 설명을 삽입하세요.
먼저 각 매개변수의 의미를 살펴보겠습니다.
시스템 규칙 공식 문서: System Adaptive Current Limiting

  • LOAD: 시스템의 로드1은 적응형 시스템 보호를 위한 경험적 지표로 사용됩니다. 시스템 부하1이 설정된 임계값을 초과하고 시스템의 현재 동시 스레드 수가 예상 시스템 용량을 초과하는 경우 시스템 보호가 트리거됩니다.
    참고:
    1. 시스템의 현재 동시 스레드 수: maxQps * minRt는 대략적으로 이것으로 계산할 수 있습니다.
    2. 시스템 용량: 일반적으로 CPU 코어*2.5로 설정됩니다.
    3. Linux 시스템에만 load1 매개변수가 있습니다. 가동 시간을 사용하여 시스템 부하
    여기에 이미지 설명을 삽입하세요.

  • RT: 단일 머신의 모든 수신 트래픽의 평균 RT가 임계값에 도달하면 시스템 보호가 트리거되며 단위는 밀리초입니다.

  • 스레드 수: 단일 시스템의 모든 수신 트래픽에 대한 동시 스레드 수가 임계값에 도달하면 시스템 보호가 트리거됩니다.

  • 수신 QPS: 단일 시스템의 모든 수신 트래픽 QPS가 임계값에 도달하면 시스템 보호가 트리거됩니다.

  • CPU 사용량: 시스템 CPU 사용량이 임계값을 초과하면 상대적으로 민감한 시스템 보호가 트리거됩니다(값 범위 0.0-1.0).

위의 내용은 시스템 규칙에서 지원하는 모든 매개변수이며 로드 및 RT 설정 등 다양한 전략을 동시에 사용하여 시스템 규칙 설정을 지원합니다. 시스템 규칙은 시스템 서버 수준에서 서버를 보호하며 위에서 언급한 흐름 제어, 핫스팟, 권한 부여, 회로 차단기 등은 모두 리소스 또는 인터페이스를 기반으로 하며 이것이 주요 차이점입니다.
다음은 설정된 RT 규칙입니다.
여기에 이미지 설명을 삽입하세요.
예상 결과: 인터페이스의 평균 RT가 30ms를 초과하면 흐름 제어가 트리거됩니다.
다음은 새로운 인터페이스입니다.

    @RequestMapping("/testSystemRule")
    @SentinelResource(
            value = "testSystemRule",
            blockHandler = "testSystemRule",
            blockHandlerClass = BlockMethod.class
    )
    public String testSystemRule(@RequestParam("type") String type,@RequestParam("name") String name) throws Exception{
    
    
        log.info("{},{}",type,name);
        // 等待40ms,模仿RT超过30ms
        Thread.sleep(400);
        return "testSystemRule : success";
    }

다음은 그의 흐름 제어 블록 핸들러 방법입니다.

    /**
     * 系统规则
     */
    public static String testSystemRule(String type, String name,BlockException blockException) throws Exception{
    
    
        log.info("{},{}",type,name);
        return "系统规则-流控 : success";
    }

참고:
1. 시스템 규칙이 설정된 값에 따라 정확하게 실행되지 않으며 일부 매개변수의 민감도가 높지 않은 것으로 확인되었습니다. 여기서 RT는 민감도가 높지 않음을 확인하는 데 사용됩니다. 2. 시스템 현재 제한은 액세스된 인터페이스나 리소스에 해당하는 현재 제한을 호출하지 않습니다. 메서드이지만 통합된 전류 제한 메서드: BlockExceptionHandler를 구현하기만 하면 됩니다. 자세한 내용
이 문서 네 번째 섹션의 섹션 4.2의 소개를 참조하세요.
여기에 이미지 설명을 삽입하세요.
블록 핸들러를 설정하더라도 시스템 전류 제한 방법은 여전히 ​​통합 전류 제한 방법을 사용합니다. 이는 요청이 인터페이스에 진입한 것이 아니라 시스템 수준에서 차단되었기 때문에 이해할 수 있는 일이며, 당연히 현재의 시스템 수준 제한 방법을 채택해야 합니다.
************************************************** * ********** API 소개는 다음과 같습니다******************************** ***************************

   /**
    * 系统限流
    */
   @Bean
   public SystemRule getSystemRule() {
    
    
       SystemRule systemRule = new SystemRule();

       // 平均RT:2ms
       systemRule.setAvgRt(2);

       // 加载规则
       SystemRuleManager.loadRules(Collections.singletonList(systemRule));
       return systemRule;
   }

다른 구성 및 확인과 페이지에는 차이가 없으므로 여기서는 반복하지 않겠습니다.

9. 요약

실제로 이 기사에는 클러스터링, 흐름 제어를 위한 게이트웨이와의 Sentinel 통합, 프로덕션 배포 중 Sentinel 코드 수정 등 아직 작성되지 않은 부분이 여러 개 있습니다. 그런데 이 글은 이미 5만 포인트를 돌파했습니다.더 이상 쓰면 너무 길어져서 횡설수설이 될 것 같습니다.센티넬에 대한 다른 정보는 다른 글로 업데이트하도록 하겠습니다.
Sentinel의 주요 기능은 다운그레이드, 회로 차단기, 흐름 제어, 인증 등을 수행하는 것입니다. 흐름 제어는 실제로 일반 흐름 제어, 핫스팟 데이터 흐름 제어, 시스템 흐름 제어 등으로 나눌 수 있습니다. 가장 중요한 것은 일반적인 흐름 제어가 작성하는 가장 일반적인 응용 프로그램이라는 것입니다. 일반적인 흐름 제어는 QPS와 동시 스레드 수(TPS로 간주할 수 있지만 TPS는 아님)라는 두 가지 전략을 지원하며, 각 전략은 직접, 연관, 링크의 세 가지 흐름 제어 모드를 지원합니다. QPS 시나리오에서 각 흐름 제어 모드는 실패, 예열, 대기열 등 다양한 흐름 제어 효과 편집도 지원합니다. 실제로 Sentinel은 어렵지 않지만 여전히 많은 지식이 있습니다. 공식 문서보다 자세한 안내가 있으니, 문서 활용법을 배워서 지나가시는 모든 학우분들께 도움이 되었으면 좋겠습니다.

Guess you like

Origin blog.csdn.net/m0_46897923/article/details/132796974