Notion에서 보기

 

iOS 푸시 알림 구현하기 세팅편 - AWS SQS, Lambda, Firebase

개요

cabi.oopy.io

개요

이 글은 백엔드의 입장에서 작성되었습니다.

iOS를 이용한 앱의 Java 백엔드를 담당하게 되면서, 앱 내 알림 및 Push 알림 기능 구현을 맡게 되었다. 이를 위해 DB 알림 관리와 Push 알림 전송 관리 구현이 필요했다. 방법들을 찾아보는 도중, AWS의 SQS, Lambda, 그리고 Google의 Firebase를 이용하면 무료로 이 알림들을 구현할 수 있음을 알게 되었다.

iOS 앱의 백엔드 서버로써 DB 알림과 Push 알림을 구현하기 위한 나의 삽질기를 기록하려고 한다.


AWS SQS, Lambda?

**SQS(Simple Queue Service)**는 마이크로서비스, 분산 시스템 및 서버리스 애플리케이션을 위한 완전관리형(알아서 해줌) 메시지 대기열이다.

Lambda는 서버를 프로비저닝 또는 관리하지 않고도 실제로 모든 유형의 애플리케이션 또는 백엔드 서비스에 대한 코드를 실행할 수 있는 이벤트 중심의 서버리스 컴퓨팅 서비스다.

  • TMI - Serverless?**클라우드 제공업체가 서버 인프라에 대한 프로비저닝, 유지 관리, 스케일링 등의 일상적인 작업을 처리**하며, 개발자는 배포를 위해 코드를 컨테이너에 패키징하기만 하면 된다.→ 한 줄 요약 : 편하고, 싸다. - 심지어 AWS Lambda(+ SQS)는 달 100만 건까지 무료다..!
  • 서버리스 애플리케이션은 배포되고 나면 필요에 따라 자동으로 스케일 업되거나 스케일 다운됩니다. 퍼블릭 클라우드 제공업체의 서버리스 오퍼링은 일반적으로 이벤트 기반 실행 모델을 통해 온디맨드로 미터링된다. 그러므로 서버리스 기능이 유휴 상태일 때는 아무런 비용도 들지 않는다.
  • **서버리스(serverless)**란 개발자가 서버를 관리할 필요 없이 애플리케이션을 빌드하고 실행할 수 있도록 하는 클라우드 네이티브 개발 모델이다.

간략한 구조도는 이렇다.

SQS에 원하는 메시지를 전송하면, Lambda에 이 메시지를 Event로 트리거(동작)하고, Lambda는 해당 Event에 대한 처리를 수행한다.


Firebase?

Firebase 는 BaaS(Backend-as-a-Service) 플랫폼으로 제공되는 포괄적인 도구 및 서비스 솔루션으로, 개발자가 모바일 및 웹 애플리케이션을 모두 쉽게 생성, 실행 및 확장할 수 있도록 해준다. 실시간 데이터베이스, 인증, 스토리지, 호스팅 및 기타 기능을 제공하며 모두 단일 플랫폼에서 관리가능하다.

한줄 요약: 백엔드에서 사용되는 여러 기능들을 통합적으로 제공하는 하나의 서비스

FCM?

FCM(Firebase Cloud Messaging)은 이름 그대로 클라우드 기반 메시지를 전송할 수 있는 Firebase의 플랫폼 솔루션이다. 기본적으로 무료이기 때문에, 그리고 여러 가지 기술들에도 적용할 수 있으며 우리의 경우 iOS 앱에서 이용할 수 있어서 선택했다.


굳이 SQS, Lambda를 사용하려는 이유

사실 FCM에 대해서 직접적으로 WAS(Spring Boot)에서 Push 알림을 전송할 수 있지만, 사용자의 증가로 인한 알림 처리의 증가와 이에 따른 서버의 리소스 사용을 고려하고자 했다.

확장적으로 생각했을 때 메시지 큐를 이용하여 별도의 처리 서버로 찢어놓는 것이 부하 분산뿐만아니라 스케일링에 있어서도 좋을 것이라고 생각했다. 따라서, ‘우리 서비스가 커지지 않을까?’라는 희망을 갖고, SQS와 Lambda를 이용해서 구현해보려고 한다.

SQS, Lambda 세팅하기

인스턴스 생성, 설정에 관련해서는 다른 좋은 글들이 많으니 구체적으로 적지는 않겠다. 우선, SQS와 Lambda를 연결해서 Event를 처리하는 작은 서버를 구현해보자.

  • Lambda 인스턴스 생성하기
  • SQS 인스턴스 생성하기
  • Lambda에 SQS에 대한 역할 부여해주기

  • SQS로 Lambda 트리거 등록하기

위의 과정들을 거쳤다면, 여기까지 왔을 것이다. 여기에서 SQS에 메시지를 보내면 해당 데이터가 이벤트로 트리거되어 람다가 처리한다.

이제 FCM을 설정해보러 가자.


FCM 앱 구성하기

FCM(웹페이지)에서 본인이 원하는 방식의 구성(Android, iOS, Web)을 선택하고, 앱 이름을 설정하면 프로젝트가 생성된다.

