[Study] SNS FIFO : MessageGroupId 지정

2025. 10. 9. 21:33·SPRING/TIL

배경

기존에 채점 시스템에서 SNS와 SQS를 활용한 팬아웃(Fan-out) 패턴을 통해 채점 요청을 처리하고 있었다. 초기 아키텍처는 효율적인 비용과 처리량에 중심을 둔 Standard 타입의 SNS와 SQS로 구성했다. Standard는 순서를 보장하지 않는 대신, 높은 처리량을 제공하여 만약 채점 요청이 대량으로 들어올 경우 분산 처리하는데 유리했다. 

 

그러나 먼저 제출한 사람의 채점이 먼저 처리되어야 한다는 요구사항이 있었다. 그래서 SNS와 SQS를 모두 FIFO, 선입 선출 구조로 변경했다. 그러나 이렇게 둘 다 FIFO로 구성할 경우 전체 채점 요청이 단 하나의 파이프라인을 통해 직렬로 처리될 수밖에 없었다. 만약 트래픽이 몰린다면 전체 시스템 처리 속도가 급격히 저하되는 성능 병목 지점이 될 수 있었다.

 

개념 요약

MessageGroupId

그룹 ID는 메시지가 특정 메시지 그룹에 속하도록 지정하는 필수 토큰입니다. SNS FIFO 주제는 구독된 Amazon SQS FIFO 대기열에 그룹 ID를 전달합니다. SNS FIFO 주제 또는 SQS FIFO 대기열의 그룹 ID 수에는 제한이 없습니다. 메시지 그룹 ID는 Amazon SQS 표준 대기열로 전달되지 않습니다.

 

작동 방식

'FIFO 주제에 대한 Amazon SNS 메시지 그룹화' 자료

SNS FIFO로 4개의 메시지(m1, m2, m3, m4)가 가고 있다고 가정해보자. 각 메시지에는 다음과 같이 `MessageGroupId`가 지정되어 있다.

  • product-214: m1, m4
  • product-799: m2, m3

이 메시지들이 SNS FIFO → SQS FIFO → Lambda 파이프라인을 통과하면, 처음에 출발한 (m1, m2, m3, m4) 순서가 유지되지 않는 것을 확인할 수 있다. 

 

그러나 핵심은 (m1, m4) 그룹과 (m2, m3) 그룹의 내부 순서는 유지된다는 것이다. 즉, m1은 무조건 m4보다 먼저, m2는 무조건 m3보다 먼저 처리된다.

 

즉 같은 `MessageGroupId`를 가질 경우 해당 그룹 내에서의 순서는 보장된다. 반면 `MessageGroupId`가 다르면 그룹 간의 순서는 보장되지 않는다.

 

결론적으로, `MessageGroupId는 순서가 중요한 메시지들을 하나의 그룹으로 묶어 데이터 정합성은 보장하면서도, 그룹과 그룹 사이에는 병렬 처리를 통해 높은 처리량을 확보할 수 있게 해준다.

 

각 메시지 그룹은 초당 최대 300개의 메시지를 전송할 수 있다. 따라서 전체 처리량을 높이려면, 여러 개의 MessageGroupId를 사용하는 것이 좋다.

 

코드 예시

private void publishJson(String topicArn, Object payload, String messageGroupId) {
        try {
            String body = objectMapper.writeValueAsString(payload);
            PublishRequest req = PublishRequest.builder()
                    .topicArn(topicArn)
                    .message(body)
                    .messageGroupId(messageGroupId)	// ✅간단하게 지정
                    .build();
            snsClient.publish(req);
            log.info("SNS published. topic={} bytes={}", topicArn, body.length());
        } catch (SnsException e) {
            log.error("SNS publish failed. topic={} status={}", topicArn, e.statusCode(), e);
            throw e;
        } catch (Exception e) {
            log.error("SNS publish failed. topic={}", topicArn, e);
            throw new RuntimeException("SNS publish failed", e);
        }
    }

 

활용

나는 `MessageGroupId`를 문제(problem) ID를 기준으로 지정했다. 같은 문제에 대한 채점 요청은 순서가 엄격하게 유지되어야 하지만, 서로 다른 문제끼리는 순서가 상관없기 때문이다. 이렇게 하면 각 문제가 독립적인 처리 라인을 갖게 되어, 문제 A에 대한 요청이 많아도 문제 B에 대한 요청 처리에 영향을 주지 않는다.

 

회고

FIFO를 사용하면 모든 요청이 직렬화되어 처리 속도가 느려질까 봐 걱정했는데, `MessageGroupId`를 통해 병렬 처리가 가능하도록 최적화할 수 있어 만족스러웠다. 순서 보장과 성능이라는 두 마리 토끼를 잡는 좋은 해결책을 찾은 것 같다.

 

그러나 서비스 초기처럼 전체 문제의 수가 적을 때는 병렬 처리의 이점이 거의 없다. 그리고 특정 문제 하나에만 트래픽이 집중될 경우 결국 해당 `MessageGroupId`가 병목이 될 수 있다. 이 부분은 앞으로 어떻게 개선할 수 있을지 더 고민해야겠다.

 

참고자료

[📜공식 문서 : FIFO 주제에 대한 Amazon SNS 메시지 그룹화]

[📜공식 문서 : SendMessageRequest]

[📡유튜브 : SNS-FIFO 정리 및 활용]

'SPRING > TIL' 카테고리의 다른 글

[Study] @Modifying: 벌크 연산과 영속성 컨텍스트 관리  (5) 2025.09.29
[Troubleshooting] QueryDsl 서브쿼리 limit 1 적용 안 됨  (0) 2025.09.28
'SPRING/TIL' 카테고리의 다른 글
  • [Study] @Modifying: 벌크 연산과 영속성 컨텍스트 관리
  • [Troubleshooting] QueryDsl 서브쿼리 limit 1 적용 안 됨
seo-cherry
seo-cherry
devyeonee911 님의 블로그 입니다.
  • seo-cherry
    Emergency
    seo-cherry
  • 전체
    오늘
    어제
    • 분류 전체보기 (11)
      • SPRING (7)
        • TIL (3)
        • HOW-TO (4)
      • CI-CD (1)
      • REVIEW (3)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
seo-cherry
[Study] SNS FIFO : MessageGroupId 지정
상단으로

티스토리툴바