Spring cloud 의 흐름 제한 방식

빈번 한 인터넷 요청 을 할 때 서 비 스 는 때때로 매우 큰 압력 을 받는다.특히 그런 인터넷 공격 은 불법이다.이런 상황 은 때때로 약간의 제한 이 필요 하 다.예 를 들 어 상대방 의 요 구 를 제한 할 수 있다.이런 제한 은 몇 가지 근거 가 있 을 수 있다.요청 IP,사용자 의 유일한 표지,요청 한 인터페이스 주소 등 이다.
현재 흐름 을 제한 하 는 방식 도 매우 많다.Spring cloud 에서 게 이 트 웨 이 자체 의 흐름 제한 기능 은 redis 를 바탕 으로 한다.이 동시에 아 리 도 한 류 신기 Sentinel 을 기원 했다.오늘 우 리 는 주로 이 두 가 지 를 둘러싸 고 실전 마이크로 서비스의 흐름 제한 체 제 를 둘러싸 고 있다.
먼저 Spring cloud 원생 의 흐름 제한 기능 을 말한다.흐름 제한 은 모든 서비스 에 대해 흐름 제한 을 할 수도 있 고 게 이 트 웨 이 를 통일 적 으로 제한 처리 할 수도 있 기 때문이다.
1.실전 은 Spring cloud Gateway 의 제한 흐름 을 바탕 으로 한다.
pom.xml 도입 의존:

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
    </dependency>
그 기 초 는 redis 를 바탕 으로 하기 때문에:

spring:
  application:
    name: gateway-service
  redis: #redis    
    database: 8
    host: 10.12.15.5
    port: 6379
    password: 123456 #      
    jedis:
      pool:
        max-active: 8
        max-idle: 8
        min-idle: 0
    timeout: 10000ms
다음은 흐름 제한 정책 을 주입 해 야 하 는 bean:

@Primary
  @Bean(value = "ipKeyResolver")
  KeyResolver ipKeyResolver() {
      return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
      //return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
      //return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
  }

 
  @Bean(value = "apiKeyResolver")
  KeyResolver apiKeyResolver() {
    return exchange -> Mono.just(exchange.getRequest().getPath().value());
  }

  
  @Bean(value = "userKeyResolver")
  KeyResolver userKeyResolver() {
    return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("userId"));
  }

ipKeyResolver,apiKeyResolver,userKeyResolver 세 가지 전략 을 도입 하여 주석@Primary 를 이용 하여 사용 되 는 것 을 결정 할 수 있 습 니 다.
bean 을 주입 한 후 설정 에 준비 해 야 합 니 다:

spring:
  application:
    name: gateway-service
  redis: #redis    
    database: 8
    host: 10.12.15.5
    port: 6379
    password: 123456 #      
    jedis:
      pool:
        max-active: 8
        max-idle: 8
        min-idle: 0
    timeout: 10000ms
다음은 흐름 제한 주요 설정 입 니 다:

