일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 프리코스
- Docker
- JPA
- Level2
- 스프링부트
- 백준
- JUnit5
- 자바
- MSA
- 우테코
- REDIS
- AWS
- 세션
- Paging
- HTTP
- 미션
- 프로그래머스
- 레벨2
- AOP
- CircuitBreaker
- mock
- 스프링 부트
- 코드리뷰
- 우아한세미나
- Spring Batch
- 의존성
- yml
- 서블릿
- 트랜잭션
- 우아한테크코스
- Today
- Total
늘
[CircuitBreaker] 게이트웨이에서 서킷 브레이커 설정시 주의할점 본문
게이트웨이를 운영하던중 첫 적립 api를 호출했을때 아래의 예외가 터졌다.
java.util.concurrent.TimeoutException: Did not observe any item or terminal signal within 1000ms in 'contextWriteRestoringThreadLocals' (and no fallback has been configured)
게이트웨이 구성은 spring cloud gateway로 구성되어있고 아래 zipkin에서 보면 response-time이 1s가 넘어가자 exception을 던지는 것으로 확인했다.
다만 gateway에서 response-timeout설정을 1s보다 길게 잡아두었는데 1000ms에서 예외가 터지는게 의아했다.
원인 찾기
1. 일반적인 response-timeout으로 예외가 발생하면 아래처럼 예외가 발생해야하는데 예외 내용도 달랐다.
org.springframework.web.server.ResponseStatusException: 504 GATEWAY_TIMEOUT "Response took longer than timeout: PT2S"
2. 해당 예외가 터질때마다 circuitBreaker의 fail count가 올라갔다. 따라서 해당 exception이 circuit breaker에 걸어둔 exception 조건에 맞는 예외일 것이라고 가정했다 실제 circuit breaker를 제거한 상태에서는 아무리 지연되어도 response-timeout내에서는 정상 응답을 받았다.
결과
원인으로는 circuit breaker를 추가하면 timelimiter의 default timeout기간이 1s이다. 따라서 해당 설정이 우선순위가 되어 http-client의 response timeout이 1s보다 길더라도 timelimiter에 걸려서 예외가 발생한 것이다.
public class TimeLimiterConfig implements Serializable {
private static final long serialVersionUID = 2203981592465761602L;
private static final String TIMEOUT_DURATION_MUST_NOT_BE_NULL = "TimeoutDuration must not be null";
private Duration timeoutDuration = Duration.ofSeconds(1L);
private boolean cancelRunningFuture = true;
추후 조치
timelimiter timeout > metadata timeout > httpclient timeout 우선순위이므로 timelimiter의 timeout을 httpclient timeout보다 길게 잡으면
metadata timeout > httpclient timeout > timelimiter timeout순서가 되도록 timelimiter timeout을 httpclient timeout보다 길게 설정하면 좋을 것 같습니다. (circuit을 붙이고 때더라도 spring gateway에서 설정한 timeout을 일정하게 유지하기 위함)
spring:
cloud:
gateway:
httpclient:
connect-timeout: 1000
response-timeout: 1s # 여기서는 1s가능.
routes:
- id: api-server
uri: http://localhost:8081
filters:
- name: CircuitBreaker
args:
name: tmpCircuitBreaker
fallbackUri: forward:/fallback/tmp
metadata:
connect-timeout: 1000
response-timeout: 1000 # 1s로 적으면 1초 넘어도 exception안터짐
resilience4j:
timelimiter:
configs:
default:
timeout-duration: 10s
cancel-running-future: false
추가 사항
timelimiter의 timeout-duration은 slow-call-duration보다 반드시 커야한다. 안그러면 서킷브레이커에 집계되기 전에 timeout예외가 터지기때문이다.
slow-call-duration <= metadata timeout <= httpclient timeout < timelimiter timeout
Reference
https://docs.spring.io/spring-cloud-gateway/docs/3.0.2/reference/html/#route-metadata-configuration
https://medium.com/@im_zero/spring-cloud-gateway-circuit-breaker-time-limiter-5e3c26a62b4c
'백앤드 개발일지 > 웹, 백앤드' 카테고리의 다른 글
Spring Batch 5 와 ??? (3) | 2024.01.08 |
---|---|
[오브젝트] 6장 메시지와 인터페이스 (2) | 2023.12.17 |
rpc(GRPC) vs HTTP (1) | 2023.11.23 |
쿠버네티스 사알짝 맛보기 (0) | 2023.10.23 |
분산 시스템에서 데이터 처리(Queue, CDC, Outbox Pattern...) (0) | 2023.09.23 |