spring cloud gateway 의 스 트림 제한 편

원본 링크:https://juejin.im/post/5c18fba151882509a76856d3
전재 출처 표시: www. fangzhipeng. com
높 은 병발 시스템 에 서 는 시스템 에서 흐름 을 제한 해 야 한다. 한편 으로 는 대량의 요청 으로 서버 가 과부하 되 어 서 비 스 를 사용 할 수 없 게 하 는 것 을 방지 하기 위해 서 이 고, 다른 한편 으로 는 네트워크 공격 을 방지 하기 위해 서 이다.
흔히 볼 수 있 는 흐름 제한 방식, 예 를 들 어 Hystrix 는 스 레 드 탱크 의 격 리 를 적용 하고 스 레 드 탱크 의 부 하 를 초과 하여 끊 어 지 는 논 리 를 말한다.일반 응용 서버 에서 예 를 들 어 tomcat 용기 도 스 레 드 수 를 제한 하여 병발 을 제어 합 니 다.시간 창의 평균 속 도 를 통 해 트 래 픽 을 조절 하 는 경우 도 있다.흔히 볼 수 있 는 제한 위 도 는 Ip 를 통 해 흐름 을 제한 하고 uri 를 통 해 흐름 을 제한 하 며 사용자 의 방문 빈 도 를 통 해 흐름 을 제한 하 는 것 이다.
일반적으로 흐름 제한 은 모두 게 이 트 웨 이 라 는 층 에서 하 는데 예 를 들 어 Nginx, Openresty, kong, zuul, Spring Cloud Gateway 등 이다.애플 리 케 이 션 층 에서 AOP 라 는 방식 으로 흐름 제한 을 할 수도 있다.
본 고 는 Spring Cloud Gateway 에서 어떻게 제한 흐름 을 실현 하 는 지 상세 하 게 연구한다.
흔 한 흐름 제한 알고리즘
카운터 계산법
계수기 알고리즘 은 계수기 로 제한 흐름 을 실현 하 는 것 이 좀 간단 하고 거 칠 습 니 다. 보통 우 리 는 1 초 동안 통과 할 수 있 는 요청 수 를 제한 합 니 다. 예 를 들 어 제한 흐름 qps 는 100 입 니 다. 알고리즘 의 실현 방향 은 첫 번 째 요청 이 들 어 오 면 시간 을 계산 하 는 것 입 니 다. 이 어 진 1s 에서 요청 할 때마다 1 을 추가 합 니 다. 만약 에 누적 한 숫자 가 100 에 이 르 면...그럼 후속 요청 은 모두 거절 당 할 겁 니 다.1s 가 끝 난 후에 계산 을 0 으로 회복 하고 다시 계산 을 시작 합 니 다.구체 적 인 실현 은 이 럴 수 있다. 매번 서비스 호출 에 대해 Atomic Long \ # increment AndGet () 방법 으로 카운터 에 1 을 추가 하고 최신 값 을 되 돌려 주 며 이 최신 값 과 한도 값 을 비교 할 수 있다.이러한 실현 방식 은 모두 가 알 고 있 는 단점 이 있다 고 믿 습 니 다. 만약 에 제 가 직장 시간 1s 내 10 ms 전에 100 개의 요 구 를 통과 했다 면 그 뒤의 990 ms 는 간절히 요 구 를 거절 할 수 밖 에 없습니다. 우 리 는 이런 현상 을 '갑 작 스 러 운 현상' 이 라 고 부 릅 니 다.
누 통 알고리즘
누 출 통 알고리즘 은 '돌기 현상' 을 없 애기 위해 누 출 통 알고리즘 을 사용 하여 제한 흐름 을 실현 할 수 있 습 니 다. 누 출 통 알고리즘 이라는 이름 은 매우 형상 적 입 니 다. 알고리즘 내부 에 용기 가 있 는데 생활 에 사용 되 는 깔때기 와 비슷 합 니 다. 들 어 오 라 고 요청 할 때 물 을 깔때기 에 부 은 다음 에 하단 의 작은 구멍 에서 느 리 고 고 른 속도 로 흘러 나 오 는 것 과 같 습 니 다.위의 유량 이 아무리 많 더 라 도 아래 에서 흘러 나 오 는 속 도 는 변 하지 않 는 다.서비스 호출 자가 아무리 불안정 하 더 라 도 누 출 통 알고리즘 을 통 해 흐름 을 제한 하고 10 밀리초 에 한 번 씩 요청 을 처리 합 니 다.처리 속도 가 고정 되 어 있 기 때문에 요청 이 들 어 오 는 속 도 는 알 수 없습니다. 갑자기 많은 요청 이 들 어 올 수 있 습 니 다. 미 처 처리 하지 못 한 요청 은 먼저 통 에 넣 습 니 다. 통 이 라면 용량 상한 선 이 있 을 것 입 니 다. 통 이 가득 차 면 새로 들 어 온 요청 은 버 립 니 다.
알고리즘 구현 에 있어 서 요청 을 저장 할 수 있 는 대기 열 을 준비 할 수 있 습 니 다. 또한 하나의 스 레 드 풀 (Scheduled ExecutorService) 을 통 해 정기 적 으로 대기 열 에서 요청 을 가 져 오고 실행 할 수 있 습 니 다. 여러 개의 병행 을 한꺼번에 가 져 올 수 있 습 니 다.
이런 알고리즘 은 사용 한 후에 도 단점 이 존재 한다. 짧 은 시간의 돌발 유량 에 대응 할 수 없다.
영패 통 알고리즘
특정한 의미 에서 볼 때 토 큰 통 알고리즘 은 누 출 통 알고리즘 에 대한 개선 이다. 통 알고리즘 은 호출 을 요청 하 는 속 도 를 제한 할 수 있 고 토 큰 통 알고리즘 은 호출 의 평균 속 도 를 제한 하 는 동시에 어느 정도 의 돌발 호출 도 허용 할 수 있다.토 큰 통 알고리즘 에는 고정된 수량의 토 큰 을 저장 하 는 통 이 존재 합 니 다.알고리즘 에는 일정한 속도 로 통 에 토 큰 을 넣 는 메커니즘 이 존재 합 니 다.호출 을 요청 할 때마다 토 큰 을 먼저 받 아야 합 니 다. 토 큰 을 받 아야 계속 실행 할 수 있 습 니 다. 그렇지 않 으 면 사용 가능 한 토 큰 을 기다 리 거나 직접 거절 할 것 을 선택 하 십시오.토 큰 을 놓 는 동작 은 계속 진행 되 고 있 습 니 다. 만약 에 통 에 있 는 토 큰 수가 상한 에 도달 하면 토 큰 을 버 립 니 다. 그래서 이런 상황 이 존재 합 니 다. 통 에 사용 가능 한 토 큰 이 대량으로 있 습 니 다. 이때 들 어 온 요청 은 바로 토 큰 을 받 아 실행 할 수 있 습 니 다. 예 를 들 어 qps 를 100 으로 설정 하면 스 트림 기 초기 화 완료 1 초 후에 통 에 100 개의 토 큰 이 있 습 니 다.이때 서 비 스 는 아직 완전히 시작 되 지 않 았 고 대외 제공 서 비 스 를 시작 할 때 이 제한 기 는 순간 100 개의 요 구 를 막 을 수 있다.따라서 통 에 영패 가 없 을 때 만 요청 이 기다 리 고 마지막 에는 일정한 속도 로 실행 되 는 셈 이다.
아이디어 구현: 토 큰 을 저장 할 수 있 는 대기 열 을 준비 할 수 있 습 니 다. 또한 하나의 스 레 드 풀 을 통 해 정기 적 으로 토 큰 을 생 성하 여 대기 열 에 넣 을 수 있 습 니 다. 요청 할 때마다 대기 열 에서 토 큰 을 가 져 오고 계속 실행 할 수 있 습 니 다.
스프링 클 라 우 드 게 이 트 웨 이 제한 흐름
Spring Cloud Gateway 에는 필터 필터 가 있 기 때문에 'pre' 유형의 필터 에서 상기 세 가지 필 터 를 자체 적 으로 구현 할 수 있 습 니 다.그러나 스 트림 제한 은 게 이 트 웨 이의 가장 기본 적 인 기능 으로 Spring Cloud Gateway 는 공식 적 으로 RequestRate Limiter Gateway FilterFactory 라 는 종 류 를 제공 하여 Redis 와 lua 스 크 립 트 를 적용 하여 토 큰 통 방식 을 실현 했다.구체 적 인 실현 논 리 는 RequestRate Limiter Gateway FilterFactory 클래스 에서 lua 스 크 립 트 는 다음 그림 과 같은 폴 더 에 있 습 니 다.
구체 적 인 소스 코드 는 여기 서 설명 하지 않 고 독자 가 스스로 볼 수 있 으 며 코드 의 양 이 적 으 며 스프링 클 라 우 드 게 이 트 웨 이에 내 장 된 제한 필터 공장 을 어떻게 사용 하여 제한 흐름 을 실현 하 는 지 사례 로 설명 할 수 있다.
먼저 프로젝트 의 pom 파일 에 gateway 의 시작 의존 과 redis 의 reactive 의존 을 도입 합 니 다. 코드 는 다음 과 같 습 니 다.

 
    org.springframework.cloud
    spring-cloud-starter-gateway



    org.springframework.boot
    spring-boot-starter-data-redis-reactive



