더이상 미룰 수 없다 ACC 해커톤 회고록 시작해보겠숩니다.
저는 정규학기를 마치고 인프라와 CI/CD, 아키텍처에 대한 지식의 부족함을 느끼고 교내 AWS Cloud Club에 졸업유예생 신분으로 가입하였습니다. ACC는 만들어진지 1년도 안된 신생동아리로 AWS에서 정식적으로 운영하는 대학생 클라우드 동아리입니다. 1기 모집때는 AWS 정규 동아리임에도 정보가 너무 없어 지원하지 않았는데, 이번 2기 모집에는 1기 결과물의 수준이 상당히 높아 보여 지원해 활동하게 되었습니다.
ACC의 첫 3주는 연합 해커톤과 코어 세션이 동시에 진행되었습니다. 사실 어떠한 활동도 없이 바로 프로젝트에 투입된다는게 많이 부담스럽고, 실제로 부족함도 느꼈지만 적극적이고 뛰어난 팀원들 덕분에 많이 배워가는 시간이었던 것 같습니다. 또 AUSG에서 활동하시는 현직자 멘토님 덕분에 다양한 인사이트를 얻어갈 수 있어서 유익한 시간이었습니다.
주제는 가상 면접 사례로 배우는 대규모 시스템 설계 기초 책에 나오는 주제 중 4가지가 주어졌습니다.
본인은 개인적으로 피드 시스템 구현에 관심이 있었습니다. 실시간성이 중요한 피드 시스템 특성상 레디스를 적극적으로 기용할 수 있을 것 같았고, 좋아요나 팔로우 같은 처리 속도나 순서가 중요하진 않지만 대규모로 들어올 수 있는 트래픽에 대한 고민도 재밌을 것 같았습니다.
다수의 팀원들이 피드 시스템을 1순위로 지망하였고, 실제로도 피드 시스템에 배정 받았습니다!
피드 시스템에 배정 받은 뒤에는 주제를 구체화하고 유저 시나리오를 작성했습니다. 주제는 맛집 추천 피드 시스템으로 결정하였습니다. 선릉역으로 매일 교육을 다니면서 점심거리를 고민할 일이 많아졌고, 이러한 고민을 해결해줄 실시간 맛집 추천 피드 시스템이 있다면 유용할 것 같다 생각했습니다. 기술적으로는 점심 시간이나 저녁 시간에 트래픽이 몰리는 뚜렷한 문제 사항이 주어진다는 것도 매력적이었습니다.
완성된 유저 시나리오는 다음과 같았습니다.


주제를 구체화하고 유저 시나리오가 완성 될 때 즈음, 서비스 요구사항이 구체적으로 추가되었습니다. 사실 1주차가 끝날 때까지 트래픽 규모에 대한 요구사항이 없어 아키텍처 구조를 어떻게 짜야 할지 고민이 많았습니다. 다수의 팀이 이러한 고민을 겪고 있었고, 운영진 측에선 다음과 같이 요구사항을 구체화해 추가 제시하였습니다.


구체적인 요구사항과 구현 방안 제시는 좋았지만, 대규모 피드 시스템이라는 주제에서 1000명의 유저는 턱없이 적은 수치였습니다. 최대 2배 가량의 사용자가 몰린다 해도 2000건이고, 이는 아키텍처면에서 깊은 고민을 하지 않아도 웬만해서 서버가 버틸 수 있는 수치이기 때문입니다. 하지만 개발자로서 주어진 요구사항을 완전 무시하고 진행할 순 없었습니다. 따라서 저희 팀은 일일 평균 이용자를 요구 사항의 10배인 10000명으로 잡았습니다. 오버 엔지니어링을 지양하되 AWS의 여러가지 서비스를 적용할 가치는 있는 수준이라 판단했습니다. (사실 학부생들끼리의 판단이라 틀릴 수도 있습니다 ㅎㅎ.)
해당 영상을 참조하며, 요구사항이 주어지기 전 초기 아키텍처 설계는 다음과 같았습니다.

