공부/CS

[CS] 웹 성능최적화 (2), Lighthouse

youngble 2023. 1. 4. 00:33

순서

1. Lighthouse 설명

- First Contentful Paint, FCP

- Speed Index, SI

- Largest Contentful Paint, LCP

- Time To Interactive, TTI

- Total Blocking Time, TBT

- Cumulative Layout Shift, CLS


이전글 웹 성능최적화 (1) 보러가기

1.  Lighthouse 설명

웹 페이지의 종합 성능을 측정하는 툴로써 이전에는 따로 프로그램을 다운로드하여 사용해야했지만 이후에 구글 크롬은 브라우저에 기본내장하여 사용할 수 있도록 했다. Lighthouse를 통해 성능 점수를 매길때 6개의 지표(Metrics)가 있다. 또한 이러한 지표를 웹 바이탈(Web Vitals)이라고 한다.

 

First Contentful Paint

First Contentful Paint, FCP는 페이지가 로드될때 브라우저가 DOM 콘텐츠의 첫번째 부분을 렌더링하는데 걸리는 시간에 관한 지표이다. 위의 결과를 토대로 본다면 페이지에 들어와 첫 콘텐츠가 뜨기까지 1.4초가 걸린 것이다. FCP에 대한 가중치는 전체의 10%를 가진다.

 

Speed Index

Speed Index, SI는 페이지가 로드 중에 콘텐츠가 시각적으로 표시되는 속도를 나타내느 지표이다. 단순히 콘텐츠가 화면에 모두 뜨는 시간이라기 보단 같은 시간이라도 전체페이지에저 일부의 컨텐츠가 언제 뜨는지에 따라 측정 속도가 다르다고 볼수 있다. 아래 그림을 통해 더 자세히 이해해보자.

A와 B라는 페이지에서 콘텐츠가 모두 렌더링하여 화면에 보여주는데 걸리는시간은 4초이다. 하지만 A는 B보다 일부 콘텐츠가 먼저 떴다. 이럴경우 SI는 A페이지가 B페이지보다 더 빨리 로드된 것으로 계산되고 더 높은 점수를 준다. SI에 대한 가중치는 전체의 10%를 가진다.

 

Largest Contentful Paint

Largest Contentful Paint, LCP는 페이지가 로드될때 화면내에서 가장 큰 이미지나 텍스트 요소가 렌더링되기까지 걸리는 시간을 나타내는 지표이다. 위의 계산결과에서는 2.1초가 걸렸다. LCP는 전체 가중치의 25%를 갖는다. 이 LCP 시간과 FCP나 다른 컨텐츠가 화면에 뜨는데 걸리는 시간과 헷갈릴수도 있는데, 경험해보았다면 알수 있듯이 모든 렌더링 컨텐츠가 뜨더래도 이미지가 나중에 뜨는걸 본적이 있을 것이다. 그것이 이경우에 해당한다고 생각하면 된다. 아래의 그림을 보면 이해하기 쉽다. 참고 

위의 경우처럼 FCP가 발생하고 나머지 렌더링 완료된 부분들을 화면에 보여주고 마지막에 LCP의 이미지가 뜨는걸 확인할 수 있다. 또한  다음 아래와 같이 이미지가 뜨기전과 후의 화면 구조가 밀리는 현상도 확인 될때도 있다.

 

Time To Interactive

Time To Interactive, TTI사용자가 페이지와 상호 작용이 가능한 시점까지 걸리는 시간을 측정하는 지표이다. 즉, 렌더링이 완료하여 브라우저에 컨텐츠가 보이더래도 TTI가 완료되지 않았다면 클릭, 키보드 누름과같은 사용자 입력 Event를 사용할려고해도 아무 동작도 안하게 된다. TTI는 전체 가중치의 10%를 갖는다.

 

위의 사진들을 통해 어느 타임라인에서 TTI로 결정되는지 알 수 있다. 참고

TTI를 간략하게 말하면 FCP가 시작되고 조용한 구간(idle window)이 시작하기전의 마지막 long task가 끝나는 시점까지의 소요한 시간이라 생각하면된다.

 

TTI로 측정되는 시간은 FCP가 시작하는곳에서부터 긴 작업, long task(50ms 이상)이 없고(CPU Idle) 전송 중 네트워크 GET 요청이 2개 미만인 기간을 갖는 구간(Network Idle)이 최소 5초정도인 부분(5 sec idle window)을 찾고 그 찾은 부분에서 역방향으로 검색하여 마지막 긴 작업, long task 부분까지의 기간을 측정한다. 만약 긴 작업이 없거나 발견되지 않으면 FCP와 동일한 시간으로 측정된다. 위의 타임라인처럼 A,B,C,D 라는 Js 파일들이 있지만 A와 C만 50ms를 초과하고 B, D는 50ms를 초과하지않기 때문에 end Navigation의 5초의 조용한 구간(idle)에서 역방향으로 검색하여 long task인 C를 찾고 C task가 끝나는 시점까지를 TTI로 측정한 것이다.

 

TTI 주의사항

TTV라고 하여 Time To View(대략 FCP라고 생각, 페이지에서 컨텐츠가 사용자에게 보일때)와 TTI 사이의 공백기간이 있을때 해당 페이지를 이용하는 사용자에게는 그 공백기간이 무엇인지 모르기때문에 페이지 상호작용이 안된다면 페이지의 응답속도가 느리다고 짜증이날 수 있고 최악의 경우는 해당 페이지에 문제가 있다고하여 아예 떠나버리는 이탈이 생길 수 있다. 심지어 해당 사이트의 브랜드 가치의 신뢰 또한 잃어버릴 수 있다

따라서 이러한 문제를 피하기위해 FCP와 TTI 사이 차이를 최소화하기 위한 노력이 필요하다.

 

