천만 사용자 아키텍처에 대해 아마 여러분도 한번쯤은 보셨을 것 같은데요. AWS에서 가장 유명하고 오래된 콘텐츠 중에 하나입니다. 지금으로 부터 10년전인 2013년에 처음 소개된 이 방법론은 고전적인 애플리케이션에서 한 명의 사용자 부터 백, 만, 십만, 백만, 천만 사용자에 이르기까지 인터넷 스케일 서비스의 가용성을 확보하는 방법을 알려주었습니다. 제 블로그에서도 천만 사용자를 위한 클라우드 아키텍처, 5년간의 여정 이라는 주제로 소개해 드린 적 있습니다

이것은 당시 천만 사용자 아키텍처입니다. 하나의 가상 서버에서 부터 로드밸런싱, 오토스케일링, 콘텐츠 캐싱, 데이터베이스 선택 방법까지 다양한 분산 아키텍처 기법들을 포함하고 있구요. 이를 위해 어떤 AWS 서비스를 사용해야 하는지 설명하고 있습니다. 추억의 옛날 AWS 서비스 아이콘들이 보이네요.
서버리스 기반 천만 사용자 아키텍처를 아십니까?
그런데 10년이 지난 지금은 우리가 애플리케이션을 만드는 방법도 많이 달라졌습니다. 과거에는 온프레미스 기반 데이터 센터에서 물리적 서버에 MVC 프레임워크 기반 프론트엔드와 백엔드를 함께 만들어 클라이언트에 전달해 주었습니다. 최근에는 클라이언트에서 직접 구동하는 싱글 페이지 앱 기반 프레임워크들이 인기를 끌면서, 백엔드는 API를 통해 JSON 데이터를 생성해 주는 역할로 많이 바뀌었죠. 클라우드 환경에서 풀스택 앱을 빠르게 만들 수 있게 된 것도 큰 변화 중에 하나입니다.

이러한 변화를 기반으로, 지금은 아예 처음 부터 서버리스 컴퓨팅과 데이터베이스를 활용해서 가용성과 확장성을 염려하지 않는 천만 사용자 아키텍처를 구성할 수 있습니다. 지금 보시는 아키텍처가 오늘 여러분과 살펴볼 AWS 서버리스로 구성된 천만 사용자 아키텍처입니다. 서버리스란 여러분이 관리 및 운영할 서버가 없다는 뜻으로 그 일을 대부분 AWS가 담당하는 것을 의미합니다. 그렇다고, 서버 방식의 이전 방식이 잘못된 것은 아닙니다. 여러분 회사의 비지니스 목표에 따라 선택할 수 있습니다.

먼저 알아두셔야 할 것은 클라우드 아키텍처에 정답은 없습니다. 클라우드의 장점은 쉽게 구축하고 이를 변경할 수 있다는 점입니다. 따라서, 구축후에 다양한 운영 데이터를 측정해서 배운 점을 토태로 다시 구축하는 과정을 반복해야 합니다. 이를 통해 서비스 확장 및 성능, 그리고 최적화된 아키텍처로 비용도 절감할 수 있습니다. 서버 방식이든 서버리스 방식이든 만능키는 없다는 점을 먼저 기억해 주시면 감사하겠습니다.
사용자 1명 부터 1만명을 위한 클라우드 기반 서버리스 아키텍처
그래서 한 명의 사용자 부터 각 앱 구성 요소를 나누도록 가이드합니다. 예를 들어, 웹 서버와 데이터베이스를 다른 서버로 분산하는 것이죠. 우리가 이제 살펴볼 서버리스 방식도 크게 다르지 않습니다. 우리가 앞에서 애플리케이션 요소로 분리했던 프론트엔드, 백엔드, 데이터스토어에 대해 적절한 AWS 서비스를 선택해서 분리해야 합니다. 그렇게 하면, 인프라의 관리 부담 없이 서비스 확장이 가능하도록 할 수 있구요. 각 영역별 개발 부하가 크게 감소합니다. 최신 개발 프레임워크 와 통합도 쉽고 일관된 개발자 경험을 얻을 수도 있습니다.

