넷플릭스 성능 케이스스터디
🎬

넷플릭스 성능 케이스스터디

@November 22, 2018

원문 : https://medium.com/dev-channel/a-netflix-web-performance-case-study-c0bcde26a9d9

Netflix.com 데스크톱 브라우저에서 Time-To-Interactive 개선하기

tl;dr: 웹 성능 개선에 왕도는 없다. 간단한 정적 페이지들은 최소한의 자바스크립트만 포함하도록 서버 렌더링할 수 있다. 신중하게 사용된 라이브러리들의 가치는 페이지가 복잡할때 빛을 발한다.

Netflix는 아주 유명한 비디오 스트리밍 서비스이다. 2016년 글로벌 출시 이후신규 가입자들이 많이 늘어났다. 이들은 모바일 페이지에서 회원 가입을 하거나 비디오 스트리밍에 적합하지 않은 환경에서도 접속했다.

개발자 팀은 Netflix.com 회원가입 과정에 사용되는 자바스크립트를 최적화 하고 프리패치(prefetch) 기술을 적용했다. 그 덕에 모바일과 데스크톱 사용자 모두에게 더 나은 사용자 경험을 제공할 수 있었다.

  • 로딩 시간과 Time-to-Interactive가 50% 감소(Netflix.com의 데스크톱 홈페이지)
  • React와 클라이언트 측 라이브러리들을 순수(vanilla) 자바스크립트로 변경하여, 자바스크립트 번들 크기 200kB 감소. React는 서버 측에서 여전히 쓰임.
  • HTML, CSS, 자바스크립트(React)를 미리 다운로드하여(prefetch), 다른 페이지들의 Time-to-Interactive 30% 감소

자바스크립트를 더 적게 만들어 Time-to-Interactive 줄이기

Netflix 개발자들은 사용자들이 가입하거나 로그인하는(로그인 정보가 없을 시 보이는) 홈페이지의 성능을 최적화했다.

역자주: 이후 표현을 해치지 않는 범위에서 logged-out homepage를 홈페이지로 줄여 쓰겠다.
image

새로운 사용자 혹은 로그인하지 않은 사용자를 위한 Netflix.com 홈페이지

이 페이지는 초기 300kB의 자바스크립트를 포함하고 있었다. React 그리고 Lodash처럼 유틸리티 같은 클라이언트 코드가 일부 있었고, React의 상태를 초기화(hydrate)하기 위한 데이터가 일부 있었다.

Netflix의 모든 웹페이지는 서버에서 React로 렌더링한 HTML이 전달되며, 이후 클라이언트 측 애플리케이션이 보내진다. 그렇기에 개발의 일관성을 위해 새로 개편될 홈페이지의 구조를 동일하게 유지하는 것이 중요했다.

image

일례로 홈페이지의 탭들은 React를 사용해 만들어진 컴포넌트이다

크롬의 개발자 도구와 Lighthouse에서 3G 연결을 시뮬레이션했더니, 홈페이지 로드에 7초가 걸렸다. 단순한 랜딩 페이지일 뿐인데 너무 긴 시간이 걸린다. 이로써 개선될 여지가 확인되었다. 몇 가지 성능 감사 도구를 사용했더니 클라이언트에서 사용할 자바스크립트의 비용이 매우 높았다.

image

최적화 이전의 Netflix.com를 느린 3G 환경으로 제한한 크롬 개발자 도구

브라우저의 자바스크립트를 비활성화한 상태로 사이트의 어떤 요소가 동작하는지 살펴보는 방법으로, 홈페이지가 동작하는 데 정말 React가 필요한지 확인할 수 있었다.

이 페이지 요소 대부분은 기본적인 HTML이었기에, 자바스크립트 클릭 처리나 class를 추가하는 일 따위의 나머지 요소들은 순수 자바스크립트로 대체할 수 있었다. 또한 원래 React로 만들었던 언어 전환 기능은 300줄도 되지 않는 순수 자바스크립트로 다시 만들었다.

