프로그래밍/Web

[스압/데이터주의] 웹 최적화 방식 모음 - 0. 전반적 원칙과 원리

BlaCk_Void 2020. 3. 17. 15:56

웹으로 전향한지 얼마 안됐는데

그동안 경험상 전반적 구조 파악에는 퍼포먼스 개선하는게 최고라 적게되었습니다.

이 문서는 완전히 완성된 상태가 아니라 시간이 나면 업데이트 중.

혹시 이외에도 재미있는 팁을 아시는 분이 있다면 댓글로 알려주세요.

모바일이나 기타 프로그래밍/전공 경험과 지식을 살려봤습니다.

 

제 블로그 글들을 보면 알겠지만 상당히 장문으로 이루어져 있지만..

이건 역대급으로 심하게 길다보니 머릿글을 ㅎㅎ

조금 과장해서 책 한권;;

 

블로그 스킨을 React 기반으로 클린룸 구현해볼까 생각 중이라 더 열심히 하고 있습니다.

타입스크립트, PWA, 웹컴포넌트 등 파워풀한 것을 모두 넣어서 가볍고 빠르고 생산성까지 잡으며 아름답게 만드는 것이 목표 ㅎㅎ

 


 

가끔씩 업데이트하다보니 렉이 심해서 나누었습니다.

 

0. 전반적 원칙과 원리

이 긴 글을 읽기 귀찮다면 TOAST UI팀이 작성한 성능 최적화을 읽어보면 좋다.

아주 깔끔하고 세세하게 설명해놓았다.

 

0.1 이 글의 원칙

성능 개선을 위해서는 적절한 알고리즘과 자료구조를 사용하는 것이 좋다.

원래 그러라고 나온 것들이니까.

 

하지만, 이 글은 알고리즘과 자료구조를 소개하는 글은 아니므로 제외.

네트워크, 브라우저, 언어적 구조와 특성을 이해하고, 최적화하는 것에 중점을 두고 소개한다.

 

효율적인 성능 개선을 위해서 구조에 대한 파악과, 측정은 중요하다.

성능은 측정 가능해야 한다.

 

최신 기술인 SPA나 웹번들러 관련 기법들은 가장 보편적인 리엑트, 웹팩 기준으로 서술한다.

 

+.

보통 소프트웨어 성능이라 함은

  • 디자인 효율성(언어 독립적, 고수준)
    • 알고리즘 / 데이터 구조: 데이터를 다루는 구조와 방법. 필요조건이지만, 충분조건은 아니다.
    • 프로그램 분해(Program Decomposition, 뭐라 번역해야 할지 모르겠다): 작업을 객체 계층, 함수 등의 흐름으로 나누는 것을 의미.
  • 코딩 효율성(언어 의존적, 중저수준)
    • 언어구조: 파이썬의 GIL처럼 커다란 부분부터, C++의 Try-Catch 예외 발생같이 작은 부분까지 언어 특성을 고려
    • 시스템 아키텍처: 프로세서, 메모리 용량과 접근, OS등에 따라 성능특성이 달라짐
    • 라이브러리: 사용하는 라이브러리에 따라 달라짐
    • 컴파일러 / VM 최적화: 컴파일러가 인라인 함수, 분기예측, VM의 GC 등에 최적화

으로 나누어 설명할 수 있다.

 

0.2 원리

0.2.1 네트워크 동작

네트워크 동작은 네트워크 시간에 흔히 배우는 DNS 개념과 TCP/IP에 대한 개념(주로 핸드쉐이크)에 대한 개념이 필요하다.

High Performance Browser Networking브라우저 주소창에 URL을 치면 일어나는 일들에서 전반적 내용을 잘 설명해주고 있다.

 

- DNS

아마존의 DNS란 무엇입니까?란 글이 쉽게 설명해준다.

조금 더 자세한 글을 원한다면 클라우드플레어의 글을 참고하면 좋다.

 

  1. 브라우저에서 www.example.com 같은 도메인 이름을 입력
  2. ISP가 운영하는 DNS Resolver(또는 Local DNS)로 쿼리를 수신
  3. Local DNS에 IP주소가 있다면 전달, 아니라면 루트 DNS 서버에 전달
  4. .com, .net, .kr처럼 공통 도메인 확장자를 관리하는 TLD(Top-Level Domain) 서버에 전달
  5.  TLD 서버는 example.com을 관리하는 DNS 서버에 요청
  6. IP를 전달 받고
  7. 브라우저에게 알려줌
  8. 전달받은 IP주소를 기반으로 요청
  9. www.example.com이 해당되는 웹페이지 반환

