들어가기
지난번 포스팅에선 스프링의 힘을 빌려 @Async로 API Latency를 개선했습니다.
하지만 비동기 처리 중 네트워크 문제나 AWS의 문제로 S3 폴더 이동에 제약이 생겨 실패한다면 식별,복구하기가 매우 어렵습니다.
안전한 비동기 처리를 위한 방법들을 알아보겠습니다.
Redis Pub/Sub
Redis의 Pub/Sub은 Publisher가 Channel(Topic)에 이벤트를 발생시키면 Channel을 구독하던 Subscriber(Consumer)가 이벤트를 받아 처리하는 구조입니다.
현재 프로젝트에 대입해보자면
1. 사용자의 게시글 등록 요청
2. 이미지 정보 DB에 저장
3. S3 tmp 폴더에서 original폴더로 이동시키는 이벤트 발행
4. 사용자에게 성공 응답
5. Subscriber가 이벤트를 받아 처리 (비동기)
구조는 잘 맞아 보입니다.
하지만 Redis의 Pub/Sub은 메세지 전달을 보장하지 않습니다. Subscriber쪽이 구독을 하지 않거나 구독을 했지만 내부 문제로 이벤트를 수신하지 못하면 해당 이벤트는 다시 수신할 수 없습니다.
이러한 이유로 Pub/Sub구조는 현 구조에 부적합하다 판단했습니다.
Redis Stream
Redis Stream은 Pub/Sub과는 달리 메세지를 보관합니다.
또한 소비자 그룹을 형성해 특정 소비자 그룹이 이벤트를 소비할 수 있습니다.
Stream은 Pub/Sub보다 안정적이며 여러 소비자가 존재할 경우 디테일한 핸들링이 가능합니다.
하지만 S3 폴더 이동 이벤트를 발행하고 소비하는 1:1구조에서 Stream을 쓰는 것은 과하다고 판단했습니다.
Redis List
Redis의 List는 링크드리스트이며 Queue형태로 사용이 가능합니다.
Stream보다 제공하는 기능은 확실히 적지만 이벤트를 저장하고 소비할 수 있는 큐가 있다는 것이 적절하다 생각했습니다.
흐름은 아래와 같습니다.
1. 사용자의 게시글 등록 요청
2. 이미지 정보 DB에 저장
3. S3 tmp 폴더에서 original폴더로 이동시키는 이벤트를 Redis List에 Push
4. 사용자에게 성공 응답
Redis List에 저장된 이벤트들은 스프링 스케줄러를 이용해 주기적으로 처리해줍니다.
1초에 한 번씩 Redis List(messageQueue)에 접근하고 이미지를 이동시켜줍니다.
만약 작업 도중 여러 원인으로 예외가 발생하면 DeadLetterQueue(이하 DLQ)에 저장하게 됩니다.
DLQ는 2초에 한 번씩 실패한 작업이 있는지 확인하고 다시 원래의 작업 큐에 적재해 재시도하게됩니다.
재시도를 거치더라도 계속되는 실패 혹은 네트워크나 S3서버에 중대한 문제가 생겨 DLQ에 과다하게 이벤트가 쌓인다면
개발자가 직접 확인할 수 있도록 Admin이메일로 통지를 보내게됩니다.
'Spring' 카테고리의 다른 글
위치기반 서비스 데이터베이스 선택 [PostgreSQL GIS] (0) | 2024.07.13 |
---|---|
위치기반 서비스 데이터베이스 선택 [MySQL] (0) | 2024.07.12 |
적정 스레드 풀 크기를 고민해보자 (0) | 2024.06.19 |
게시글과 이미지 등록 API 분리로 API Latency 개선기 (2) (0) | 2024.06.19 |
게시글과 이미지 등록 API 분리로 API Latency 개선기 (1) (0) | 2024.06.19 |