AWS에서 스케줄링 작업을 예약하려면?!

dev-jjun·2023년 8월 17일
0

Server

목록 보기
27/33

서버에서 주기적으로 특정 로직을 수행하거나, 특정 시간에 푸시 예약을 발송하는 기능 등을 구현할 때 Scheduler를 사용한다. 이러한 기능들은 API 호출 또는 사용자의 이벤트 시에 처리하는 것들이 아니므로 모두 비동기적으로 작업이 이루어지는데, 이들 간에 작업이 쌓이거나 앞단에서 이루어지는 API 호출 등의 작업과 동시적으로 이루어져 병렬 수행할 수 있는 크기의 최대치를 넘어가게 되면 서버가 급격히 느려지거나 장애가 발생하게 되는 것이다.

현재는 스프링부트 내에 있는 Spring Scheduler 라이브러리를 사용해 cron으로 예약을 일괄적으로 걸도록 구현된 상태이지만, 이러한 작업을 효율적으로 최적화하기 위해 메시지 큐를 사용할 수도 있다.

Spring Scheduler를 이용할 때는 cron 표현식을 각각의 부모자식 마다 지정해둔 뒤, Trigger로 예약한 작업을 수행하는 방식으로 구현을 했다.

이때 부모와 자식 모두 답변을 완료했다는 특정 조건을 충족했을 떄만 파이어베이스로 알림을 보내는 함수를 호출한다.

다른 스케줄링 작업 외에 푸시알림을 구현한 부분은 SQS 대기열에 메시지를 추가하기 위해 SqsPrducer에서 정의한 produce() 를 호출한다. 그렇다면! 스케줄링 작업 역시 이와 마찬가지로 예약된 시간+특정 조건에 달성하면 produce() 호출과 같이 SQS로 보내주면 되는 것이다.

어차피 SQS에 추가한 이후부터는 다른 푸시 메시지와 동일하게 리스너를 통해 consume하면 되는 것이므로 어떻게 SQS 대기열로 보내느냐가 관건인 것이다.

그렇다면 크게 두 가지로 나눠서 해야할 일을 정리해볼 수 있겠다.

  1. 특정 시간마다 특정 조건을 만족했는지 검사
  2. 검사했다면 SQS 대기열로 푸시
👨‍👩‍👧‍👦 도입가능한 기술 스택
  • AWS Lambda AWS Lambda에 대해 알아보자 서버리스로 트리거할 작업을 정의 → 테이블의 각 필드마다 예약 작업을 처리하는 Lambda 함수를 적용 가능 지난 ‘오늘의 질문 알림’이 푸시된 이후에 부모와 자식 모두 답변을 한 경우, 푸시알림 전송 → but, 이는 ec2와 같이 하나의 서비스를 운영할 수 있는 함수 단위이므로 단순히 일부 기능(부모, 자식이 모두 답변을 했는가?)에 대한 트리거를 위해 람다를 사용하는 건 투머치라고 생각함.
  • AWS EventBridge AWS EventBridge에 대해 알아보자 AWS의 스케줄러 서비스
    • 일정 - cron 표현식으로 지정할 수 있어 가장 기존과 유사하게 구현할 수 있지만, 푸시알림 시간이 부모자식마다 다르므로 각각에 대한 작업 예약을 어떻게 구현할지는 더 알아봐야 함
    • 규칙 - 외부 애플리케이션과의 연동이 단순 API 호출만으로 가능할지 모르겠다!

⇒ 결론적으로 도입 가능한 방식

1. AWS Lambda 함수로 해당 스케줄링+푸시알림 기능 별도의 서비스로 관리

  • ParentchildRepository에서 알림 시간을 읽어와 Lambda로 전송
  • Lambda에서는 계속해서 RDS의 답변여부 필드를 읽으며 체크
  • 예약된 시간이 되었을 때, 조건이 충족되었다면 SQS로 푸시알림 전송
  • SQSListener가 대기열에 있는 메시지를 폴링하여 서버에서 파이어베이스로 전송

2. EventBridge로 SQS 대기열에 메시지를 보내는 작업 스케줄링

  • 전체 Parentchild를 조회하는 것은 서버에서 실행
  • 작업 예약을 위해 이벤트 버스 규칙에 맞게 요청 API 호출

최후의 방법은.. 가장 별로라고 생각되지만 현재 API 서버에 있는 SqsProducer의 역할을 알림서버에도 함께 두는 방식이다. API 서버와 알림 서버의 역할을 명확히 분리해야 하는데, ①스케줄러를 API 서버에 옮기거나 ②SQS 대기열에 추가하는 SqsProducer를 알림 서버로 옮기거나 둘 중 하나를 포기하는 게 최선의 방법인 것 같다. 하지만 이렇게 하면 단순히 파이어베이스에 보내는 작업을 병렬처리 하는 것을 SQS 대기열에 추가하는 것으로 바꾸는 것밖에 안되기 때문에 실질적으로 동시다발적으로 발생하여 부하를 최소화 하고자 했던 본래 스케줄링 작업의 변화는 없는 것이다.

그럼에도 스케줄링 작업을 SQS와 연동하여 처리함으로써 보장되는 장점은 비동기 작업 처리 및 안정성을 확보하면서 시스템의 확장성을 향상시킬 수 있다고 한다..

결론적으로 , 내가 선택한 방식은?

스케줄러 자체가 항상 알림에만 적용되지 않을 수 있다! 즉, 파이어베이스로 푸시 메시지를 보내는 작업 외에는 모두 DB를 조회해서 특정 조건에 대한 검사를 반복적으로 수행하는 것이므로 엄연히 말하자면 API 서버에 두는 것이 더 적절하다고 판단했다


⭐️ 이후 변동사항

→ 비동기로 이루어지는 스케줄링 작업과 일반 API 작업이 같은 쓰레드 풀을 공유함으로써 풀이 꽉 차거나 누수가 발생하는 문제가 빈번히 발생했다.

결국, 멀티모듈과 서버 분리의 이점을 극대화하기 위해서는 스케줄링 작업을 알림서버에 두는 것이 최선이었고 쓰레드 풀을 API 서버와 알림서버 각각에 두고 사용하다보니 훨씬 서버의 부하가 적게 들었다.

현재는 스케줄링 작업을 활성시키기 위한 신호를 API 서버에서 SQS로 보내고, 이 신호를 알림 서버의 Listener가 대기열에서 가져오면 작업을 예약하는 방식으로 구현되어 있다.

profile
서버 개발자를 꿈꾸며 성장하는 쭌입니다 😽

0개의 댓글