- TCP/IP 연결

TLS (Transport Layer Security)

 

TCP는 흔히 알다시피

  • SYN
  • SYN ACK
  • ACK

3 handshake로 이루어진다.

 

그리고 보안에 필요한 TLS까지 사용한다면 몇단계가 더 추가된다. [What Happens in a TLS Handshake?, TLS 핸드쉐이크 (Handshake) 프로토콜 분석, The Illustrated TLS Connection]

 

- HTTP

헤더를 한번 쯤 살펴보길 바란다. [HTTPWTF]

 

0.2.2 브라우저 동작

다음 글은 브라우저가 어떻게 동작하는지 잘 설명해주고 있다.

최근에는 아예 Web Browser Engineering이라는 책이 나왔으니 관심있는 분은 보기 바란다.

 

유명한 브라우저 엔진인 웹킷과 게코의 렌더링 과정은 이렇다.

 

살짝 차이가 있긴 하지만 다음의 과정을 거친다고 볼 수 있다.

다운로드 - 파싱 - 스타일링 - 레이아웃 - 페인트 -합성&렌더링

 

이중 주목할 것은 Layout과 Paint에서 많은 리소스가 필요하다는 것이다.

그래서 돔 조작을 줄이기 위해 Virtual Dom과 같은 개념을 사용하는 라이브러리들이 나오는 중.

 

이번에는 조금 다른 방향으로 들어가서 자바스크립트 엔진의 소개글을 읽어볼 수도 있다.

 

최신 브라우저들의 구조에 대해서는

를 읽어보길 바란다.

왜 메인 쓰레드, 컴포지터 쓰레드, GPU 가속등으로 처리를 나누어 사용하고, 서비스 워커와 웹 어셈블리가 생겨났는지 이유를 찾을 수 있다.

 

마지막으로 하드웨어 가속관련 글과 컴파일러 엔지니어의 이야기

 

브라우저의 각종 기술의 지원 여부는

https://caniuse.com/

 

Can I use... Support tables for HTML5, CSS3, etc

About "Can I use" provides up-to-date browser support tables for support of front-end web technologies on desktop and mobile web browsers. The site was built and is maintained by Alexis Deveria, with occasional updates provided by the web development commu

caniuse.com

를 참고바란다.

 

0.2.3 측정 및 해석

- 브라우저 내장 프로파일러

가장 먼저 생각해볼 수 있는 것은 TOAST UI팀이 작성한 성능 최적화처럼 브라우저에 내장된 프로파일러를 가지고 성능을 측정할 수 있다.

 

프로파일러에서 보이는 각종 타이밍은 다음과 같다. [Navigation and resource timings]

 

다루는 방법은 Chrome DevTools, Firefox 개발자 도구, Safari Developer Help, Microsoft Edge(EdgeHTML) Developer Tools, Flame Graph 문서를 참고.

 

크로미움(Blink), 파이어폭스(Getko), 미도리(Webkit2GTK)의 프로파일링 모습.

요즘 맥북을 잘 안쓰고 리눅스에서 작업하느라 사파리 대신 넣었다.

웹킷은 정보가 너무 부족하고, 크로미움이나 파이어폭스는 장단점이 존재하는데..

 

가장 좋은 것을 뽑자면 크로미움이다.

하드웨어나 각 모듈, 이벤트별로 꼼꼼하게 리소스 소모/부하 및 UX적으로 느끼는 향상까지 전반적으로 다룰 수 있기 때문이다.

  • FPS, CPU, GPU, Network,  Compositor, Service Worker, 자바스크립트 프레임 차트등 다양한 부하
  • 스크린샷, 매 프레임의 시각화
  • 또한 점진적 렌더링과 사용자 기준의 성능측정 기준인 FP(First Paint), FCP(First Contentful Paint), FMP(First Meaningful Paint)등의 이벤트 시간

