이전 글에서는 요리하기 전에 재료를 파악했다고 생각하면 된다.
이제 이 재료들로 요리를 어떻게 만들고, 무엇을 고려해야 하는지 알아보자.
사실 Lambda에 대해서는 별로 언급할 점이 없다.
Lambda가 작동하고 최대 15분까지 리소스가 유지될 수 있다는 점만 제외하면 크게 주의할 점은 없다.
그러니 처리하는데 시간이 오래 걸린다거나, 연결을 계속 유지해야 하는 작업은 Lambda를 사용하기 적합하지 않다.
이벤트 기반 뭐시기를 구현하려면, 작은 단위의 구조는 대충 이렇다.
이벤트(메시지) 생성자 > 메시지 브로커 > 이벤트 소비자
그런데 이렇게 구성하면 문제가 하나 생긴다. 바로 메시지 유실 가능성이다.
(아래에서는 SQS에서 표준 대기열을 선택할 경우를 가정한다.)
(FIFO 대기열은 순차성이 필수가 아닌 이상 굳이 사용하지 않는다)
생성자는 브로커로 던져놓고 나몰라라 할텐데, 만에 하나 브로커가 메시지를 받지 못했다면?
SQS에는 재전송 관련 기능(Dead Letter Queue, DLQ)은 있어도, 재수신 기능은 없다.
(애초에 재수신 같은 기능을 어떻게 만드겠냐만)
그래서 SQS의 메시지 유실 가능성을 방지하기 위해 AWS SNS(Simple Notification Service)를 도입한다.
여기서 나올 수 있는 의문점이 뭐가 있을까?
1. SNS나 SQS나 역할은 비슷한거 아닌가?
얼핏 보면 둘 다 메시지를 받아 전달하는 역할이라 똑같게 보일 수 있다. 하지만 위에서 말했듯 SNS의 추가는 이벤트 유실 방지를 위한 것이다. 이벤트 기반 구조에서 이벤트가 유실된다는 것은 굉장히 큰 문제다. 사용자의 서비스 사용에 큰 영향을 미치는 요소인 만큼, 역할이 비슷하니 굳이 쓸 필요 있느냐는 의문은 적절하지 않다. 물론 작동하든 말든 유실되든 말든 별 상관 없는 기능이고, 비용 감축이 더 중요하다면 상관 없겠다.
(규모가 무지막지하지 않는 이상 비용이 그리 많이 나오지도 않는데...)
2. SNS가 어떻게 이벤트 유실을 방지하는가?
처음 언급한 생성자 > SQS > 소비자 과정에서 유실이 발생하는 부분은 생성자 > SQS 부분이다. SQS > 소비자 부분은 SQS에서 DLQ 등의 기능을 도입해서 방지가 가능하다.
생성자 > SQS 부분에서 발생할 수 있는 유실 가능성을 SNS를 끼워넣고 SNS의 DLQ/재전송 등의 기능을 사용해 전달을 보장하게 만드는 것이다.
그럼 SNS가 생성자에게 받아오는 과정에서 문제가 생기면 어쩌냐?
-> 방법이 없다. 생성자 > SNS 과정은 동기식으로 이루어지는데, SNS로부터 메시지를 잘 수신했다는 ACK를 받으면 넘어가고, 받지 못하면 재시도한다.
까놓고 말하면 SNS가 이벤트 유실에 대해 기상천외한 역할을 하는 것이 아니다.
SNS의 도입은 Fan - out 구조를 위한 것이다.
(그리고 SQS - Lambda 구조에 SNS가 들어가는 것이 아니라, SNS - Lambda 구조에 SQS를 도입한다는 표현이 더 맞는 것 같다)
※ 2022.09.01 수정
SNS를 끼워 넣는다고 해서 이벤트 유실을 100% 방지할 수 있는 것은 아니다. 생성자에서 SNS/SQS로 가는 부분이 동기식이던 비동기식이던 유실 생기면 답이 없는 것은 똑같다.
결국 답은 애플리케이션(코드) 레벨에서 재시도 로직을 구현하는 방법밖에 없다.
SNS/SQS API 호출의 response를 확인하고 유실이나 에러가 발생했을 때 사용자에게 다시 시도하도록 해야 한다.
3. 유실 방지도 중요하긴 한데, SNS를 추가해서 얻는 다른 이점이 있나?
SNS는 Topic 기능이 있다. 생성자 > SQS > 소비자 프로세스로 전달되는 이벤트 처리를 이거 하나로 끝낼 것이 아니라면 하나의 이벤트를 여러 대상에게 전달하는 기능이 필요하다.
예시) 음식 주문을 하는 기능이라고 가정해보자.
생산자 > SQS > 소비자 구조에서는 그냥 이 프로세스로 끝이다.
생산자 > SNS > SQS > 소비자 구조에서는 주문이 입력되면 SNS가 여러 SQS로 메시지를 보낼 수 있다.
주문 처리를 위한 큐, 주문 데이터 수집을 위한 큐, 주문 데이터 분석을 위한 큐 등 여러 목적을 가진 큐에 이벤트를 전송할 수 있다. 데이터를 그냥 날릴 생각이 아니라면 절실히 필요한 구조다.
그냥 큐 방식에서는 메시지를 뽑아가면 삭제된다.
단순하게 생각하면 당연한 것이다. 큐 대기열에 있는 것을 뽑아갔으니 없어지겠지.
하지만 Topic 방식은 Pub/Sub 구조다. Publish되면 생산자는 다른 곳에서 데이터를 얼마나 가져가든 신경쓰지 않는다.
위와 같은 기능/구조를 한 번에 제공하는 것이 Kinesis인데, 이건 대규모 데이터 처리를 위한 서비스니까 일단 제쳐두자.
※ 그냥 소비자만 이벤트를 받아서 다른 기능들까지 한 번에 처리하거나, 다른 기능을 처리하는 리소스에게 전달하면 안되나? 라고 생각할 수 있는데, 애초에 왜 이러고 있는지를 생각하자. 기능별 디커플링과 리소스 간 느슨한 결합을 위해 이러고 있는데, 한 번에 구성하면 말짱 꽝이다. 하나만 잘못되도 동시다발로 장애가 발생할 것이다.
추가로, SQS 표준 대기열은 중복 수신 가능성이 있다(같은 메시지를 2번 이상 수신하는 것).
이 문제는 애플리케이션에서 해결하는 것을 권장한다.
참고 자료
3편은 정리할게 더 생기면...
'AWS' 카테고리의 다른 글
MongoDB with AWS Marketplace (0) | 2022.07.11 |
---|---|
Root 계정 로그인 시 이메일이 오게 하기 (0) | 2022.06.22 |
Lambda, SQS, SNS (1) (0) | 2022.06.14 |
RDS 스냅샷 복구 관련 테스트 (0) | 2022.06.02 |
AWS 시작 후 체크리스트(220525) (0) | 2022.05.25 |
댓글