AWS SQS, Lambda 를 이용하여 쉽게 지연(Delay) 작업 처리하기

김상범
직방 기술 블로그
9 min readNov 8, 2021

--

안녕하세요! 직방 백엔드팀에서 우리집 서비스를 개발하고 있는 김상범입니다.

오늘은 직방 입주민라운지 게시글의 댓글 알림 기능 구현에 AWS SQS, AWS Lambda 를 어떻게 활용 하였는지 간단히 공유하려고 합니다.

입주민라운지는 직방과 제휴된 아파트의 입주민분들께서 게시글-댓글을 통해 커뮤니케이션을 원활히 하실 수 있도록 지원 하는 기능 입니다.

직방 입주민 라운지

입주민 라운지 게시글의 댓글 알림 기능은 게시글에 댓글이 달리면 5분 뒤 해당 댓글을 포함하여 몇 개의 댓글이 달렸는지 직방앱사용자에게 푸쉬 알림하는 기능입니다.

댓글 알림 수신 화면

이런 댓글 알림 기능은 아래의 2가지 조건이 필요했는데

  • 댓글의 정보와 생성된 시간을 알 수 있어야 했고
  • 댓글 생성 5분 뒤 사용자에게 추가로 달린 댓글 수를 푸쉬 알림해야 했습니다.

구현하는 방법을 몇 가지 생각해보았습니다.

  1. 댓글 등록 요청시 마다 서버에서 5분씩 대기 후 알림을 보내는 방법.
  2. 짧은 시간마다 동작하는 Polling/Schedule 프로그램을 작성하거나 댓글 알림만을 위한 전용 프로그램을 작성하여 댓글 기록 정보를 참고하여 알림을 보내는 방법
  3. Message Queue에 댓글 정보를 저장하고 5분 뒤에 알림을 보내는 방법

1번 방법으로 구현 시 댓글이 달릴때마다 불필요한 자원 낭비가 계속 발생하게 되며, 5분간 대기 중 서버에 장애가 발생하게 되면 모든 댓글 알림 데이터가 사라질 가능성이 매우 크며, 서버 성능에 안좋은 영향을 끼치게 됩니다.

2번 방법으로 구현 시 댓글 알림이 없을때도 불필요한 동작을 수행할 것이며, 반대로 댓글 알림이 많을 시엔 사용자에게 댓글이 달린 후 5분 뒤라는 시간에 제대로 알림을 보내지 못할 가능성이 큽니다.

3번 방법으로 구현 시 MQ 의 구축, 운영 비용이 발생이 불가피 합니다만 AWS SQS, Lambda 를 선택하면 MQ 와 서버를 구축할 필요도 없고 간단한 몇 개의 설정과 구현된 함수 배포만으로 안전하고 빠르게 구현할 수 있습니다.

따라서 3번의 방법을 선택하기로 하고 AWS SQS, Lambda 를 이용하여 구현하였습니다.

Amazon Simple Queue Service(SQS)와 Lambda

AWS SQS 는 마이크로 서비스, 분산 시스템 및 서버리스 애플리케이션을 쉽게 분리하고 확장할 수 있도록 지원하는 완전관리형 메시지 대기열 서비스입니다.
이는 처리되길 기다리는 메시지를 저장하는 메시지 대기열에 대한 액세스를 제공합니다.

SQS 는 다음과 같은 기본 아키텍처가 있습니다.

  • 분산 대기열(Distributed queues)
    분산 메시징 시스템에는 세 가지 주요 부분, 즉 분산 시스템의 구성 요소, 대기열 (Amazon SQS 서버에 분산됨), 대기열의 메시지가 있습니다.
시스템에는 여러 Producers(메시지를 Queue로 전송하는 Components), Cosumers(Queue의 메시지를 수신하는 Components)가 있습니다. Queue(메시지 A~E 유지) 은 여러 Amazon SQS 서버에 메시지를 중복 저장합니다.
  • 메시지 수명 주기(Message lifecycle)
    다음은 Queue 메시지의 생성, 처리, 삭제까지의 시나리오 입니다.
Producer (Component 1) 는 메시지 A를 대기열로 전송하고 이 메시지는 Amazon SQS 서버에 중복 분산됩니다.
Consumer(Component 2)는 메시지를 처리할 준비가 되면 Queue에서 메시지를 소비하고 메시지 A가 반환됩니다. 메시지 A는 처리되는 동안 Queue에 그대로 남아 있고 Visibility Timeout 동안 다른 Consumers 에게 반환되지 않습니다.
Consumer(Component 2)는 Queue에서 메시지 A를 삭제하여 Visivility Timeout 시간이 만료되면 이 메시지가 수신되어 다시 처리되지 못하도록 합니다.