CSR방식과 SSR 방식에 따른 TTV 와 TTI 타임라인

CSR방식과 SSR 방식에 따라 TTV와 TTI 사이의 시간도 달라진다.

 

CSR 타임라인

CSR의 경우 TTV와 TTI가 같다. 대표적으로 React를 사용하여 CSR방식으로 페이지를 로드한다고 할때 다음과 같은 타임라인을 갖기 때문이다.

해당 페이지가 보이기까지의 순서는 이전의 렌더링과정에 대한 포스트를 보면 좀더 이해하기 쉬울것이다. 브라우저 렌더링 과정

사이트에 접속하고 서버에서 Index.html 파일을 받아온다. 이때 화면상 아무것도없는 텅비어있는 파일이기 때문에 사용자에게 흰화면만 보인다. 이후 index.html에 링크된 모든 로직이 있는 자바스크립트를 받아오고 동적으로 html을 생성할 수 있는 js를 받아온다. 이때부터 웹사이트가 보이게 되고 상호작용이 가능하게 된다-> TTV = TTI

 

SSR 타임라인

반면 SS방식의 경우는 TTV와 TTI사이에 공백이 발생한다. 먼저 사이트에 접속하게 되면 서버에 요청하여 해당페이지의 이미 만들어진 index파일을 받아와서 빠르게 사용자에게 보여줄수 있도록해준다-> TTV 발생. 하지만 이때부터 사용자가 상호작용을 위한 클릭, 입력등을 하여도 아무 반응을 하지 않는다. 그리고 나서 서버에서 해당 페이지와 연관된 JS를 받아오고 처리한후 사용자가 상호작용이 가능하게 된다-> TTI, TTI-TTV>0 (공백시간)

 

따라서 CSR의 경우는 한번에 다운로드하는 리소스들에 대해서 분할하여 첫번째로 사용자가 페이지를 보기위한 시간을 줄이도록 노력해야하고 SSR의 경우는 사용자가 페이지에 대한 인터렉션이 발생하기까지의 시간을 줄이도록 노력해야한다.

 

Total Blocking Time

Total Blocking Time, TBT는 페이지가 클릭, 키보드 입력 등의 사용자 인터렉션에 응답하지 않도록 차단된 시간을 총합한 지표이다. TBT의 중치는 전체의 30%를 갖는만큼 큰 비중을 차지한다. 이해가 잘안되기 때문에 아래 좀더 자세히 설명하고자한다.

위의 사진을 보면 FCP가 시작된 이후long task를 가진 JS를 메인스레드에서 작업할때 long task를 작업하는 동안 interactive 상호작용이 발생하게되면 반응하지 않기 때문에 blocking time이 생긴다. 위의 TTI를 설명할때 long task로 잡는 기준은 50ms초과하는지 안하는지로 측정하게 되는데 blocking time의 경우는 이러한 long task가 메인 스레드에서 작업하는 동안에는 인터렉티브가 발생하지 않기 때문에 50ms를 제외한 나머지 task 걸리는 시간을 의미하는 것이다. 그리고 이러한 blocking time을 갖는 long task들이 여러개 이기때문에 모두 더한게 Total Blocking time, TBT가 되는것이다. 

좀더 정확하게 측정하는 방법은 long task가 50ms 이상일때 50ms를 제외하고 나머지 ms시간을 blocking period로 측정하면된다.

예를들어 한 페이지에서 Long task가 위와같이 2개 있다고 가정해보자. 한 task는 총 120ms가 걸리고 다른하나는 75ms가 걸린다. 이럴때 각각의 task의 50ms를 제외하고 나머지 시간을 더하면 70ms + 25ms이기 때문에 TBT는 95ms라고 한다.

 

Cumulative Layout Shift

Cumulative Layout Shift, CLS는 페이지 로드 과정에 발생하는 예기치 못한 가장큰 레이아웃 이동을 측정한 지표이다. 전체의 15%의 가중치를 가진다.

Layout Shift Score = impact fraction(영향분율) * distance fraction(거리분율)

위의 gif그림을 통해서 어떤상황의 문제점을 나타내는지 보여준다. 위의 사진처럼 상단에 느린 로딩 광고가 있다고 할때, 텍스트 부분을 먼저 읽고 있었고 "No, go back" 버튼을 눌러 주문하지않고 뒤로 갈려고 한다고 생각해보자. 누르는 순간 layout shift가 발생하면서 느리게 로딩된 광고가 해당 컨텐츠들을 아래로 밀면서 레이아웃이 밀렸다. 이렇게되면서 돌아가려고 클릭했던 이전 버튼뿐만아니라  주문 버튼도 밀리면서  "Yes, place my order"를 누르게 되어 원하지 않는 주문을 하게 되는 현상이다.

CLS의 원인

1. 크기가 정해지지 않은 이미지

2. 크기가 정해지지 않은 광고, 임배드 및 iframe

3. 동적으로 주입된 컨텐츠

4. FOIT/FOUT을 유발하는 웹 글꼴

5. DOM을 업데이트하기 전에 네트워크 응답을 대기하는 작업

 

CLS 개선방법

1. 이미지 및 비디오 요소에 항상 크기 속성을 포함하거나 CSS 가로 세로 비율상자와 같은 방식으로 필요한 공간을 미리 확보한다. width와 height 크기 속성을 주는것이다.

2. 사용자 상호 작용에 대한 응답을 제외하고는 기존 컨텐츠 위에 컨텐츠를 삽입하지 않는다. 그러면 느리게 로딩되면서 밀리는 현상은 없기 때문이다.

3. 동적으로 주입된 컨텐츠에 대하여 스켈레톤 UI를 사용한다.