spring
  cloud:
    gateway:
      routes: #    :     List
      - id: cas-server #    
        uri: lb://cas-server-service #     ,     
        order: -1
        predicates:
        - Path=/cas-server/** #      ,     /ribbon/**   ,    lb:cas-server-service
        filters:
        - StripPrefix=1 #  Path  ,   1    /ribbon

        - name: RequestRateLimiter #  redis Gateway     
          args:
            redis-rate-limiter.replenishRate: 1  #              
            redis-rate-limiter.burstCapacity: 3  #       ,               
            key-resolver: "#{@ipKeyResolver}" #SPEL        bean

      - id: admin-web
        uri: lb://admin-web-service
        order: -1
        predicates:
        - Path=/admin-web/**
        filters:
        - StripPrefix=1

        - name: RequestRateLimiter
          args:
            redis-rate-limiter.replenishRate: 1  #              
            redis-rate-limiter.burstCapacity: 3  #       ,               
            key-resolver: "#{@ipKeyResolver}" #SPEL        bean

여 기 는 기 존의 경로 에 RequestRate Limiter 제한 필 터 를 추가 하 는 것 입 니 다.세 개의 인 자 를 포함 합 니 다.

- name: RequestRateLimiter #  redis Gateway     
          args:
            redis-rate-limiter.replenishRate: 3  #             
            redis-rate-limiter.burstCapacity: 5  #      ,               
            key-resolver: "#{@ipKeyResolver}" #SPEL        bean
  • 그 중에서 replenish Rate 는 초당 처리 요청 수 를 허용 한 다 는 뜻 입 니 다.
  • burstCapacity 는 1 초 안에 처리 할 수 있 는 최대 요청 수 를 표시 합 니 다.
  • key-resolver 여 기 는 요청 IP 제한 을 사용 하여 SPEL 표현 식 으로 대응 하 는 bean
  • 작은 스 크 립 트 를 써 서 테스트 해 보 세 요.
    
    for i in $(seq 1 30000); do echo $(expr $i \\* 3 + 1);curl -i -H "Accept: application/json" -H "Authorization:bearer b064d95b-af3f-4053-a980-377c63ab3413" -X GET http://10.10.15.5:5556/order-service/api/order/getUserInfo;done
    
    for i in $(seq 1 30000); do echo $(expr $i \\* 3 + 1);curl -i -H "Accept: application/json" -H "Authorization:bearer b064d95b-af3f-4053-a980-377c63ab3413" -X GET http://10.10.15.5:5556/admin-web/api/user/getCurrentUser;done
    
    
    위의 두 스 크 립 트 는 각각 두 서비스 에 대해 압력 측정 을 하고 결 과 를 인쇄 합 니 다.
    {"message":{"status":200,"code":0,"message":"success"},"data":"{\"message\":{\"status\":200,\"code\":0,\"message\":\"get user success\"},\"data\":{\"id\":23,\"isAdmin\":1,\"userId\":\"fbb18810-e980-428c-932f-848f3b9e7c84\",\"userType\":\"super_admin\",\"username\":\"admin\",\"realName\":\"super_admin\",\"password\":\"$2a$10$89AqlYKlnsTpNmWcCMvgluRFQ/6MLK1k/nkBpz.Lw6Exh.WMQFH6W\",\"phone\":null,\"email\":null,\"createBy\":\"admin\",\"createTime\":1573119753172,\"updateBy\":\"admin\",\"updateTime\":1573119753172,\"loginTime\":null,\"expireTime\":null,\"remarks\":\"super_admin\",\"delFlag\":0,\"loginType\":null}}"}ex
    테스트 도구 Jmeter 로 같은 초 동안 여러 번 요청 한 후:
    
    HTTP/1.1 429 Too Many Requests
    X-RateLimit-Remaining: 0
    X-RateLimit-Burst-Capacity: 3
    X-RateLimit-Replenish-Rate: 1
    content-length: 0
    
    expr: syntax error
    
    HTTP/1.1 429 Too Many Requests
    X-RateLimit-Remaining: 0
    X-RateLimit-Burst-Capacity: 3
    X-RateLimit-Replenish-Rate: 1
    content-length: 0
    
    expr: syntax error
    
    
    위 에서 볼 수 있 듯 이 실행 후 호출 에 실패 하고 상태 가 429(Too Many Requests)로 변 합 니 다.
    2.아 리 개원 제한 기 기반:Sentinel
    우선 의존 도입:
    
    <!--      sentinel    -->
        <dependency>
              <groupId>com.alibaba.cloud</groupId>
              <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
    
    프로필 application.yaml 파일 에 설정 하려 면 두 개의 설정 을 추가 해 야 합 니 다.
    
    spring:
      application:
        name: admin-web
      cloud:
        kubernetes:
          discovery:
            all-namespaces: true
        sentinel:
          eager: true #  Sentinel       
          transport:
            dashboard: 10.12.15.2:8080 #sentinel Dashboard  
            port: 8719 # sentinel           
            heartbeat-interval-ms: 500 #    
          scg:
            fallback: #scg.fallback sentinel        
              mode: response
              response-status: 455
              response-body:     
    
    그 중에서 이 안 에는 spring.cloud.sentinel.transport.dashboard 가 설정 되 어 있 습 니 다.sentinel 의 Dashboard 주 소 를 설정 합 니 다.또한 spring.cloud.sentinel.transport.port 라 는 포트 설정 은 해당 하 는 기기 에서 Http Server 를 시작 합 니 다.이 서버 는 Sentinel 콘 솔 과 상호작용 을 합 니 다.
    Sentinel 은 기본적으로 모든 HTTP 서비스 에 스 트림 매 립 점 을 제공 합 니 다.위 설정 이 완료 되면 모든 매 립 점 이 자동 으로 완 료 됩 니 다.스 트림 제한 규칙 만 제어 하면 됩 니 다.
    여기 서 우 리 는 주 해 를 통 해 지정 한 인터페이스 함수 에 상한 류 매장 점 을 추가 하고 RestController 를 써 서 인터페이스 함수 에 주 해 를 추가 합 니 다.
    
    @SentinelResource:
    @GetMapping(value = "/getToken")
    @SentinelResource("getToken")
    public Response<Object> getToken(Authentication authentication){
        //Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        authentication.getCredentials();
        OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails)authentication.getDetails();
        String token = details.getTokenValue();
        return Response.ok(200, 0, "get token success", token);
    }
    
    상기 코드 부분 이 완성 되 었 습 니 다.그 다음 에 Sentinel Dashboard 를 설치 하고 Sentinel Dashboard 다운로드 주소:github.com/alibaba/Sentinel/releases.
    다운로드 완료 후 명령 시작:
    
    java -jar sentinel-dashboard-1.6.2.jar
    
    기본 시작 포트 는 8080 입 니 다.IP:8080 에 접근 하면 Sentinel 의 로그 인 인터페이스 를 표시 할 수 있 습 니 다.사용자 이름과 비밀 번 호 는 모두 sentinel 입 니 다.대시 보드 로그 인 에 성공 한 후 인터페이스'/getToken'을 여러 번 방문 하면 대시 보드 에서 해당 데 이 터 를 볼 수 있 습 니 다.여 기 는 표시 되 지 않 습 니 다.다음은 인터페이스의 흐름 제한 기능 을 설정 할 수 있 습 니 다.'+흐름 제어'단 추 를 누 르 면 설정 인터페이스 를 열 고 문턱 값 유형 은 qps 이 며 단기 한도 값 은 5 입 니 다.
    브 라 우 저 반복 요청http://10.10.15.5:5556/admin-web/api/user/getToken 밸브 값 을 초과 하면 다음 과 같은 인터페이스 정보 가 나타 납 니 다.
    Blocked by Sentinel (flow limiting)
    이 때 Sentinel 의 흐름 제한 이 작용 하 는 것 을 볼 수 있 습 니 다.spring.cloud.sentinel.scg.fallback 을 sentinel 의 흐름 제한 후의 응답 설정 으로 추가 할 수 있 고 흐름 제한 이상 정 보 를 사용자 정의 할 수 있 습 니 다.
    
    @GetMapping(value = "/getToken")
    @SentinelResource(value = "getToken", blockHandler = "handleSentinelException", blockHandlerClass = {MySentinelException.class}))
    public Response<Object> getToken(Authentication authentication){
        //Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        authentication.getCredentials();
        OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails)authentication.getDetails();
        String token = details.getTokenValue();
        return Response.ok(200, 0, "get token success", token);
    }
    
    public class MySentinelException {
        public static Response<Object> handleSentinelException(BlockException e) {
            Map<String,Object> map=new HashMap<>();
            logger.info("Oops: " + ex.getClass().getCanonicalName());
            return Response.ok(200, -8, "     @SentinelResource                   ", null);
        }
    }
    주석@SentinelResource 는 다음 과 같은 속성 을 포함 합 니 다:
  • value:자원 이름,필수 항목;
  • entry Type:입구 유형,옵션 가능(기본 값 은 EntryType.OUT);
  • blockHandler:blockHandlerClass 에 대응 하 는 이상 처리 방법 명,매개 변수 유형 과 반환 값 은 원래 방법 과 일치 해 야 합 니 다.
  • blockHandlerClass:사용자 정의 흐름 제한 논리 처리 클래스
  • Sentinel 스 트림 제한 논리 처리 가 완료 되 었 으 나 서비스 가 재 개 될 때마다 이전에 설정 한 스 트림 제한 규칙 이 비 워 집 니 다.메모리 형식의 규칙 대상 이기 때문이다.따라서 다음은 Sentinel 의 한 특성 인 ReadableDataSource 로 파일,데이터베이스 또는 설정 센터 설정 제한 규칙 을 가 져 옵 니 다.현 재 는 Apollo,Nacos,ZK 설정 을 지원 합 니 다.
    먼저 한 가지 흐름 제한 규칙 은 주로 다음 과 같은 몇 가지 요소 로 구성 된다.
  • resource:자원 명,즉 흐름 제한 규칙 의 역할 대상,즉 주석@Sentinel Resource 의 value;
  • count:제한 한도 값;grade:제한 한도 값 형식(QPS 또는 병렬 스 레 드 수);
  • limitApp:흐름 제어 에 대한 호출 소스,default 이면 호출 소스 를 구분 하지 않 습 니 다.
  • strategy:호출 관 계 를 바탕 으로 하 는 흐름 제한 전략;
  • controlBehavior:데이터 제어 효과(직접 거부,대기,등 속기 모드)
  • 뜻 을 이해 하고 다음 파일 을 통 해 설정 합 니 다.
    
    #          
    spring.cloud.sentinel.datasource.ds1.file.file=classpath:flowrule.json
    spring.cloud.sentinel.datasource.ds1.file.data-type=json
    spring.cloud.sentinel.datasource.ds1.file.rule-type=flow
    
    resources 에 새 파일 을 만 듭 니 다.예 를 들 어 flow rule.json 에 스 트림 제한 규칙 을 추가 합 니 다.
    
    [
      {
        "resource": "getToken",
        "count": 1,
        "controlBehavior": 0,
        "grade": 1,
        "limitApp": "default",
        "strategy": 0
      },
      {
        "resource": "resource",
        "count": 1,
        "controlBehavior": 0,
        "grade": 1,
        "limitApp": "default",
        "strategy": 0
      }
    ]
    
    항목 을 다시 시작 합 니 다.다음 로그 설명 이 성공 하 였 습 니 다.
    
    DataSource ds1-sentinel-file-datasource start to loadConfig
    DataSource ds1-sentinel-file-datasource load 2 FlowRule
    
    Nacos 를 설정 으로 스 트림 제한 규칙 을 가 져 오 면 파일 에 다음 과 같은 설정 을 추가 할 수 있 습 니 다.
    
    spring:
      application:
        name: order-service
      cloud:
        nacos:
          config:
            server-addr: 10.10.15.5:8848
          discovery:
            server-addr: 10.10.15.5:8848
        sentinel:
          eager: true
          transport:
            dashboard: 10.10.15.5:8080
          datasource:
            ds1:
              nacos:
                server-addr: 10.10.15.5:8848
                dataId: ${spring.application.name}-flow-rules
                data-type: json
                rule-type: flow
    
    스프링 클 라 우 드 의 흐름 제한 에 관 한 다양한 방식 의 글 을 소개 합 니 다.스프링 클 라 우 드 의 흐름 제한 에 관 한 더 많은 내용 은 예전 의 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 도 많은 응원 부탁드립니다!

    좋은 웹페이지 즐겨찾기