순수 자바스크립트로 전환한 전체 컴포넌트 리스트는 다음과 같다.

  • 기본적인 상호작용 (홈페이지 중간의 탭들)
  • 언어 전환 기능
  • 쿠키 배너 (미국 이외의 방문자 대상)
  • 분석을 위한 클라이언트 측 로깅
  • 성능 측정과 로깅
  • 광고 속성 픽셀 부트스트랩 코드 (보안상 iFrame에서 샌드박스 처리됨)
image

React의 자체 용량은 45kB에 불과했지만, React, 몇몇 라이브러리, 그리고 이를 사용하는 앱 코드를 클라이언트에서 제거했더니 모두 200kB가 넘는 자바스크립트가 줄어들었다.

image

클라이언트에서 React, Lodash 등의 라이브러리 삭제 전/후 페이로드 비교

실험실 환경에서는 Lighthouse(추적 데이터)를 사용해 사용자들이 Netflix 홈페이지를 빠르게 사용(Time-to-Interactive)할 수 있음을 확인할 수 있었다. 데스크톱 TTI는 3.5초 미만.

image

Time-to-Interactive 최적화한 이후 Lighthouse 보고서

그렇다면 실제 환경에서는? Chrome User Experience report를 보면 97%의 데스크톱 Netflix 사용자들에게 첫 입력 지연(First Input Delay)이 빠르다는 것을 확인할 수 있다. 첫 입력 지연이란 사용자가 첫 동작을 시작한 순간부터 브라우저가 그 동작에 응답한 순간까지를 뜻한다.

image

첫 입력 지연(FID)은 사용자가 페이지에서 느끼는 상호작용 지연을 측정한다.

이어지는 페이지에서 사용되는 React 미리 가져오기

홈페이지를 방문할 성능을 더욱 개선하기 위해, 사용자들이 랜딩 페이지에서 보내는 시간을 그들이 방문할만한 페이지의 리소스를 미리 가져오도록(prefetch) 활용했다.

이는 브라우저 API인 <link rel=prefetch> 그리고 XHR 를 사용해 미리 가져오는 2가지 방법을 통해 가능했다.

브라우저에 포함된 이 API는 페이지의 head 태그 안에 간단한 link 태그로 되어있다. 이것은 브라우저에 그 리소스(HTML, 자바스크립트, CSS, 이미지 같은)가 미리 가져올 수 있는 것이라 알려주지만, 브라우저가 실제로 그 리소스를 미리 가져온다고 보장할 수는 없다. 또한 완벽히 지원하지 않는 다른 브라우저들도 있다.

image

미리 가져오는 방법 비교

그에 반해 XHR로 미리 가져오는 방법은 수년간 브라우저의 표준이었고, 브라우저가 리소스를 캐시 하도록 했을 때 95%의 성공확률을 보였다. XHR로 미리 가져오는 방법을 HTML 문서에 사용할 수는 없지만, Netflix는 이어지는 페이지의 자바스크립트와 CSS를 미리 가져오는 데 사용했다.

주의: Netflix의 HTTP 응답 설정은 HTML을 XHR로 캐싱하지 못하도록 하고 있다(두 번째 페이지의 HTML에 no-cache 적용). Link를 사용한 미리 가져오는 방법은 HTML에서 동작하기 때문에 예상대로 동작했다. no-cache가 특정 포인트까지는 막는다고 하더라도 말이다.

// 새로운 XHR 요청 생성
const xhrRequest = new XMLHttpRequest();

// 리소스르 미리 가져오기 위해 요청 열기
xhrRequest.open('GET', '../bundle.js', true);

// 뿅!
xhrRequest.send();

브라우저에 포함된 API(link)와 XHR를 사용해 HTML, CSS, 그리고 자바스크립트를 미리 가져왔더니, Time-to-Interactive 가 30% 줄었다. 이 구현방식은 자바스크립트를 재작성할 필요도 없었고, 홈페이지의 성능에 나쁜 영향을 주지도 않았다. 그러니 이는 아주 적은 위험으로 페이지 성능을 최적화하는 귀중한 도구라 하겠다.

image

미리 가져오기를 구현한 후, 크롬 개발자도구로 리소스의 캐시 적중과 페이지의 Time-to-Interactive 매트릭을 분석하여 향상 점들을 살펴봤다.