자 그럼 본격적으로 프론트엔드 부분부터 살펴보겠습니다. AWS에서 웹 호스팅을 하려고 할 때 가장 널리 알려진 방법은 바로 Amazon S3의 정적 웹 호스팅을 사용하는 방법입니다. AWS의 무제한 스토리지 저장소인 S3 버킷에 웹 페이지를 업로드하면, 바로 사이트를 볼 수 있습니다. 하지만, 똑 같은 기능을 제공하면서도 향후 확장 가능성을 고려하면 AWS Amplify Hosting 서비스를 이용하는 것이 좋습니다. 특히, 다양한 프론트엔드 프레임워크에 특화되어 있기 때문인데요.
Amplify Hosting은 싱글 페이지 앱을 위한 글로벌 호스팅 저장소입니다. 전 세계에 400 개가 넘는 콘텐츠 배포 지점을 가진 Amazon CloudFront라는 콘텐츠 전송 네트워크를 이용합니다. 앱이 배포되면, 자동 생성 된 HTTPS 기반 도메인으로 바로 서비스 가능하고, 자체 도메인지정도 쉽게 할 수 있습니다. 앱 배포 과정도 원클릭으로 지속적 통합/배포 즉 CI/CD 모델을 따르고 있습니다. 즉, 소스 코드의 풀 리퀘스트가 오면 자동으로 소스 변화를 감지해서 배포하는 방식입니다. 또한, 개발 시 간단한 사용자 이름 및 비밀번호 인증으로 앱을 보호하는 옵션이 있습니다. 이는 앱의 여러 기능 중 공개 혹은 비공개 상태로 테스트할 때 유용한 옵션입니다.
자! 이제 백엔드 구성에 대해 살펴보도록 하겠습니다. 가장 기본적으로 Amazon EC2 기반의 가상 서버를 백엔드 인프라로 제공하고, 애플리케이션 로드 밸런서라는 서비스 부하 분산 서비스를 주로 이용해 왔습니다. 인프라에 대한 걱정 없이 애플리케이션 구현과 배포에만 집중할 수 있는 서버리스 옵션도 있습니다. 컨테이너 오케스트레이션 서비스인 Amazon ECS와 Amazon EKS 모두 AWS Fargate라는 서버리스 기반 컨테이너 관리 서비스를 선택할 수 있구요. AWS AppRunner는 Fargate를 기반으로 컨테이너 배포 및 운영까지 손쉽게 해 주는 서비스입니다. 더 나아가 AWS Lambda는 프로그램 코드를 실행할 때만 과금하는 대표적인 서버리스 서비스입니다.

AWS AppRunner는 서버리스 기반 컨테이너 서비스로 웹 기반 백엔드, 모바일 백엔드, 마이크로서비스 및 API 호스팅을 좀 더 간단하게 할 수 있도록 도와주는 서비스입니다. Node.js, Python, Java, .Net 및 Rails와 같은 널리 사용되는 언어 런타임을 지원합니다. App Runner 서비스 제공 방식을 살펴보면, 개발팀이 소스 코드 레포지터나 기존 컨테이너 이미지를 등록하면, 바로 소스 코드 접근 권한이나 레지스트리 등록 권한을 얻어 HTTPS 엔드포인트로 접근 가능한 서비스를 바로 생성합니다. 여기서 빌드 및 런타임 구성, CPU 및 메모리 크기, 배포 및 확장 같은 모든 것은 AWS에서 관리 하게 됩니다.
자 이제 데이터 베이스 부분을 알아보겠습니다. 대표적으로는 SQL이라고 부르는 질의 방식을 사용하는 관계형 DB가 있습니다. 우리가 자주 사용하는 MySQL, PostgreSQL, Oracle, MSSQL 같은 데이터베이스가 대표적이죠. RDB도 이미 많은 사용자와 예제가 있고, 수백만의 사용자도 충분히 처리 가능한 확장성을 가지고 있습니다. AWS에서는 관계형 DB를 완전 관리형으로 제공하는 Amazon RDS라는 서비스가 있습니다. 그리고, MySQL과 PostgreSQL 성능과 확장성을 개선한 Amazon Aurora라는 서비스도 제공합니다.
어떤 분들은 기술 유행에 따라 NoSQL DB를 채택하는 경우가 있는데, 사실 대부분은 RDB만으로도 충분합니다. 저는 AWS에서 가장 인기 있는 Amazon Aurora를 추천합니다. MySQL이나 PostgreSQL을 쓰신다면, Amazon Aurora Serverless 기능이 있습니다. DB 서버나 클러스터를 띄우고 관리할 필요가 없이 그냥 DB 엔드포인트만 딱 제공해 줍니다.
Aurora Serverless는 Aurora가 제공하는 읽기 전용 복제본 , 멀티 AZ 지원, 멀티 리전을 위한 글로벌 데이터베이스처럼 다양한 가용성 옵션을 기본으로 제공하구요. 최소한의 DB로 운영되다가, 트래픽이 늘어나면 이에 맞게 스케일업 방식으로 컴퓨팅 용량을 늘려줄게 됩니다. 순식간에 수십만건의 트랜잭션이 일어나도 즉시 확장이 가능하구요. 서버리스 방식으로 최대 90%까지 운영 비용을 절약할 수 있습니다.
1만명 이상을 위한 영역별 성능 튜닝
1만 명이상으로 사용자가 늘어나면 새로운 문제가 생길 수 있습니다. 우선 사용자가 많아지면 다양한 요구 사항에 따른 애플리케이션 복잡성이 늘어나구요. 하나의 제품 영역에서 성능 문제가 생길 때, 함께 문제가 생길 수 있습니다. DB 같은 경우, 테이블 크기나 인덱스가 커지면 전반적인 DB 쿼리 속도 저하되어 애플리케이션 구동에 영향을 줄 수도 있습니다. 따라서, 우리는 프론트엔드, 벡엔드, 데이터베이스 각 영역에 대한 자세한 성능 튜닝이 필요합니다.