이외에 어플리케이션 탭에서 PWA 수준까지 정보 제공, Audits에 내장된 구글 라이트하우스 프로파일링 등 매우매우 강력한 디버깅을 제공한다.

 

파이어폭스의 경우,

크롬처럼 각 리소스별 세부적인 정보보단, 우리에게 익숙한 렌더링 프로세스에 충실한 워터풀 모델이 특징.

  • setTimeout, 이벤트 핸들러, 함수호출 등의 자바스크립트
  • 마이너 GC, 비증가형 GC, 사이틀 콜렉션등 자바스크립트 엔진
  • 스타일 재계산, 변경적용, 레이아웃등의 CSS
  • 페인트

 

웹킷은 애플이 만드는 것 답게 매우 심플하며 어떤 부분에서 개선이 필요할지 대략 감잡기 쉽다.

그런데 위에서 적었다시피 정보가 너무 부족;;

특이한 것은 레이어를 볼 수 있다는 것 정도?(아마 Graphics Layer를 뜻하는 듯 하다, 그래픽 가속에서 살짝 다룸)

 

단, 메모리 관리나 레이아웃 디버깅은 파이어폭스가 쉬운편.

시각화가 잘 되어 있고, 보기를 바꾸면 크롬만큼 자세히 보는 것도 가능

 

 

엄청나게 직관적인 CSS 플렉스 박스와 그리드 다루기, 폰트, 애니메이션 등등의 기능

 

웹 개발자 도구의 역사에서 기타 썰들을 들어볼 수 있다.

 

- 라이브러리/프레임워크 전용 프로파일러

 

각종 라이브러리나 프레임워크 전용 프로파일러, 개발자도구들이 존재한다.

 

Redux나 MobX같은 상태관리 라이브러리도 개발자 도구를 지원한다.

웹팩을 사용하면

를 애용하자.

 

마지막으로 React의 경우, Why Did You Render를 활용해보자.

렌더링이 되는 이유와 시기에 대한 정보를 제공해준다.

 

- JS 성능 측정

자바스크립트의 실행시간을 측정하는 방법에 대해 다룬다. [How to measure time taken by a function to execute, How to test vanilla JS performance, 실행 측정 및 계산]

자바스크립트에서 성능을 측정하는 방법은 보통 3가지(new Date[getTime, now], console.time, performance.now)가 있다.

// 1. new Date
const start = new Date(); // or Date.now();
doSomething();
const end = new Date();
console.log((end - start) / 1000);

// 2. console.time - 문자열이 같아야 함.
console.time('Time');
console.timeEnd('Time');

// 3. performance.now - 베스트
const start = performance.now();
doSomething();
const end = performance.now();
console.log((end - start) / 1000);

이 중에서는 performance.now를 사용하는게 가장 나은 방식.

안타까운점은 Spectre와 같은 공격 때문에 정밀도가 줄어들었다. [Mitigations landing for new class of timing attack]

 

사실 클럭 단위로 측정하는게 좋으나 로우레벨이 아니니 그렇게 하거나 할 필요가 없구..

JS 엔진에서 나왔던 "hot code"의 warm up이나 User Timing(W3C)/Navigation Timing정도는 고려해야 한다. [코드성능측정에서 고려해야할 부분들, Bulletproof JavaScript benchmarks, Date 객체와 날짜 - 벤치마크, Define number of cycles - Benchmark.js, When milliseconds are not enough: performance.now, User Timing API: Understanding your Web App - HTML5 Rocks]

벤치마크 프레임워크들이 놓치는 점(파싱 및 컴파일등)도 고려해야 한다. [The truth about traditional JavaScript benchmarks, Speedometer]

기타 마이크로 벤치마크에서 주의할 사항 [Adventures in Microbenchmarking]

 

이러한 사항들에 대해서 알아두고 프레임워크(benchmark.js, zakzak)나 사이트(jsperf, jsben)를 사용해보도록 하자. [Which JS benchmark site is correct?]

 

Jalangi2Analyses란 툴을 사용하면 JIT 최적화 관련 룰을 프로파일링 할 수 있나보다.

 

 

- 기타 측정