조금 더 자세한 아키텍처 설명은 최종 설계본에서 하겠습니다. 결론적으론, 멘토님한테 아주 깨졌습니다 🥹 멘토님의 주옥 같은 피드백을 정리해보겠습니다.
대규모 트래픽이라는 가정 하에 NoSQl의 기용은 필수적이라 생각했습니다. key-value 기반의 NoSQL은 복잡한 쿼리와 정규화가 불가능한 대신 높은 처리량과 확장성, 그리고 낮은 지연 시간을 자랑하기 때문에 기능이 적고 트래픽은 높다고 가정한 저희 시스템 설계에 적합하다고 생각했습니다. 가격도 사용량에 비례하기 때문에 RDS에 비해 이득을 볼 수 있다 생각했고요. 메인 DB를 DynamoDB로 선정하고 보조 DB로 RDBMS를 정했죠.
멘토님은 RDBMS 외의 DB를 기용하는 것에 근거가 부족하다고 지적하셨습니다. 분명 대규모 시스템에서 Dynamo DB가 유용하게 사용되고 있는 것은 사실이나, 이는 정말 극한적으로 빠른 처리가 요구되는 상황에서 유리한 것이고 RDB도 충분히 무거운 쿼리도 빠르게 처리할 수 있다 말씀하셨습니다. 또한 이에 대한 경험이 있는 팀원이 없으므로 시간도 결국 돈, 비용적으로 불리한 설계라고 말씀하셨습니다. (시간도 돈이라는 말씀이 크게 와닿았습니다.)
또 DynamoDB는 파티션 키와 정렬 키, 인덱스의 설계가 매우 중요한데, 이에 대한 설계는 치밀하고 꼼꼼하게 이루어져야 한다고 말씀하셨으며, 만약 설계상의 오류가 있거나 확장이 필요한 때가 온다면 다시 키 설계를 해야 하므로 숙련도가 낮은 사람은 사용하기 어렵다고 말씀하셨습니다. DynamoDB는 Join 없이 한 번의 쿼리문으로 바로 데이터를 가져와야 하기 때문에 키와 인덱스 설계가 중요합니다. 잘못된 키 설계는 오히려 성능상 독이 될 수 있습니다. 이에 대해 인지는 하고 있었지만, 열정과 시간 박치기로 해결되지 못할 것은 없다며 간과한 것 같습니다.
결론적으론 비용이었습니다. 아무리 DynamoDB가 비용면에서 유리하다 해도 이미 존재하는 RDS에 추가적으로 DynamoDB를 기용하는 것은 이중 과금이라고 말씀하셨습니다. 이에 대해 팀원끼리 단일 DynamoDB 체제를 고려하기도 하였으나.. 3주만에 DynamoDB를 효율적으로 다루기는 어렵다는 점과 1만명의 규모에서 DynamoDB를 기용했을 때 RDB의 단일 기용과 비교하여 차이가 크지 않다는 점에서 결국 RDBMS와 Redis 로 DB 설계를 수정하였습니다.
대규모 시스템이라는 가정하에 설계한 것이므로 포스팅에 대한 트래픽이 가장 무거울 것이라 생각했습니다. 가장 많은 데이터를 담고 있기도 해서 서버에 부하가 가장 많이 갈 것이라 생각했기 때문입니다. 우선 포스팅보단 좋아요나 팔로우의 요청이 훨씬 많을 것이라는 점을 간과했습니다. 일별 1만명 규모면 서버에 부하가 갈만한 트래픽은 포스팅보단 좋아요나 팔로우에서 더 많이 발생할텐데 말이죠. 또 좋아요나 팔로우는 즉각적인 반영 필요성이 비교적 덜한 반면 포스팅은 동기 처리도 견딜 수 있는 수준의 요구사항이기 때문에 굳이 비동기 처리의 단점을 안고 갈 필요가 없었습니다. 따라서 포스팅은 동기 처리로, 좋아요와 팔로우를 비동기 처리로 변경하였습니다.
Lambda는 서버리스 컴퓨팅 플랫폼으로 서버를 띄우지 않고 간단한 코드를 저렴한 가격에 실행시킬 수 있다는 장점을 가집니다. SQS와의 조합도 좋아 worker로도 자주 사용됩니다. 저희는 비용을 고려하라는 요구 사항에 따라 Lambda를 적극적으로 기용하기로 했습니다.
Lambda는 최대 1000개의 컨테이너를 동시 수용할 수 있습니다. 1000개의 함수까지는 동시 실행이 가능하단 말이죠. 1만명의 규모에서 Lambda 정도면 성능에 영향을 미치지 않으면서 서버 자원을 아끼고 비용도 아낄 수 있다 생각했습니다.
다만 이런 지적이 들어왔습니다.
어차피 EC2를 띄울 것이라면 Lambda를 또 두는 것은 이중 과금 아니냐?
계속해서 이중과금에 대한 지적이 들어왔습니다. 조금 더 람다와 EC2에 대해 조사해보고 결론은 Lambda를 사용하는 것으로 결정 지었습니다. 근거는 다음과 같습니다.
비용상
EC2는 사용 시간과 데이터 양에 비례해 금액이 정산됩니다. 프리티어 기준 매달 750 시간과 1GB의 데이터 송신을 무료로 제공합니다. EC2는 24시간 구동되므로 데이터 양이 크지만 않다면 추가 과금이 발생하진 않을 것입니다.
람다의 비용 정책은 프리티어 기준 100만회당 0.2$가 청구되며 40만 GB-초(GB-seconds)의 실행 시간이 무료로 제공됩니다. 일별 1만명의 사용자라 가정했기 때문에 청구되는 금액은 미미할 것이라 생각됩니다.
비용에서 차이가 없다면 일반적으로 컴파일 언어로 작성되는 람다는 자바 외의 언어로 작성돼야 하므로 추가적인 시간이 소비돼 시간이라는 비용면에서 불리할 수 있습니다. 저희는 다른 언어를 쓰지 않고 자바를 사용한 스프링 어플리케이션을 그대로 람다에 올리기로 하였습니다.
성능상
결론
물론 1만명의 규모에서 성능상의 이점도 그리 크지 않을 것이라 생각되지만 .. 점점 더 규모가 커진다고 가정했을 때 ec2 혼자 모든 트래픽을 처리하는 것은 부담이 될 것이라 생각했고, 람다로 분리하였습니다.
멘토님의 피드백과 팀원과의 상의를 마쳐 결정된 최종 아키텍처입니다.

이것저것 해보고 싶은 신입 개발자의 입장에서 항상 엔지니어링은 과잉되기 마련이고, 저희 팀 역시 그랬습니다. 아키텍처는 더 좋은 서비스를 위한 도구일 뿐, 이에 몰입돼 "좋은 서비스"를 놓쳐선 안됩니다. 좋은 서비스에는 성능 뿐 아니라 비용도 포함되겠죠. 글이 너무 길어져 송정우 멘토님의 명문을 마지막으로 글을 마무리하고, 다음 글에선 해커톤 당일 후기와 아쉬웠던 점, 리팩토링 계획 등에 대해 풀어보겠습니다.