또한 SQS 는 위의 기본 수명주기에 맞춰 아래와 같은 Queue 파라미터 설정 기능을 제공하고 있습니다.

SQS Queue 파라미터 설정

  1. Visibility timeout
    한 소비자가 Queue에서 받은 메시지가 다른 메시지 소비자에게 표시되지 않는 시간입니다.
  2. Message retention period
    Amazon SQS 가 Queue에 남아 있는 메시지를 보관하는 시간입니다.
  3. Delivery delay
    Amazon SQS 가 Queue로 추가된 메시지를 전송하기 전에 지연되는 시간입니다.
  4. Maximum message size
    Queue의 최대 메시지 크기입니다.
  5. Receive message wait time
    Queue가 수신 요청을 받은 후 Amazon SQS 에서 메시지를 사용할 수 있을 때까지 대기하는 최대 시간입니다.
  6. Enable content-based deduplication
    Amazon SQS 메시지 본문을 기반으로 중복 제거 ID를 자동으로 생성할 수 있습니다.
  7. Enable high throughput FIFO
    Queue에 있는 메시지에 높은 처리량을 사용하도록 설정하는 데 사용합니다.

위의 설정 중 5 분 지연 후 댓글 알림을 처리할 수 있을 듯한 내용이 있습니다.
바로 Delivery delay 입니다.

AWS SQS Delay Queues

Delivery Delay에 지연될 시간을 설정하면 Producer의 Component가 Queue 에 새 메시지를 추가 한 후 최소 0초에서 최대 15분까지 지연 후에 Consumer가 메시지를 처리하도록 설정할 수 있습니다.

SQS 파라미터 설정 화면

위처럼 생성된 Queue 에 메시지를 추가하면 5 분 지연된 후 SQS 수명 주기처럼 Consumer 가 메시지를 처리할 수 있으며, Visibility Timeout 동안 다른 Consumer 에게 반환되지 않을 것 입니다.

[참고]Amazon SQS Queue 생성, Amazon SQS Queue 편집

메시지를 처리하기 위한 Consumer를 Lambda로 설정

AWS Lambda는 서버를 프로비저닝하거나 관리하지 않고도 코드를 실행할 수 있게 해주는 컴퓨팅 서비스입니다.
고가용성 컴퓨팅 인프라에서 코드를 실행하고 서버와 운영 체제 유지 관리, 용량 프로비저닝 및 자동 조정, 코드 및 보안 패치 배포, 코드 모니터링 및 로깅 등 모든 컴퓨팅 리소스 관리를 수행합니다.

또한 AWS Lamdba 는 소비자(Consumer)로서 SQS Queue의 메시지를 처리할 수 있습니다.

댓글 알림 기능이 구현된 코드를 Lambda 함수로 생성합니다.

[참고]Lambda 함수 생성, Amazon SQS에서 AWS Lambda 사용

자, 이제 SQS에 Consumer 로 Lambda 를 연결해볼까요?

생성한 Lambda 함수를 연결 해줍니다.

이렇게 설정된 SQS, Lambda 는 다음의 구조를 갖습니다.

이제 입주민 라운지 게시글의 댓글 기능은 SQS 기본 생명 주기에 따라서 다음과 같이 진행됩니다.

  1. 메시지 생성
    게시글에 댓글이 달리면 SQS의 Task queue에 댓글 정보 메시지 추가
  2. 메시지 처리
    Queue의 Delivery Delay 설정에 따라 메시지는 5분 지연 뒤 Consumer로 전달되고 Consumer로 설정된 Lambda에서 메시지의 댓글 정보를 이용하여 댓글이 작성된 시간부터 5분 뒤 추가로 작성된 댓글 수를 계산하여 직방앱사용자에게 푸쉬 알림 실행
  3. 메시지 삭제
    작업을 완료한 Consumer 가 queue에서 처리한 메시지 삭제

마치며

지금까지 AWS SQS, Lambda 를 이용하여 쉽게 지연 작업을 처리하는 방법을 살펴보았습니다.
구현할 기능과 상황에 따라 구조의 구성은 달라질 수 있겠지만 적은 비용과 간단한 설정으로 완전관리형 MQ 와 Serverless 애플리케이션을 사용할 수 있어서 정말 손쉽게 구현할 수 있었습니다.
또한 SQS 수명주기의 특성과 Visibility timeout, Lambda timeout을 이용하여 간편한 Failover 도 가능했습니다.

긴 글 읽어주셔서 감사합니다!

참고자료

--

--