먼저 프론트엔드 영역의 Amplify Hosting입니다. 일단 Amplify Hosting은 전 세계 410개 이상의 Amazon CloudFront 엣지 로케이션 위에 구축되어 있어서 별도로 컨텐츠 전송 네트워크를 쓰지 않아도 됩니다. 글로벌 규모의 전송망을 그대로 이용하기 때문인데요. 따라서 프론트 엔드 코드 성능을 높이고, 백엔드에 대한 호출 수를 줄이는 등의 일반적인 성능 개선 방법을 사용하면 됩니다. Amplify는 호스팅 성능과 배포 가용성 간의 균형을 위해 새로 앱 배포 시 즉각 캐시 무효화를 통해 빠르게 배포가 이뤄지도록 할 시 있습니다. 좀더 고급 사용자는 Amplify 콘솔의 사용자 지정 헤더를 통해 앱의 배포 특성에 따라, 캐시 시간을 지정하여 성능을 개선할 수 있습니다.
백엔드 부분의 App Runner에서 처리 가능한 최대 용량에 대해서도 알아보겠습니다. AppRunner가 사용하는 컴퓨팅 단위는 ECS Fargate 작업이지만 이를 인스턴스라고 부르는데요. 각 인스턴스는 고정된 비율의 CPU와 메모리를 가질 수 있습니다. 각 인스턴스는 동시 요청 수를 기준으로 200이 넘으면 확장을 하게 되는데요. 최대 25개까지 확장 가능하여, 따라서 동시 요청 5천개까지 처리 가능하게 됩니다. 만약 요청당 2초 정도가 걸린다고 가정하면 분당 최대 십오만 정도의 요청을 처리할 수 있습니다. 그러니까, 상당한 트래픽을 처리할 수 있습니다. 트래픽이 줄어들면 자체 L7라우터가 판단하여 인스턴스 숫자를 자동으로 줄여줍니다. 그리고, 백엔드에서는 애플리케이션 자체 성능 튜닝이 상당히 중요합니다.
최근에는 백엔드 성능을 높이기 위해서 인공 지능 기반 데브옵스 운영 도구도 선보이고 있습니다. Amazon CodeGuru는 애플리케이션 소스 코드를 분석해서 성능 문제 해결과 비용 절감을 해주는 서비스이구요. 그리고 Amazon DevOps Guru는 클라우드 인프라에서 운영 중 비정상적인 동작을 감지하여 성능 문제를 해결하는 방법을 제시해 주는 서비스입니다.

