외부 서비스 장애로 인해 응답이 오래 걸린다고 했을 때 외부 API 응답
으로 대기
하는 자원
들이 운영 서버 내부에 쌓이면
서 성능에 악영향
을 줄 수 있습니다. 이를 해결
하기 위한 가장 기본적인 방법은 타임아웃
을 설정하는 것입니다. 크게 타임아웃에는 커넥션 타임아웃과 리드 타임아웃, HTTP 커넥션 풀 타임아웃을 설정해 볼 수 있습니다.
다음과 같이 특정 서비스의 장애가 전체 서비스에 영향을 주는 경우는 어떻게 해결할 수 있을까요? 🤔
이 경우는 벌크헤드 패턴을 적용해 볼 수 있습니다. 벌크헤드 패턴
은 기능의 종류마다 자원 사용
을 분리
하는 것을 의미하는데요. 자원을 격리하여 서비스 일부에 장애가 발생해도 전체로 전파되지 않도록 보장해 주는 패턴입니다. 위 예시에서는 외부 서비스마다 다른 HTTP 커넥션 풀을 사용하도록 벌크헤드 패턴을 적용할 수 있습니다. 서로 다른 커넥션 풀을 사용하기 때문에 A 서비스에 문제가 발생해도 B,C의 영향을 최소화할 수 있습니다.
외부 서비스 장애가 계속 발생하면 어떻게 되나요?
지속되는 외부 서비스 장애로 타임아웃에 의한 서비스 에러가 발생할 수 있습니다. 외부 서비스가 장애가 발생했는데도 불구하고 운영 서버는 계속 요청을 보내게 되니, 불필요하게 응답 시간이 저해되고, 처리량도 감소하게 됩니다. 이 문제를 해결하기 위해서는 서킷 브레이커를 적용할 수 있는데요. 서킷 브레이커
는 오류가 지속되는 경우 일정 시간 동안 기능 실행을 차단할 수 있습니다. 두꺼비집 같은 차단기를 생각하시면 됩니다. 서킷 브레이커가 빠른 실패
를 도와주기 때문에 외부 서비스 장애에 의한 응답 시간 증가
를 예방
할 수 있습니다.
+) 코드로 살짝 보는 장애 조치 적용
- Bulkhead 패턴으로 서비스별 커넥션 풀 분리
@Configuration
public class HttpClientConfig {
@Bean("serviceAHttpClient")
public HttpClient serviceAHttpClient() {
return HttpClient.create()
.pool(ConnectionProvider.fixed("serviceAPool", 50)); // A 서비스 전용 풀
}
@Bean("serviceBHttpClient")
public HttpClient serviceBHttpClient() {
return HttpClient.create()
.pool(ConnectionProvider.fixed("serviceBPool", 30)); // B 서비스 전용 풀
}
}
- 타임아웃 설정
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate() {
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setConnectTimeout(3000); // 커넥션 타임아웃
factory.setReadTimeout(5000); // 리드 타임아웃
return new RestTemplate(factory);
}
}
- Circuit Breaker로 장애 전파 방지
@CircuitBreaker(name = "myService",
failureRateThreshold = 50, // 실패율 임계값
slidingWindowSize = 10) // 집계 단위
public String callService() {
return externalService.call();
}
이렇게 여러 레벨의 대응 방안을 조합하는 것이 더 완성도 있는 해결책이 될 것 같습니다.
참고
'CS > 개발지식' 카테고리의 다른 글
데이터베이스 시스템에서 동시성을 제어하는 방법? (0) | 2024.12.18 |
---|---|
실생활 예시로 이해하는 동기/비동기 & 블로킹/논블로킹 (1) | 2024.12.10 |