위 과정을 통해 첫 앱을 생성하였다면, ‘첫 번째 캠페인 만들기’가 활성화된다.

  • 여기서 ‘테스트 메시지 전송’은 iOS의 경우 Device Token이 필요하다. Device Token은 FCM 모듈이 설치되어 있는 앱을 사용하면 사용하는 기기에 대해 식별자처럼 부여해주는 토큰을 의미한다.
  • iOS 앱에 대해 Device Token만 있다면, 바로 push 알림을 전송할 수 있다. 토큰을 받아오는 것은 해당 앱의 프론트엔드의 설정과 조회로 가능하므로, 이 부분에서는 생략한다.위 FCM에 대한 구성을 마쳤다면, 위 그림처럼 준비가 끝난 것이다. 이제, DeviceToken을 가지고 SQS-Lambda를 연결해보자.


Lambda에서 FCM으로 메시지 전송하기

  • 주의사항
  • Lambda를 설정할 때, Node.js의 경우에는 메시징을 위해 사용해야하는 모듈인 firebase-admin의 의존성 용량이 람다가 기본적으로 수용할 수 있는 용량을 넘어가게 되므로, Python을 사용하는 것이 정신건강에 좋다..!

FCM을 사용하기 위해, 다음 의존성을 설치해야한다.

pip3 install firebase-admin

람다 자체에 해당 모듈을 넣고 람다 함수를 작성해도 되지만, Lambda에는 Layer라는 것을 통해 모듈을 Import할 수 있게끔 설정해줄 수 있다.

Lambda Layer에 의존 모듈 추가하기

Lambda의 Layer 혹은 계층에서 추가를하려고 하면, 다음과 같은 창이 나타난다.

Python의 firebase-admin 모듈은 압축하면 꽤나 가벼우므로, ‘.zip 파일 업로드’로도 가능하다. → 주의사항 - firebase-admin 모듈을 위에서 설치했다면, 해당 모듈의 최상위 폴더를 ‘python’이라는 이름으로 변경, 압축하여 업로드해야지 람다가 알아듣는다!

‘호환 아키텍처’는 Lambda의 런타임 환경과 동일하게 한다. - Python의 경우 x86_64에 해당한다.

‘호환 런타임’은 Lambda의 런타임 환경과 동일하게 한다. - 나의 경우 Python 3.7로 설정했다.

이후에 계층을 추가하면 모듈 설정 완료!

FCM에 메시지를 전송하는 Lambda 함수 작성하기

lambda 함수에 들어오는 event를 따로 설정할 수도 있고, 이에 대해서 Test도 가능하다.

FCM에 원하는 Push 알림을 전송하기 위해, 다음과 같은 것들이 필요하다.

  • firebase-admin 모듈(방금 설치함)
  • FCM 앱 config(secret)
    • 받아오는 방법
      파이어베이스 앱 - FCM에 등록한 프로젝트 - 설정 - 서비스 계정 - 새 비공개 키 생성으로 .json 파일로 받아올 수 있다.
  • 메시지를 전송할 기기의 Device Token(프론트에서 줬다고 가정)

이후에, 다음과 같이 작성하면 푸시 알림을 보낼 수 있다!

import firebase_admin as admin
from firebase_admin import credentials
from firebase_admin import messaging

# 어드민 계정 정보를 이용해 firebase-admin을 초기화
cred = credentials.Certificate('diary_admin_config.json')
admin.initialize_app(cred)

# 람다 핸들러
def lambda_handler(event, context):
    parsed_payload = parse_sqs_message(event)
    
    return send_notification(parsed_payload);

# firebase 모듈을 이용한 푸시 알림 message send
def send_notification(payload):
    message = messaging.Message(
        notification=messaging.Notification(
            title=payload['title'],
            body=payload['payload']
        ),
        token=payload['deviceToken']
    )
    print(message)
    return messaging.send(message)
    
# sqs 메시지 파싱
def parse_sqs_message(sqs_message):
    title = sqs_message['Records'][0]['messageAttributes']['title']['stringValue']
    deviceToken = sqs_message['Records'][0]['messageAttributes']['deviceToken']['stringValue']
    payload = sqs_message['Records'][0]['body']
    
    return {"title": title, "payload": payload, "deviceToken": deviceToken}

SQS 메시지(JSON)에 대해 딕셔너리로 변경하는 간단한 파싱을 구현 - 단순 전달하게끔 해놓았다.

‘title’이나 ‘deviceToken’ 같은 경우에는 이 정보를 담은 메시지를 전송하는 백엔드 서버에서 임의로 집어넣은 부분이어서 추가적인 구현이 필요하다(다음 구현편에 내용 있음).


정리

여기까지 구성했다면 우리는 위 구조를 구성한 것이다.

SQS - Lambda - FCM을 이용해서 푸시 알림을 위한 세팅을 해보았다.

꽤 많은 삽질이 생략되었지만, 필요한 부분은 이 정도면 충분한 것 같다. 물론 서비스가 거대해진다면 메시징 기법과 정합성에 대해서 고민을 더 해봐야 할 것 같다.

이제, SQS에 이 메시지를 어떻게 잘 보낼지에 대해 Spring Boot 기반 상세구현을 해보자!

iOS 푸시 알림 구현하기 구현편 - Spring, AWS SQS, Lambda, Firebase


 

복사했습니다!