프로필 에 다음 설정 을 합 니 다:

server:
  port: 8081
spring:
  cloud:
    gateway:
      routes:
      - id: limit_route
        uri: http://httpbin.org:80/get
        predicates:
        - After=2017-01-20T17:42:47.789-07:00[America/Denver]
        filters:
        - name: RequestRateLimiter
          args:
            key-resolver: '#{@hostAddrKeyResolver}'
            redis-rate-limiter.replenishRate: 1
            redis-rate-limiter.burstCapacity: 3
  application:
    name: gateway-limiter
  redis:
    host: localhost
    port: 6379
    database: 0



위의 설정 파일 에서 지정 한 프로그램의 포트 는 8081 입 니 다. redis 정 보 를 설정 하고 RequestRateLimiter 의 스 트림 제한 필 터 를 설정 합 니 다. 이 필 터 는 세 개의 인 자 를 설정 해 야 합 니 다.
  • burstCapacity, 토 큰 통 총 용량.
  • replenish Rate, 토 큰 통 은 1 초 에 평균 속 도 를 채 웁 니 다.
  • key - resolver, 흐름 을 제한 하 는 키 의 해석 기 에 사용 되 는 Bean 대상 의 이름 입 니 다.SpEL 표현 식 을 사용 하여 \ # {@ beanName} 에 따라 Spring 용기 에서 Bean 대상 을 가 져 옵 니 다.

  • KeyResolver 는 resolve 방법 을 실현 해 야 합 니 다. 예 를 들 어 Hostname 에 따라 흐름 을 제한 하려 면 hostAddress 로 판단 해 야 합 니 다.KeyResolver 를 실현 한 후 에는 이러한 Bean 을 Ioc 용기 에 등록 해 야 합 니 다.
    
    public class HostAddrKeyResolver implements KeyResolver {
    
        @Override
        public Mono resolve(ServerWebExchange exchange) {
            return Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
        }
    
    }
    
     @Bean
        public HostAddrKeyResolver hostAddrKeyResolver() {
            return new HostAddrKeyResolver();
        }
    
    

    uri 에 따라 흐름 을 제한 할 수 있 습 니 다. 이때 KeyResolver 코드 는 다음 과 같 습 니 다.
    
    public class UriKeyResolver  implements KeyResolver {
    
        @Override
        public Mono resolve(ServerWebExchange exchange) {
            return Mono.just(exchange.getRequest().getURI().getPath());
        }
    
    }
    
     @Bean
        public UriKeyResolver uriKeyResolver() {
            return new UriKeyResolver();
        }
    
     
    
    

    사용자 차원 으로 흐름 을 제한 할 수도 있 습 니 다.
    
       @Bean
        KeyResolver userKeyResolver() {
            return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
        }
    
    
    

    jmeter 로 압력 측정 을 하고 10thread 를 설정 하여 순환 요청 lcoalhost: 8081, 순환 간격 1s 를 설정 합 니 다.압력 측정 결과 일부 요청 이 통과 되 었 고 일부 요청 이 실 패 했 습 니 다.redis 클 라 이언 트 를 통 해 redis 에 존재 하 는 key 를 확인 합 니 다.다음 과 같다.
    이 를 통 해 알 수 있 듯 이 RequestRate Limiter 는 Redis 를 사용 하여 흐름 을 제한 하고 redis 에 key 2 개 를 저장 했다.이 두 키 의 의 미 를 주목 하면 lua 소스 코드 를 볼 수 있 습 니 다.
    원본 코드 다운로드
    github.com/forezp/Spri…
    참고 자료
    cloud.spring.io/spring-clou…
    windmt.com/2018/05/09/…
    www.spring4all.com/article/138…
    청소 좀 하고 작가 님 을 지지 해 주세요.
    (본 사이트 의 글 을 옮 겨 실 으 려 면 작가 와 출처 를 밝 혀 주 십시오)

    좋은 웹페이지 즐겨찾기