마지막으로 데이터베이스 성능 튜닝에 대해 살펴보겠습니다. 병목 구간이 될 가능성도 높고, 확장 자체가 어렵기 대문에 가장 중요한 영역이기도 합니다. 일단 Aurora Serverless는 스케일 업 방식으로 CPU/메모리 자동 추가 혹은 축소합니다. 수십만 건의 트랜잭션도 처리 가능하도록 모니터링을 하면서 컴퓨팅 플릿을 수평 확장합니다. Aurora처럼 3개의 가용 영역에 최대 15개의 읽기 복제본을 생성할 수 있습니다. 따라서, DB의 경우도 느린 SQL 질의는 없는지, 성능에 영향을 지는 건 없는지 먼저 튜닝하는게 필요합니다.
Amazon DevOpsGuru 기능 중에 DB 관련 성능 문제를 자동으로 감지, 진단, 수정 권고하는 기능도 있습니다. 현재 Amazon Aurora에서 바로 사용이 가능하구요. Amazon에서 다년간 운영한 정보를 기반으로 하는 기계 학습 모델을 사용하여 CPU나 I/O 리소스 부족, 슬로우 쿼리 같은 잠재적 성능 문제를 자동으로 식별합니다. 실시간으로 알람을 보내 줄 수 있게 설정할 수 있고, 권장 사항을 통해 DB 전문가가 아니라도 쉽게 문제를 해결할 수 있습니다.

그런데 DB 운영과 성능을 아무리 잘 관리하더라도 급작스런 트래픽이 몰려오는 경우에 여전히 관계형 DB의 한계가 있을 수 있습니다. 예를 들어, 커넥션 풀이 꽉 차버린다거나, 확장 속도 보다 더 많이 트래픽이 몰러 오는 경우죠. 이 때, 우리는 DB 커넥션 풀을 관리할 필요 없이 DB 앞단에서 부하를 처리하는 Amazon RDS Proxy를 사용할 수 있습니다. RDS 프록시와 함께 DB 성능을 획기적으로 개선할 수 있는 서비스는 Amazon ElastiCache입니다. 인 메모리 캐쉬 서비스인 Redis와 Memcached를 통해서 RDB에 지속적인 부하를 주는 핫 아이템을 따로 관리하게 할 수 있습니다. 이 기법은 DB 부하를 불이기 위해 고전적으로 많이 사용하는 데이터 캐싱 방법들입니다.

자! 이제 프론트엔드, 백엔드, 데이터베이스 각 영역별 성능 튜닝을 통해 이제 수백만 사용자까지 처리할 수 있는 아키텍처로 진화하였습니다. 이제 백만 사용자 이상을 커버할 수 있는 아키텍처를 어떻게 하는지 살펴보겠습니다.
1백만명 이상 사용자를 위한 고려 요소
사용자가 백만 정도 되면, 어느 정도 규모가 커졌기 때문에… 애플리케이션 복잡성이 커집니다. 아무래도 기능 증가로 인해 비지니스 로직이 지속적으로 추가되기도 하구요. 여러 팀이 개발 및 운영함에 따라 서비스 개발 및 배포 속도가 느려지게 됩니다. 그러면, 결국 백엔드와 데이터베이스 영역에서 다시 병목 현상이 일어날 수 있습니다.
규모가 어느 정도에 왔을 때, 이런 문제를 장기적으로 해결하는 방법은 마이크로서비스(Microservices) 아키텍처로 리팩토링하는 것입니다. 기존에 모든 기능이 다 포함된 큰 애플리케이션 덩어리를 모놀리식이라고 한다면, 마이크로서비스는 잘 정의된 API를 통해 통신하는 기능을 독립적인 서비스로 구성하는 것입니다. 그렇게 되면, 작은 팀이 독립적으로 각 서비스를 소유해서 자율적으로 개발 스택도 선택할 수 있고 배포도 빠르게 할 수 있겠죠.

