Situation
제가 다니던 오믈렛이라는 회사에서 프런트엔드 개발자가 부재한 상황 속에서 새로운 Next.js 프로젝트를 진행하여야했습니다. 저희는 물류 최적화 알고리즘을 서빙하는 모델을 API화 해야했으나, 이 과정에서 API 인증 키 발급, API 사용량 측정 등을 백엔드로 구현해야했습니다. 또한 이것을 보여주기 위한 프런트엔드가 필요하였습니다.
프런트엔드 결과물은 다음 사이트에서 만나볼 수 있습니다.
Task
•
API 인증 키 발급 & API 사용량 측정 백엔드 구현
•
프런트엔드 개발 및 배포
Action
API 사용량을 측정해야했기에, 많은 양의 API 로그가 쌓이는 것을 효과적으로 다뤄야한다고 생각하였습니다. 특히 시간 구간을 변경하면서 확인가능하여야 하고, 몇 개월 간의 통계도 다룰 수 있으면 좋을 것 같았습니다.
데이터베이스가 가장 병목일 거 같아서 1) No-SQL 2) 일반 RDB 3) DynamoDB 4) Loki 중에 선택을 하면 좋을 거 같았습니다.
우선 NoSQL과 RDB에 관한 성능 비교는 다음 글을 참고했습니다.
전반적으로 결과는 Read는 No-SQL이 더 빠르고 단건 update, delete는 RDB가 더 빠른 것 같았습니다.
이번 Task는 Update, Delete가 없기에 RDB는 자동으로 탈락하였습니다.
DynamoDB는 읽기와 쓰기에서 빠른 응답 속도를 제공하는 것으로 기억합니다. 이전 회사에서도 영상 시청 기록을 DynamoDB에 쌓아놓고 이를 Scheduler를 통해 Batch로 로그를 가져와서 쓰고 있었습니다. 가격적인 면에서 쓰기에서 100만건당 USD 0.68, 읽기에서 USD 0.1355 달러 정도였습니다. 반면 MongoDB는 AWS EC2에서 띄울 수 있었고, 무엇보다 MongoDB 전용으로 제공해주는 Credit이 있었습니다. Storage의 경우 월별 25기가 이상은 GB당 0.27달러를 내야했습니다. MongoDB의 경우 MongoDB Atlas로 서빙하면 M20 기준으로 시간당 0.2 달러를 내야합니다. 달에는 약 144달러 정도 나갈 거 같습니다.
마지막으로 Loki 기반은 TSDB로 시계열 데이터를 저장하고 조회할 수 있다는 점에서 이번 Task에 가장 적합해보였습니다. AWS EC2로 모든 것을 구축할 수도 있고 Grafana Labs에서 제공하는 것도 할 수 있었습니다. Advanced로는 299 달러를 쓸 수 있는데, Log, Trace, Profile에 대해서 100기가를 사용할 수 있었습니다.
요약하면 다음과 같습니다.
MongoDB | DynamoDB | Loki | |
비용 | 144$ (20GB) /
약 6개월간 무료 | 100만건당 읽기 쓰기 0.6$ 미만 | 월 100GB, 30일간 retention |
시간대별 조회 | 하 | 중 | 상 |
다양한 쿼리 성능 | 상 | 중 | 하 |
개발 난이도 | 하 | 중 | 상 |
따라서
중간 규모의 트래픽과 비교적 단순한 쿼리 요건에서는 DynamoDB가 적합할 수 있습니다. 트래픽이 급증할 때 자동으로 확장된다는 점에서는 관리가 필요하지 않기 때문입니다. 하지만 복잡한 통계 작업이 많다면 별도로 스케쥴러를 만들어서 배치로 RDB에 쌓아줘야할 것입니다.
꽤 다양한 쿼리가 가능해야하고 당장에 큰 트래픽이 필요 없다면 MongoDB를 적합할 것 같습니다. 단순히 API 사용량을 누적만 하면 되는 것이 아니라 API 키 발급 및 가입/인증 등의 비즈니스 로직도 추가해야하기 때문입니다.
로그 데이터의 장기 보관이 중요하고, 구축/운영에 자신이 있는 경우 Loki가 좋을 것 같습니다. 실제로 성능 자체는 TSDB이기 때문에 가장 적합하지만 간단한 비즈니스 로직은 전혀 못하기 때문입니다. 이에 더해 운영 복잡성과 초기 설정의 어려움도 있습니다.
결정적으로 라우팅 엔진이라는 특성 상 기사 분들이 하루에 한 번 정도 API를 호출한다고 합니다. 고객이 많아지거나, 호출하는 알고리즘 API가 다양해지는 경우에는 저렇게 분화하는 것을 고려해야하지만 현재 단계에서 한 부분에 특화되어있는 기술을 선택하는 것은 오버 스펙이 될 수 있습니다.
개인적으로 성장하는 측면에서 Loki를 선택하고 싶었지만, 회사의 크기/운영의 어려움을 고려했을 때 MongoDB를 선택하는 것이 가장 합당해보였습니다. 특히 짧은 시간 안에 회원가입/인증 등의 비즈니스 로직도 함께 개발해야하는 입장에서 범용적으로 쓸 수 있는 MongoDB가 가장 적합하다고 느껴 MongoDB를 선택하게 되었습니다.
하지만 이를 계기로 주어진 상황에서 적합한 DB를 비교하면서 선택하는 경험을 할 수 있었으며, 서비스가 커짐에 따라 이에 특화되어있는 인프라를 운영하는 것이 더 효과적임을 깨달을 수 있었습니다.
프런트엔드의 경우, vercel의 v0를 이용한 개발을 진행하였습니다. 제가 디자인을 할 줄 모르기 때문에 프런트엔드 개발을 v0를 통해서 진행하였습니다. API 연동은 다른 인턴 분께서 오셔서 수월하게 작업할 수 있었으나, 페이지를 코드로 구현하는 것은 정말 많이 발전함을 느낄 수 있었습니다.
이후에는 Next.js 배포를 진행하였습니다. 리액트라면 빌드 후, S3에 배포하고 Cloudfront 연결 하였을 것 같으나 그렇게 하지 못했습니다. Next.js는 서버사이드 렌더링이기에 코드 또한 해당 컴포넌트를 많이 사용하게끔 짜여져있었습니다. 실제로 정적으로 배포하고자 하였으나, 특정 기능이 동작하지 않아서 다른 방법을 모색하였습니다. 크게는 EC2, vercel, Lambda를 생각하고 있었습니다.
EC2의 경우가 가장 간편하긴 하겠지만, 프런트엔드 페이지인만큼 성능이 호스트 머신에 묶여버리는 문제를 피하고 수평확장이 용이하면 좋겠다는 지점에서 탈락이 되었습니다. 부가적으로는 GPU로 대부분의 크레딧을 소진하고 있었던 터라, 조금이라도 비용을 아껴보자는 마음으로 다른 방식을 선택하게 되었습니다.
Vercel 도 괜찮은 선택지였습니다. 다만 인프라 관리가 AWS가 아닌 Vercel에 묶인다는 점에서 디메리트가 있었습니다. 이에 생각이 미친 것이 lambda로 배포를 하자였습니다. Nest.js처럼 Node.js 기반의 웹 앱도 통째로 lambda에 올려서 서빙할 수 있었기 때문입니다. 기본적으로 Nest도 bootstrap 파일에서 모든 것이 시작하는데, 이 함수를 lambda의 시작점으로 wrapping 해주면 되었습니다.
이 과정을 serverless 라는 프레임워크가 해주었습니다. 하지만 serverless 프레임워크가 next.js 플러그인이 더 이상 관리되지 않았습니다.
대안으로 SST라는 프레임워크가 있었고, 이 프레임워크는 lambda에 배포를 지원하기에 적합하다고 생각했으나 serverless처럼 프레임워크에 의존한다는 점이 마음에 들지 않아서 바로 lambda를 쓸 수 있으면 어떨까로 찾아보았습니다.
이 과정에서 lambda에서 도커 이미지 배포를 지원한다는 사실을 알게 되어 Next.js를 도커로 빌드하여 배포하였습니다. Next.js의 with-docker 파일을 참고하였으며, 다양한 웹서버를 lambda로 띄울 수 있게 도와주는 aws-lambda-web-adapter 를 사용하였습니다.
또한 Route53을 통해 헬스 체크 기능을 추가하였습니다. 람다의 경우 5분에 한 번 요청이 들어오면 재사용하는 것으로 알아서, Route53을 통한 헬스체크를 10초로 해놓으면 항상 warm 상태로 유지할 수 있었습니다.
Reflection
백엔드 개발에서는 Python Django 기반으로 회원가입/인증을 구현해볼 수 있었습니다. 뿐만 아니라 API 사용량 조회라는 상황에서 다양한 선택지를 가격,성능,다양한 기능 측면에서 비교해보고 검토해볼 수 있었습니다.
프런트엔드 개발에서는 Next.js를 도커로 빌드하여 lambda로 배포해보는 경험을 가질 수 있게 되었습니다. 뿐만 아니라, 이전 회사에서 serverless로 이미 세팅되어있던 lambda 운영을 직접 구축해볼 수 있게 되었으며 이 과정에서 lamda cold-start를 해결하기 위한 방법도 알게 되었습니다.
다만 속도가 작은 회사인만큼 개발 속도감 또한 선택에 있어서 중요한 요소임을 느꼈습니다. 특히 크기가 작은 회사이거나 현재 프로젝트 진행이 데모 단계라면 이런 저런 선택지를 비교하기보다 가능할 것 같은 방식으로 일단 빠르게 개발에 들어가는 것도 좋을 것 같습니다.
백엔드 개발부터 프런트엔드 디자인 배포까지 약 한 달 정도가 걸렸는데, 파트타임으로 진행했다고는 하지만 단축을 한다면 2주 정도면 할 수 있는 양이었지 않나 싶습니다.