대충 히스토리 설명
- consumer에서 이벤트 받아서 처리하는 로직에 써드파티 api를 호출하는 부분이 있는데, 너무 빠르게 호출하는지 자꾸 Throttling Exception 을 뱉는다.
- 근데 이게 초당 요청을 몇으로 제한하라는 이런 가이드가 없어서, 실패시 retry 하는 방향으로 개선을 해보려고 한다
첫번째 시도 - retryTemplate
- batch listen(단건으로 말고 레코드 뭉탱이로 들고오는거)을 하고 있어서 retryTemplate 사용 불가능
- batch records에서 몇번째 record인지 알 수가 없다고 한다.
- 실패
두번째 시도 - SeekToBatchErrorHandler
- 위에서 말했듯이 batch listen을 하고 있어서 여기저기 찾아보다가 스택오버플로보고 시도한 방법이다.
- 최신 버전에서는 deprecated 되었지만 우리가 쓰는 버전에서는 현역이고, 이거 때문에 버전업하는 것 보다는 싸게 먹힐 것 같아서 트라이했다.
- 테스트 해봤더니 최대 retry 횟수와, backoff 설정한대로 동작을 안했다
(offset 이동을 안해서 계속 무한 루프를 돌았음, 그래서 수동 커밋 등등 이상한짓 다해봄) - 실패
세번째 시도 - RetryingErrorHandler
- 이 시도부터 공식 문서를 보기 시작해서 적용한 방법이다 (빨리 볼걸그냥.. 정리도 잘 되어있는데)
- 문서를 보면서 내가 빼먹은 부분이 있는걸 알기 시작했다
- listener에서 BatchListenerFailedException 을 던져줘야하는 것이었다 (어떤 레코드에서 exception이 터졌는지)
- listener에서 BatchListenerFailedException 던지게끔하고 다시 트라이 해봤는데, 내가 원하는대로 동작은 했지만 문제가 있었다.
- batch listen한 records중에서 하나가 에러를 던져서 최대 retry 횟수를 뚫으면 해당 메시지가 속한 records 전체가 유실되는 문제가 있었다.
- 이게 말로하면 좀 복잡해서 대충 예를 들어보면
- 1,2,3,4 메시지를 수신했다고 치자, 1번 메시지에서 최대 retry 횟수를 뚫으면 1~4이 전체 유실되는 동작을 했다.
- 실패
네번째 시도 - RecoveringErrorHandler
- 위에 핸들러와 어떤 차이점이 있냐면
- 1,2,3,4 메시지를 수신했다고 치자, 1번 메시지에서 최대 retry 횟수를 뚫으면 1은 유실되고, 나머지 메시지들이 다음 batch records 포함되서 동작했다. (원하는 동작!)
- 근데 지금 우리가 받는 메시지 payload 특성상 에러터진 로직만 돌리는게 아니라, 전체 로직을 돌려야해서 일단 실패…(?)
- 특정 exception을 제외하고 retry를 할 수 있게할 수 있었는데 (addNotRetryableExceptions) 그 반대는 없어서 음…
다섯번째 시도 - @Retryable
- 프레임워크에서 제공해주는 어노테이션이다.
- exponential backoff + 특정 exception에서 retry를 잘 동작했다 허허
- 성공
- 나중에 DLQ 도입할때 RecoveringErrorHandler 요거 적용하기로 했다
참고한 문서
https://docs.spring.io/spring-kafka/docs/2.6.2/reference/html/#annotation-error-handling
'Kafka' 카테고리의 다른 글
[spring kafka] group id 관련 삽질 (0) | 2023.03.05 |
---|---|
[spring kafka] consumer @KafkaListener로 처리되는 스레드 이름 지정 (0) | 2022.12.13 |