Eureka 서버가 있는 Spring Cloud Loadbalancer

소개



저는 Eureka Discovery Service를 활용하는 매우 간단한 애플리케이션을 만들었습니다.

작업을 완료하기 위해 외부 서비스를 사용해야 하는 웹 애플리케이션으로 구성됩니다.

언젠가는 서로 다른 시스템에서 여러 서비스 인스턴스가 실행될 것입니다. 웹 애플리케이션은 Eureka를 사용하여 사용 가능한 서비스 인스턴스를 검색합니다.

아이디어는 높은 부하 상황에 반응하는 애플리케이션을 시뮬레이트하고 특정 제한 내에서 응답 시간을 유지하기 위해 더 많은 서비스를 추가하는 것입니다.

비교적 높은 부하에서 잘 작동하는 버전을 빌드하는 데 어려움을 겪었으므로 저에게 효과가 있었던 솔루션을 설명하겠습니다.

저는 Spring Cloud 2021.0.4와 Spring Boot 2.6.11 버전을 사용하고 있습니다.


.

문제



여러 서비스 인스턴스가 실행 중이고 웹 애플리케이션에서 보낸 요청을 처리할 때 그 중 하나가 종료된 경우 로드 밸런서는 여전히 그에게 요청을 보냈습니다.

따라서 애플리케이션이 요청을 처리할 수 없었고 클라이언트에 오류가 전송되었습니다.



이 그래프는 동시 응용 프로그램의 클라이언트를 시뮬레이션하는 데 사용된 JMeter에 속합니다.

녹색 선은 서비스 인스턴스 중 하나가 종료된 후 클라이언트가 받은 실패한 트랜잭션 수를 나타냅니다.

몇 초 후 로드 밸런서가 사용 가능한 서비스 인스턴스에 다시 요청을 보내기 시작했고 문제가 해결되었습니다.

예상되는 동작



웹 애플리케이션에서 실행 중인 로드밸런서는 사용 가능한 서비스 인스턴스에만 요청을 보내야 합니다. 클라이언트는 서비스 인스턴스가 종료될 때 오류를 수신해서는 안 됩니다.

첫 번째 의도.



실패한 요청이 등록된 기간은 loadbalancer 캐시 TTL(Time to Live) 구성에 해당합니다. 따라서 캐시 새로 고침 시간을 줄이면 상황이 개선됩니다.



#Configuration of web client application.
spring.cloud.loadbalancer.cache.ttl=10s


로드 밸런서 캐시 만료 시간을 줄이는 것은 로드 밸런서가 오래된 캐시가 있는 경우에도 사용할 수 없는 인스턴스에 요청을 보내는 것을 피해야 한다는 사실 때문에 해결 방법인 것 같습니다.

두 번째 의도.



또 다른 가능한 아이디어는 이미 Spring Boot와 통합된 Resilience4j와 같은 이미 재시도 구현 또는 루프를 사용하여 RestTemplate 호출을 재시도 메커니즘으로 둘러싸는 것입니다.

이 접근 방식의 문제점은 로드 밸런서가 싱글톤 구성 요소이며 들어오는 모든 요청과 상태를 공유한다는 것입니다.

밸런서가 라운드 로빈 알고리즘을 사용하는 경우(심지어 문제가 다른 구현에 적용됨) 요청이 사용할 수 없는 인스턴스로 전송될 때 동일한 인스턴스에 대해 두 번째 시도가 반복해서 처리되지 않는다는 보장이 없습니다.

실제로 서비스 인스턴스가 거의 없는 경우 문제를 재현하기가 매우 쉽습니다.



세 번째 의도



Spring Clouddocumentation에 따르면 웹 클라이언트 애플리케이션에 종속성을 추가해야 합니다.



        <dependency>
            <groupId>org.springframework.retry</groupId>
            <artifactId>spring-retry</artifactId>
        </dependency>


존재하는 경우 이 재시도 구현은 Spring Cloud 로드밸런서 구성 요소에서 내부적으로 사용됩니다.

이제 첫 번째 테스트를 다시 실행한 후 서비스 인스턴스가 종료될 때 클라이언트에 오류가 발생하지 않습니다. 그래프에서 볼 수 있듯이 웹 애플리케이션 처리량은 잠시 동안 영향을 받았지만 적어도 클라이언트는 실패한 요청을 받지 않았습니다.



지표에서 알 수 있듯이 loadbalancer는 여전히 사용할 수 없는 인스턴스에 요청을 보내고 있지만 최소한 Spring Retry와 함께 더 정확한 방식으로 ConnectionException을 처리할 수 있습니다.



마지막으로 나에게 더 나은 해결책은 LoadBalancer 캐시를 비활성화하여 최대 재시도 횟수를 3회로 늘리는 것이었습니다.

spring.cloud.loadbalancer.cache.enabled=false
spring.cloud.loadbalancer.retry.max-retries-on-next-service-instance=3


결론



Spring Cloud 로드 밸런서 구현의 복원력을 개선하려면 Spring Retry 종속성을 포함하는 것이 필수입니다.

좋은 웹페이지 즐겨찾기