다른 측정 방법 중 가장 유명한 것은 구글의 PageSpeed Insights와 라이트하우스(Lighthouse)다. [Web Performance Metrics Cheatsheet]

라이트하우스의 진화: CI, 새로운 성능 지표, User-centric performance metrics 등도 재미있는 문서.

 

라이트하우스는 크롬 개발자도구 또는

를 활용해보자.

 

개인적으로 새로운 웹페이지 성능 측정 지표 CLS(Cumulative Layout Shift)가 흥미로웠다.

실제 웹사이트에서 Web Vitals 디버깅하기는 CLS 개선시에 도움이 될만한 글.

 

다음은 기타 성능 측정 사이트가 잘 정리되어 있는 곳이거나 도구이다.

+

SPA앱은 초기로딩 후 업데이트를 하는 형식이기 때문에 재렌더링 시의 성능등도 고려해야 할 수도 있다.

엠버(링크드인)의 글이 도움이 될 수도. [Measuring and Optimizing Performance of Single-Page Applications (SPA) Using RUM, Sleek and Fast: Speeding Up your Fat Web Client]

 

++

구글의 Search Console 속도 보고서를 보면 성능 측정 후 적용/활용에 대한 이해에 조금이나마 도움이 되지 않을까 싶다.

옛날에 Yslow라고 야후에서 만들었던 확장기능도 있었는데..

 

일반적인 성능 메트릭은 다음과 같다.

메트릭 분류 설명 기준
최초 바이트까지 시간 (TTFB, Time to First Byte) 진행 여부 서버에서 처음으로 정보가 도착할 때까지 걸리는 시간 <600ms
최초 페인트 (FP, First Paint) 진행 여부 배경의 첫 번째 픽셀이 렌더링될 때까지 걸리는 시간 <1.8s
최초 컨텐츠 포함된 페인트(FCP, First Contentful Paint) 진행여부 콘텐츠 렌더링이 시작될 때까지 걸리는 시간 <1.8s
가장 큰 컨텐츠가 포함된 페인트 (LCP, Largest Contentful Paint) 유용성, 중요함 가장 큰 텍스트 블록, 이미지 또는 비디오가 렌더링을 시작할 때까지 걸리는 시간 <2.5s
시각적 완성 (VC, Visually Complete) 유용성 컨텐츠가 완전히 렌더링 되는 시간 <3.4s
속도 지수 (SI, Speed Index) 유용성 뷰포트내 컨텐츠가 눈에 띄게 채워지는 속도 <3.4s
최초 입력 지연 (FID, First Input Delay) 사용 가능 여부, 중요함 사용자가 상호작용을 한 후 웹 브라우저가 상호작용을 처리할 때까지 걸리는 시간 <100ms
최초 잠재적 첫번째 입력 지연 (mFID, Max Potential First Input Delay) 사용 가능 여부 가장 긴 작업의 지속 시간을 기반으로 가능한 최대 첫번째 입력 지연 <130ms
총 차단시간 (TBT, Total Blocking Time) 사용 가능 여부 메인 스레드가 입력 응답을 막을만큼 차단했을 때 FCP와 TTI 사이의 총 시간 <200ms
상호작용 까지의 시간 (TTI, Time to Interactive) 사용 가능 여부 사용자 입력에 안정적으로 응답할 때까지 걸리는 시간 <3.8s
누적 레이아웃 변경 (CLS, Cumulative Layout Shift) 쾌적함, 중요함 컨텐츠가 동적으로 크기 조정을 할 때 엔드유저가 예기치 않은 레이아웃 이동(변화)의 누적 점수 <0.1
프레임 레이트 (FR, Frame Rate) 쾌적함 1초에 보여주는 화면의 수 60 FPS

분류는 다음과 같다.

  • 진행여부: 서버에서 응답되는지
  • 유용성: 사용자가 볼 수 있는 컨텐츠가 렌더링되는지
  • 사용 가능 여부: 사용자가 페이지와 상호 작용할 수 있는지
  • 쾌적함: 상호작용이 부드럽고 자연스러우며, 지연과 버벅임이 없는지

 

참고

이 글을 쓸때 참고한 목록들입니다.

구글

 

야후

 

TOAST UI

 

 

MDN

 

 

기타

 

 

Other Platform