Amazon CloudFront를 활용한 동적 콘텐츠 전송 성능 개선하기
게임 서비스에 있어서 데이터 전송 성능은 매우 중요한 요소입니다. 성능 향상을 통해 더 많은 페이지 뷰, 풍부한 사용자 경험, 높은 전환율을 얻을 수 있으며, 이는 비지니스 성공과도 직결된 중요한 요소들이라고 볼 수 있습니다. 한 통계 자료에 따르면 페이지 로딩시의 1초 지연은 7%의 전환율 하락을 가져올 수 있다고 합니다. 뿐만 아니라, 글로벌 서비스에서 최종 사용자 경험을 향상 시키는데 있어서 콘텐츠 전송 성능은 매우 중요한 요소 입니다.
CDN을 통한 동적 콘텐츠 전송에 대한 이해
Amazon CloudFront는 AWS의 콘텐츠 전송 서비스(CDN) 로서, 다른 서비스들과 통합되어 최종 사용자에게 효과적으로 콘텐츠를 쉽고 빠르게 전송할 수 있습니다. CDN은 최종 사용자와 원본 저장소(Origin) 사이에서 프록시(Proxy) 역할을 하며, 전 세계 56개(2016년 6월 20일 기준) 엣지 로케이션(Edge Location)에 미리 캐시 함으로써 빠르게 사용자에게 콘텐츠 전송을 할 수 있습니다.
일반적으로 이미지나 동영상 파일 같은 정적 콘텐츠 전송을 위해서 Amazon CloudFront를 많이 활용하고 있지만, 동적 콘텐츠 전송을 위해 사용하는 것에 대해서는 몇 가지 이유로 고민을 합니다. 동적 콘텐츠는 대게 자주 변경되는 정보를 가지고 있거나, 사용자가 보낸 요청에 포함된 요인에 따라 그 내용이 변경되는 특성을 가지고 있습니다.
그래서 항상 최신의 콘텐츠를 가져오기 위해 TTL 을 0 으로 설정하여 원본 저장소에 매번 접속 하여야 하기 때문에, 엣지에 캐시를 함으로써 향상되는 콘텐츠 전송 가속의 효과가 미비하다고 생각되는 이유 때문입니다. 하지만, TTL 을 0으로 설정하여 매번 원본 저장소에 접속하여 동적 콘텐츠를 제공하더라도, CloudFront를 프록시로 사용함으로써 전송 성능을 향상 시킬 수 있습니다.
먼저 콘텐츠 전송 성능에 대해서 얘기하기 앞서, 요청에 대한 응답 시간을 어떤 요인들로 구분하여 생각할 수 있는지 알아보는게 도움이 될 것입니다.
데이터 전송 관점에서 성능 향상 방법
아래 그림에서 보시다시피 응답 시간은 간단히 DNS Lookup 시간과, 연결 수립 시간, 최초 바이트를 받기까지의 시간, 콘텐츠 다운로드 시간의 합으로 생각해 볼 수 있습니다.
최종 사용자가 요청을 보내면, 먼저 DNS Lookup 을 하게 됩니다. 이 후 대상 서버와 TCP handshakes/retries 등의 과정으로 연결을 수립하게 됩니다. 그리고 TTFB 로 알려져 있는 최초의 응답을 기다리게 되고, 그 이후 콘텐츠를 다운로드 합니다.
이 과정이 완료되면 요청에 대한 응답이 완료되었고, 콘텐츠가 전송 되었다고 볼 수 있습니다. 앞서 나열한 요인들을 포함한 응답 시간을 CloudFront는 어떻게 처리하여 콘텐츠 전송 성능을 향상 시킬까요?
- 최적화된 네트워크: Amazon CloudFront 엣지와 AWS 리전 사이의 네트워크는 지속적으로 모니터링되고 성능 및 가용성면에서 최적화 됩니다. 게다가 네트워크상에 문제가 발생할 경우 신속하게 감지 및 수정되고, 최종 사용자를 다른 네트워크 경로로 자동 라우팅하여 최종 사용자에 미치는 영향을 최소화 합니다. 이를 통해 더 적은 패킷 감소와 더 나은 성능을 기대할 수 있습니다.
- 원본과의 지속적인 연결 유지: IP 기반의 네트워크를 통해 TCP/IP 연결을 맺기 위해서는 TCP 3-way handshake 라는 과정을 거치게 됩니다. 이 과정에 필요한 패킷 사이즈는 그렇게 크지 않기 때문에 큰 오버헤드가 아닐 수 있습니다. 하지만 글로벌 서비스와 같은 경우 지리적으로 떨어져 있는 곳에서 최종 사용자가 요청을 하게 되고, 지리적인 요건으로 인한 높은 RTT(Round-Trip Time)로 인해 매우 큰 오버헤드가 될 수 있습니다. CloudFront는 엣지에서 오리진으로의 지속적인 연결을 유지 및 재사용 하여 대게 수백 밀리세컨드가 소요되는 연결 설정 시간을 줄여 줍니다. 글로벌 서비스에서는 물론, 초당 요청 건수가 많아지면 많아질수록 지속적인 연결 유지로 얻을 수 있는 콘텐츠 전송 속도 향상의 효과는 커집니다.
- TCP/IP 최적화: 네트워크의 대역폭은 다양한 이유로 시시때때로 바뀌게 됩니다. CloudFront의 모든 호스트에는 엣지와 최종 사용자 간의 시시때때로 변하는 네트워크 대역폭 사용을 최대화 하기 위해 TCP initcwnd(initial congestion window) 값이 최적화 되어 있습니다.
- Gzip 압축 사용: Amazon CloudFront가 제공하는 GZIP 압축을 사용한다면 전송되는 데이터의 크기를 줄여, 트래픽을 줄일 수 있습니다. 이를 통해, 데이터 전송은 더 짧은 시간 안에 완료할 수 있을 뿐만 아니라, 데이터 전송 비용도 절감할 수 있습니다. 특히나 동적 콘텐츠는 대부분 매우 높은 압축률을 보여주는 텍스트 형태이기에 압축을 통한 효율이 더 높습니다. 또, CloudFront 엣지에서 압축 작업을 수행함으로써 오리진에서 압축을 위해 자원을 사용할 필요가 없어지는 장점도 있습니다.
앞서 설명한 대부분의 기능과 방법들은 CloudFront 엣지와 오리진 사이의 최적화에 관련된 내용 입니다. 최종 사용자와 엣지 사이의 최적화는 어떨까요? CloudFront는 지속적으로 지연 시간을 측정하여 최종 사용자가 항상 더 나은 경험을 할 수 있는 엣지로 연결을 하도록 합니다. 그리고, 여러 리전에 오리진을 배치하여 실제 물리적 거리를 줄일 수 있을 경우 Amazon Route 53의 LBR(Latency Based Routing)을 사용하여 최종 사용자로부터 최적의 리전에 있는 오리진에서 콘텐츠가 전송될 수 있도록 합니다.
지금까지 설명한 내용으로 앞서 언급한 응답 시간 관여 요인들을 최적화 하여 응답 시간을 줄일 수 있습니다.
- DNS Lookup 시간: CloudFront의 라우팅 기술, Route 53과의 통합
- 연결 수립 시간: CloudFront의 지속적인 연결 유지
- 최초의 응답 시간(TTFB): CloudFront의 지속적인 연결 유지, Gzip 압축
- 콘텐츠 다운로드 시간: CloudFront의 TCP/IP 최적화, Gzip 압축
CloudFront를 활용한 동적 콘텐츠 전송 테스트
Amazon CloudFront가 제공하는 응답 시간을 줄이기 위한 다양한 방법들을 살펴보았습니다. 이를 통해 어느 정도 응답 시간을 줄일 수 있는지는 간단한 테스트로 확인할 수 있습니다.
아래는 Amazon CloudFront를 활용한 동적 콘텐츠 전송 테스트 시나리오입니다.
- 미국 동부(버지니아)에 있는 사용자가 한국에 있는 개인 서버로 접속하여, 1.7KB 정도의 동적 콘텐츠를 요청
- CloudFront 엣지와 오리진과의 네트워크 성능에 집중하기 위해, 모든 캐시는 비활성
- 마찬가지로 네트워크 성능에 집중하기 위해, 요청을 보낸 후 응답을 받은 뒤, 곧바로 다시 요청을 보내는 방법으로 진행 (Python 스크립트 사용)
- 1일 03:09:00 초 ~ 5일 19:29:30 초 까지 5일 가까운 기간 동안 테스트 진행
- 테스트1(빨간색 라인): 버지니아 EC2 -> CloudFront (No-cache, TTL 0) -> 오리진 (서울, 개인 서버, Node.js)
- 테스트 2(파란색 라인): 버지니아 EC2 -> 오리진 (서울, 개인 서버, Node.js)
아래는 저의 인터넷 환경에서 얻은 결과입니다. (여러분의 환경과 설정 값들로 인해, 결과는 다를 수 있음을 유의해 주시기 바랍니다.)
횟수 | 평균 | 최소 | 최대 | 90백분위 | 10백분위 | > 1초 | |
CloudFront | 1,902,091번 | 0.212초 | 0.187초 | 9.605초 | 0.209초 | 0.197초 | 40번 |
직접 연결 | 1,027,763번 | 0.393초 | 0.365초 | 7.415초 | 0.403초 | 0.384초 | 118번 |
동일한 기간 동안 테스트를 진행하였고, 그 결과를 확인해보면, CloudFront를 사용하였을 때 87만번 이상의 요청을 더 처리하였으며, 응답 시간은 직접 연결했을 때 보다 평균 181ms로 이는 약 1.8배 정도 더 빠른 결과 입니다. 또한, CloudFront를 사용하였을 때 1초 이상의 응답 지연은 직접 연결한 것에 비해 34% 정도 밖에 되지 않았습니다. 이를 통해, 직접 연결 보다 CloudFront를 활용하였을 때 더욱 빠르고 안정적인 서비스가 가능할 수 있음을 알 수 있습니다.
추가로 미국 서부(오레곤) 리전의 EC2에서 요청을 보냈을 때, 지리적인 이점으로 인해 더 낮은 평균 응답 시간을 얻을 수 있었습니다.
- 테스트1: 오레곤 EC2 -> CloudFront (No-cache, TTL 0) -> 오리진 (서울, 개인서버, Node.js)
- 테스트2: 오레곤 EC2 -> 오리진 (서울, 개인서버, Node.js)
아래는 저의 인터넷 환경에서 얻은 결과입니다. (여러분의 환경과 설정 값들로 인해, 결과는 다를 수 있음을 유의해 주시기 바랍니다.)
횟수 | 평균 | 최소 | 최대 | 90백분위 | 10백분위 | > 1초 | |
CloudFront | 2,689,804번 | 0.150초 | 0.129초 | 5.223초 | 0.191초 | 0.134초 | 52번 |
직접 연결 | 1,642,063번 | 0.249초 | 0.236초 | 3.700초 | 0.248초 | 0.241초 | 90번 |
간단한 테스트를 통하여 Amazon CloudFront를 사용하면 동적 콘텐츠 전송을 가속할 수 있음을 알 수 있었습니다. 이러한 동적 콘텐츠를 위해서 캐시 기능을 사용할 수 있다면 어떨까요? 분명 더 나은 콘텐츠 전송 속도는 물론 원본 저장소 자원 사용도 줄일 수 있을 것 입니다.
동적 콘텐츠에 대한 캐싱을 통한 성능 향상하기
웹 애플리케이션 및 게임 서비스 등에서 제공하는 다양한 기능들에서 동적 콘텐츠 임에도 불구하고 일정 기간 동안은 갱신되지 않아도 크게 영향이 없는 것들을 찾을 수 있습니다. 이런 동적 콘텐츠들은 짧게는 수십초부터 길게는 수일까지 내용을 갱신할 필요가 없으며, 캐싱을 통하여 더 빠르게 전송될 수 있습니다.
아래는 동적 콘텐츠를 캐싱할 수 있을만한 애플리케이션 및 게임 서비스 내의 기능들의 예 입니다.
- 리더보드: http://www.example.com/leaderboards/?page=50&lowest=true – 리더 보드는 소셜 기능을 포함하는 많은 서비스들, 특히 게임에서 많이 요구되는 기능입니다. 게임을 예를 들면, 게임 플레이어들이 전투와 같은 게임 내 활동을 통해 점수가 업데이트 되고, 백그라운드에서 순위가 집계 및 계산이 된 후, 그 결과가 갱신되어, 리더보드에서 순위 정보가 표시됩니다. 게임과 같이 경쟁을 요하는 서비스에서 최종 사용자로부터 자주 요청되는 콘텐츠 입니다. 만약 이 순위 정보를 즉각 계산하고 갱신하고자 한다면 많은 자원을 필요로 할 것입니다. 하지만, 순위 정보는 항상 최신일 필요성이 적다는 점을 감안하면, CloudFront에 캐싱 하여 더 빠르게 응답을 처리하는 동시에 오리진의 자원을 효율적으로 사용할 수 있을 것입니다.
<게임Castle Clash의 리더보드. 매일 자정 리더보드 갱신> - 통계 정보: http://www.example.com/stats/player1/ – 최종 사용자는 추가적인 정보를 얻기 위해서 통계 정보를 요청합니다. 이 통계 정보는 특정한 활동에 대한 집계 일 수도 있으며, 최종 사용자의 활동으로부터 예측한 정보일 수도 있습니다. 이러한 정보는 최종 사용자의 지난 정보들을 수집한 뒤 생성되는 것으로서 자주 요청될 필요성이 적습니다. CloudFront 의 캐시 기능과 보다 긴 TTL 설정을 통하여 더 빠르게 정보를 제공할 수 있습니다.
<World of Warships 포럼의 게임 플레이어 통계 정보> - 각종 리플레이 기반의 기능: http://www.example.com/replay/player1/20/ – 게임 내에서 전투와 같은 활동은 추후 다시 재현하기 위해 리플레이로 저장할 수 있습니다. 리플레이는 일반적으로 게임 플레이어와 상대방(AI 혹은 다른 게임 플레이어)이 언제 어떤 활동 및 명령을 수행 했는지에 대한 순차적인 데이터들의 모음입니다. 이런 데이터를 기반으로 멀티플레이어 게임과 같은 기능을 구현할 수 있습니다. 리플레이 데이터는 한번 생성된 후 수정이 필요하지 않은 정적 콘텐츠의 특징을 가지고 있으며 CloudFront 의 캐시 기능을 백분 활용할 수 있습니다.
<게임 Drag Racing Classic의 멀티플레이어 화면>
뿐만 아니라 Varnish나 Squid 등의 Caching Proxy를 CloudFront와 함께 사용한다면 더 세밀하고, 더 효율적으로 동적 콘텐츠를 캐싱할 수 있습니다.
지금까지 Amazon CloudFront를 활용하여 동적 콘텐츠의 전송을 가속 할 수 있는 방법을 알아 보았습니다. Amazon CloudFront가 제공하는 비용 효율성과 동적 콘텐츠 가속을 위한 기능들을 사용하여 보다 쉽고 빠르게 콘텐츠를 전송하여 최종 사용자 경험 향상은 물론 인프라의 부하도 줄일 수 있습니다. 이외에도 Amazon Route 53, Amazon S3 등의 AWS 서비스와 파트너 솔루션과의 통합으로도 성능 및 가용성을 향상 시킬 수 있습니다.
더 자세한 정보는 Amazon CloudFront – 동적 콘텐츠 전송 페이지와 Amazon CloudFront 개발자 안내서를 참고하시기 바랍니다.
본 글은 아마존웹서비스 코리아의 솔루션즈 아키텍트가 국내 고객을 위해 전해 드리는 AWS 활용 기술 팁을 보내드리는 코너로서, 이번 글은 김필중 솔루션즈 아키텍트께서 작성해주셨습니다.
Leave a Reply