넷플릭스의 홈페이지 – 최적화 요약

리소르를 미리 가져오고 홈페이지의 클라이언트 코드를 최적화하여, 가입 과정의 Time-to-Interactive 매트릭스를 크게 개선 할 수 있었다. 브라우저에 포함된 API(link)와 XHR을 이용해 곧 방문할 페이지들을 미리 가져옴으로써, Time-to-Interactive를 30% 감소 시킬 수 있었다. 이는 가입 절차 single-page 앱에 사용되는 부트스트래핑 코드를 포함한 두 번째 페이지를 위한 일이었다.

Netflix팀의 코드 최적화는 React가 유용한 라이브러리이기는 하지만, 모든 문제에 대한 만능 해결책은 아니라는 점을 보여주었다. 첫 랜딩 페이지의 클라이언트 코드에서 React를 제거하여, Time-to-Interactive가 50% 넘게 개선되었다. 클라이언트의 Time-to-Interactive를 줄였더니 사용자들이 가입 버튼을 더 많이 누르게 되었고, 이는 코드 최적화가 더 나은 사용자 경험을 이끈다는 것을 의미한다.

Netflix는 홈페이지에서 React를 사용하지 않지만, 이후 페이지를 위해 미리 다운로드 한다. 이는 이후 가입 프로세스 single-page React 애플리케이션의 디딤돌이 될 수 있었다.

이 최적화에 대한 보다 자세한 내용은 Tony Edwards의 훌륭한 연설을 보시라.

image

결론

Netflix는 자바스크립트의 비용을 주의 깊게 살펴, Time-to-Interactive를 개선 할 기회를 발견했다. 여러분의 사이트에 개선의 여지가 있는지 알아보려면 성능 도구들을 사용해보자.

Netflix가 내린 절충안은 React로 랜딩 페이지를 서버에서 렌더링하고, 그사이 React와 이후 가입 절차 코드를 미리 가져오기로 한 것이다. 이는 첫 로딩 성능뿐 아니라 single-page로서 훨씬 커다란 자바스크립트 번들을 포함한 가입 절차를 로딩하는 시간도 최적화했다.

여러분 사이트의 흐름에도 순수 자바스크립트를 활용할 수 있는지 고민해보자. 반드시 라이브러리를 사용해야 한다면 방문자가 필요로 하는 코드만 다운로드 시키려 노력하자. 미리 다운로드 시키는 방법 등은 이후 페이지의 로딩 시간을 개선하는데 도움이 된다.

추가 사항

  • Preact 사용도 고려했었지만, 상호작용이 적은 간단한 페이지 흐름에선 순수 자바스크립트를 사용하는 것이 나은 선택이었다.
  • 정적 자원 캐싱을 위한 Service Workers를 시험해보았지만, 그때는 Safari가 지원하지 않았었다. 지금은 지원하므로 다시 시도해보고 있다. 멤버들이 사용하는 페이지보다도 가입 절차 페이지는 더 넓은 구형 브라우저를 지원해야 한다. 많은 사용자는 오래된 브라우저에서 가입하고, 모바일 앱이나 TV를 사용해 시청한다.
  • 랜딩 페이지는 꽤 동적이다. 가입 흐름 중에서 랜딩 페이지는 가장 많은 A/B 테스트를 거친 페이지다. 랜딩 페이지의 메시지, 이미지는 머신러닝 모델에 따라 사용자의 위치나 기기 유형등의 여러 요인을 사용하여 커스터마이징 된다. 거의 200개국을 지원하는데, 이러한 파생마다 다른 지역, 법률, 그리고 가치 전달을 위한 도전이 있다. A/B 테스트에 대한 이야기는 Ryan Burgess의 더 나은 사용자 경험을 위한 테스팅(Testing Into A Better User Experience)을 보자.

리뷰와 이바지 해준 Netflix UI 엔지니어들, Tony EdwardsRyan BurgessBrian HoltJem YoungKristofer Baxter (Google), Nicole Sullivan (Chrome) and Houssein Djirdeh (Chrome) 에 감사의 말을 전한다.