[AWS] SQS의 사용 구조

SQS는 AWS에서 제공하는 완전관리형 서버리스 큐 서비스다.
매우 저렴하며, 관리가 편리하다는게 장점이다.

동작 구조를 잘 알고 활용한다면 가용성 높고 빠른 성능의 큐 기반 시스템을 구축할 수 있다.
여기서는 기본 형태인 SQS Standard를 위주로만 소개한다.




소비 형태

MQ나 Kafka 같은 큐 시스템들과는 사용 형태가 조금 다르다.
MQ는 대체적으로 메시지를 읽는 순간 증발되는 휘발성이고, Kafka는 만료시간 기반으로 저장은 하되, 오프셋 기반으로 이미 처리한 메시지를 건너뛰거나 한다.

반면 SQS는 조금 특이한데, 특정 consumer가 메시지를 받으면 그건 다른 consumer가 "볼 수 없는" 메시지가 되어서 다른 consumer가 다시 Receive로 읽지 못한다.

SQS에는 읽은 메세지를 자동으로 삭제하거나 하는 기능이 없다.
그래서 메시지를 읽어서 점유한 consumer가 처리를 완료했을때 메시지를 직접 삭제해야한다.

만약 최초로 점유했던 consumer가 제대로 처리를 하지 못하고 특정 시간이 지나면 그 메시지의 "볼 수 없는" 상태가 해제된다. 다른 consumer가 읽어갈 수 있다는 것이다. 이 "볼 수 없는 상태"가 해제되기까지의 제한시간을 visibility timeout이라고 한다.
visibility timeout의 기본 설정은 30초다. 최대 12시간까지도 설정이 가능하다.

설정은 큐 단위에서 설정이 가능하다.




Lambda와의 통합

SQS는 Lambda와의 강력한 통합 기능을 제공한다.
SQS에 메세지가 쌓이면, 그걸 Lambda로 넘겨서 호출하는 것이다.

https://docs.aws.amazon.com/ko_kr/lambda/latest/dg/with-sqs.html
편하긴 한데, 여기에 대해서도 유의할 점이 존재한다.

SQS에서 Lambda를 트리거했을때 Lambda가 오류 없이 종료된다면, 시스템은 자동으로 SQS에서 메세지를 삭제해준다.
반면 Lambda에서 오류가 발생하면 메시지를 삭제하지 않는다. 이 상태에서 visibility timeout이 초과되면 다시 Lambda를 트리거할 것이다.




Dead Letter Queue

SQS는 기본적으로 저장 기간(retention period)이 지나기까지는 실패하더라도 계속해서 재시도를 하면서 읽어올 수 있는 구조를 가지고 있다.
하지만 경우에 따라서는 실패한걸 겸허하게 포기할 줄도 알아야 한다. 지속적으로 실패하는 메세지가 계속 쌓인다면 시스템 전체의 병목이 될 수도 있다.

Dead Letter Queue는 메시지들에 대해서 최대 읽기 제한(Maximum Receive)을 걸어놓고 한계에 도달하면 자동으로 Dead Letter Queue라는 별도의 큐에 옮기는 기능이다.

먼저 Dead Letter용으로 사용할 큐를 따로 만들어줘야 한다.
큐 타입은 동일해야 한다.

그리고 원본 큐로 이동해서, 방금 만든 큐 정보를 넣어준다.

이러면 읽기를 10번 하는 순간 저 Dead Letter 큐로 떠넘기는 것이다.


그러면 Dead Letter 큐에서 바로 읽어서 확인할 수 있다.
여기서 처리하는 시스템을 따로 또 만들든, 그냥 로그용으로 보관만 하든 후처리를 어떻게 할지는 선택사항이다.




Dead Letter Redrive

근데 실패해서 Dead Letter에 쌓인 쓰레기들을 다시 재시도하고 싶을 수도 있다.
Redrive는 그런 상황을 위해서 Dead Letter에 쌓인 메시지를 원본 큐로 다시 집어넣어주는 기능을 말한다.

원본 큐에서 Redrive 옵션을 켜고,

Dead Letter 큐에서 "Start DLQ redrive"를 트리거하면

실제로 다 옮겨져서 원본 큐에서 조회가 된다.

유의할 점은 이렇게 옮겨지는 메세지는 이전의 메세지와 다른 새로운 Copy가 들어가는 셈이란 것이다.
페이로드만 같다.




at least once

SQS의 메시지 시스템은 기본적으로 "최소 한번(at least once)"을 보장하도록 만들어져 있다. 정확히 한번(exactly once)는 보장하지 않는다.
그래서 이걸 쓸거라면 항상 consumer가 메세지를 2번 이상 수신할 수도 있다는 것을 감안하고 시스템을 멱등적으로 설계해야 한다.




순서 보장 없음

SQS는 보낸 순서대로 받는걸 보장하지 않는다.
그걸 원한다면 FIFO 버전을 사용해야 한다.
이건 별도 포스트로 정리해보겠다.




그럼에도 강력한 장점

TPS 제한이 없다. 거의 무한대로 메세지를 때려넣어도 버틴다는 것이고, 확장성이 뛰어나다.

비용도 저렴한 편이다. 제로 베이스에 쓴 만큼만 비용을 과금하는데, 웬만해서는 비용이 별로 안나온다. 1일마다 수십-수백만 단위 요청을 쏴본 적이 있는데, 비용이 수십달러 정도밖에 안나왔던거같다.

Kafka 같은 범용 큐들이 돈을 미친듯이 뜯어간다는걸 생각한다면... 엄격한 순서나 중복성 배제가 필요하지 않다는 전제 하에서는 상당히 합리적인 선택이 될 수 있다.



관련 포스트
https://blog.naver.com/sssang97/222343875937
https://blog.naver.com/sssang97/223017245405


참조
https://docs.aws.amazon.com/ko_kr/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html