앱 푸시 알림 서버 개발(1)

수작업의 반복

현재 회사에 들어와서 처음으로 마케팅팀과 프로모션을 준비하게 되었다. 이전에도 설과 추석에 진행해서 팀원들에게 물어보면서 준비할 수 있었다. 그 중에는 약 25만명 대상자에게 앱 푸시 알림을 보내는 것도 있었다. 팀원 중 한 분이 짠 파이썬 스크립트 파일이 있어 매번 앱 푸시를 보내게 되면 그 스크립트를 이용해온 상황이었다. csv 파일을 읽어서 사용자의 광고 수신, 앱 푸신 수신 여부를 확인하고 해당 대상자의 토큰을 FCM API로 보내게 되어 있었다.

9월 프로모션은 처음으로 진행하는거라 혹시나 실수할까봐 걱정이 많았고, 중간에 deep link 부분이 문제가 있어서 시간이 좀 걸렸지만, 마케팅팀의 의도대로 매출도 잘 나왔다. 올해 프로모션은 이렇게 끝인 줄 알았는데 10월이 되어서 또 프로모션을 하게 되었다. 스크립트 파일 자체를 돌리는 건 매우 간단한 일이지만 프로모션이 아니어도 다른 스쿼드에서도 종종 앱 푸시를 보내는 일이 있었고 매번 수동으로 작업을 하고 있었다. 이전부터 관리자 페이지에서 앱 푸시를 할 수 있게 작업할 수 있는 시간을 요청했다고 했지만, 다른 업무에 밀려서 하지 못했다가 이번에 내가 있는 스쿼드에서 맡아서 앱 푸시 알림 서버를 개발하게 되었다.

앱 푸시 알림 서버 개발 시작

앱 푸시 알림 서버도 그간 익숙하게 해온 API 작업이 있긴 하지만 메인은 그게 아니다. 대상자가 많은 앱 푸시 알림을 비동기로 하는 것이 목적이었는데 처음 해보는 거라서 조금은 막막하게 느껴지기도 했다. 개발 요구 사항은 대략적으로 아래와 같다.

1. 알림 발송을 추가할 수 있다
2. 알림 대상자를 여러 타입으로 추가할 수 있다
	1. CSV 파일로 추가(사용자 ID, FCM token 포함 & 1개의 사용자 ID가 1개 이상의 FCM token을 가질 수 있음)
	2. DB에서 대상자 추출(전체 사용자, 혹은 특정 조건에 해당하는 모든 사용자)
3. 전체 개수와 알림 상태별 개수를 알 수 있어야 한다
	1. 상태값(대기, 진행중, 완료, 실패)
4. 대상자 수, 대상 토큰 개수, 실제 발송된 토큰 개수, 실제 발송 대상자 수를 알 수 있어야 한다
	1. 한 명의 사용자 계정으로 1개 이상의 토큰이 등록될 수 있다
	2. 실제 발송된 토큰 개수는 알림 대상 토큰 개수보다 작거나 같다.

먼저 모든 알림 내역의 개수나 상태별 개수는 SQL에서 count 함수를 써야하는데 데이터가 많아질수록 속도가 느려질 것을 우려해 Redis를 그리고 비동기 작업을 위해 RabbitMQ를 사용하기로 했다. 둘 다 공부할 때만 써본터라 새로운 기술을 써보게 돼서 설레었다.

너무 느리다

앱 푸시의 대상자의 범위는 특정 조건의 사용자부터 전체 사용자이며, 그 수는 최소 10만 정도가 될거라고 예상하고 있다. 그러므로 API를 호출하고 서버에서 바로 FCM API를 호출해서 푸시를 보내게 되면 클라이언트에서는 발송이 끝날 때까지 기다려야한다. 클라이언트에서는 앱 푸시 알림을 보낸다고 서버에 요청을 보내고 서버는 바로 응답하고, 앱 푸시는 Consumer에서 하는 것이 처음 설계한 구조였다. 그런데 대상자를 CSV로 등록할 때 응답 시간이 약 1분 정도가 걸렸다. 앱 푸시에 필요한 데이터를 퍼블리싱하고 푸시 알림을 보내지 않는데도 시간이 이렇게 오래 걸리는 이유가 뭘까? 구간을 찾기 위해서 중간 중간 time() 을 찍어서 찾아보았다.

가장 시간이 오래 걸리는 구간은 CSV에서 가져온 user_id를 앱 푸시 발송 대상자로 유효한지 휴면회원, 앱 푸시 수신 여부 등을 DB에서 다시 확인하는 부분이었다. 퍼블리싱을 한 후에, 하나의 컨슈머에서만 앱 푸시를 보내도록 했는데 중간에 하나의 퍼블리셔를 더 두고 시간이 오래 걸리는 DB 조회 작업을 한 후에 다시 퍼블리싱 하는 구조에 대해 고민해보았다. 내 의도대로 하자면 이 방법을 가장 나을 것 같았는데 왠지 모를 불안감에 확신이 들지 않았고 시니어 개발자분과 얘기하면서 이렇게 구조를 바꾸기로 했다.

이미 API단에 구현한 코드를 옮기는 거라서 크게 어려운 부분은 없었다. 코드 중간 중간에 로그를 추가해서 데이터가 잘 들어 오고 있는지, 어떤 작업을 하고 있는지 확인할 수 있도록 하고 테스트를 해보았다. 괜한 불안감이었다. 내가 원하던대로 요청을 보낸 후에 바로 응답이 오고 퍼블리셔가 user_id를 다 확인하고 마지막 컨슈머가 푸시를 보내는 것까지 다 확인이 됐다. 우선은 시간에 대한 고민은 해결되었다.