백엔드에서 의존성이 낮은 기능 부터 분리하여 운영하려면, 몇 가지 서비스가 추가로 필요합니다. 먼저 Amazon API Gateway는 개발자가 API를 손쉽게 생성, 게시, 유지 관리, 모니터링 및 보안 유지할 수 있도록 하는 완전관리형 서비스입니다. 실시간 양방향 통신이 가능하도록 하는 RESTful API 및 WebSocket API를 지원하기 때문에 앞단에서 기능 분산을 해 줄 수 있습니다. 분리하고자 하는 간단한 기능은 AWS Lambda 서비스로 구현하면 좋습니다. AWS Lambda는 간단한 프로그래 코드만으로 필요한 이벤트에 따라 코드를 실행할 수 있는 이벤트 중심의 서버리스 컴퓨팅 서비스입니다. 동기화에서 비동기로 이동 및 큐, 토픽, 버스 및 스트림을 활용하여 이벤트 기반 아키텍처 구축하는데 용이합니다.
데이터베이스도 서비스 별로 분리할 수 있습니다. AWS에서는 목적에 맞는 DB 선택 옵션을 제공하는데요. 지금까지 살펴본 RDS/Aurora 같은 관계형 DB와 ElastiCache 같은 캐시 서비스와 함께, 문서, 그래프, 메모리, 키-밸류, 시계열, 원장, 칼럼 등 각 목적에 맞는 데이터베이스 서비스를 제공하고 있습니다. 이들 모두 개발자가 DB SW 설치, 구성, 성능 및 가용성, 확장성, 보안 및 규정 준수 문제에 대해 걱정할 필요가 없는 완전 괸리형 서비스이구요. 필요에 따라 서버 및 클러스터 관리를 할 필요가 없는 “서버리스” 방식을 선택할 수 있습니다. 서버리스 방식은 DB 운영 부담을 획기적으로 줄여주는 장점이 있습니다.
천만 사용자를 위하여
자, 이제 마지막으로 백만을 넘어 천만 사용자를 위해 우리가 해야 할 일을 한번 살펴보겠습니다.
맨 먼저 독립적으로 구성해 온 마이크로서비스들을 이벤트 기반 아키텍처로 진화 시키면 좋습니다. Amazon EventBridge 같은 이벤트 버스는 급증하는 워크로드를 수용하는 탄력적인 버퍼 역할을 해 줄 수 있습니다. AWS StepFunctions 같은 워크플로 서비스를 쓰면, 기능들을 이벤트 기반으로 동작 시키는데도 좋습니다. 어느 정도클라우드 역량이 쌓이게 되면, 자체적인 컴퓨팅 관리를 시작해 보는 것도 좋은 방법입니다. AWS AppRunner의 기반이 되는 AWS Fargate를 직접 써보고 컴퓨팅 확장 관리 및 튜닝을 해보는 것이죠. 어쨌던 지금까지 해오던 대로 전체 스택의 성능을 계속 분석하고 지속적으로 개선하는 노력이 필요합니다.

천만 사용자 아키텍처로 진화하면서 기존 AWS Lambda 함수에 이벤트 기반 아키텍처 구성을 위한 AWS 서비스들도 추가하고 AWS Fargate를 직접 활용해서 구축하는 방법도 검토해 보면 좋습니다.
지금까지 서버리스 서비스들을 기반한 천만 사용자 아키텍처를 살펴보았습니다. 이번 AWS Builders Online 행사에서 좀 더 자세히 설명한 동영상을 공개하였으니, 더 자세한 것은 아래 영상을 참고하세요!
참고 – 기존의 서버 기반 천만 사용자 아키텍처도 좋은 선택 옵션입니다. 활용하는 AWS 서비스의 차이만 있지, 접근하는 방법은 거의 같습니다. 이 영상도 함께 보시면 좋습니다.
더 읽어 볼 글
※ Disclaimer- 본 글은 개인적인 의견일 뿐 제가 재직했거나 하고 있는 기업의 공식 입장을 대변하거나 그 의견을 반영하는 것이 아닙니다. 사실 확인 및 개인 투자의 판단에 대해서는 독자 개인의 책임에 있으며, 상업적 활용 및 뉴스 매체의 인용 역시 금지함을 양해해 주시기 바랍니다. 본 채널은 광고를 비롯 어떠한 수익도 창출하지 않습니다. (The opinions expressed here are my own and do not necessarily represent those of current or past employers. Please note that you are solely responsible for your judgment on checking facts for your investments and prohibit your citations as commercial content or news sources. This channel does not monetize via any advertising.)