주소창에 www.naver.com을 입력하고 사용자에게 네이버 페이지가 보이기까지의 과정

최윤석·2023년 2월 20일
3

CS

목록 보기
1/3

⭐포스팅 목표

F-Lab 멘토링 중 포스팅 제목의 질문을 받았다.

과거 면접 준비 당시 일련의 과정을 이해없이 암기하였지만 해당 포스팅을 통해 이해를 기반으로 내용을 정리한다.

단순 데이터 통신에서 그치지 않고 프론트엔드 개발자의 관점에서 데이터를 받아온 후 사용자의 화면에 렌더링 되기까지의 과정을 자세하게 알아본다.

데이터 통신

0. 주소창에 www.naver.com을 입력한다.

1. 웹 브라우저는 입력된 텍스트를 확인한다.

주소창에 텍스트를 입력하면 웹브라우저는 텍스트검색어인지 URL인지 확인한다.

만약 입력된 텍스트가 검색어이면 검색 엔진의 URL검색어를 포함하여 이동시킨다.

입력된 텍스트가 URL이면 DNS서버naver.com의 주소를 요청할 준비를 한다.

2. 캐싱된 DNS 기록을 확인한다.

만약 도메인 이름에 맞는 IP 주소가 존재하면, 캐싱된 IP 주소를 반환한다.

일치하는 IP 주소가 없다면 DNS server에 요청을 보낸다.

DNS 기록을 캐싱하는 이유

만약 새로운 웹사이트 요청이 들어올때마다 DNS서버에 요청을 보낸다면 웹브라우저는 매번 resolver에게 요청을 보내고, resolver에서 root server, root server에서 TLD server에 요청을 보내는 과정이 필요하다.
따라서 웹사이트 요청마다 매번 DNS서버와의 통신 과정을 반복한다면 속도는 당연히 더 느려질 것이고 DNS서버에 병목현상이 발생할 수 있다.
병목 현상을 방지하고 반복을 막기위해 OS웹브라우저는 검색된적 있는 DNS 기록을 캐싱한다.

OS에 저장된 DNS Cache 목록은 cmd에서 ipconfig/displaydns를 입력하면 조회할 수 있다.

브라우저에 저장된 DNS Cache 목록은 chrome://net-internals/?#dns를 검색하면 조회할 수 있다.

DNS Cache는 영구적으로 저장되지 않으며, TTLDNS Query를 저장하는 기간을 의미한다.

DNS CachingOS브라우저 단계에서만 일어나지 않는다.

새로운 웹사이트 요청이 들어오면 DNS가 조회되는 동안 resolver, root server, TLD server를 거치고 각 단계에서 정보가 수집되고 캐시된다.

따라서 local DNS cache가 비어있더라도 resolver는 모든 DNS조회 과정을 거칠 필요가 없을 수 있다.

resolver란?

resolver는 웹 브라우저와 같이 DNS 클라이언트의 요청을 네임 서버로 전달하고 네임 서버로부터 정보를 받아 클라이언트에 제공하는 기능을 수행한다.
일반적으로 모든 기능을 PC와 같은 클라이언트 호스트에 구현하는 것은 제약이 있기 때문에 resolver의 대부분의 기능은 local DNS server에 구현한다.

참고자료
DNS cache
https://www.keycdn.com/support/dns-cache

3. DNS server에 IP주소를 요청한다.

브라우저는 ISP(인터넷 서비스 제공자)를 통해 DNS query를 전달한다.

먼저 local DNS에 문의한 www.naver.comIP주소를 문의한다.

만약 local DNSwww.naver.comIP주소가 없다면 root DNS를 시작으로 원하는 IP주소를 찾을때까지 도메인의 뒤에서부터 재귀적 탐색을 반복한다.

이 과정을 Recursive Query라고 부른다.

탐색순서

. (root DNS) => com (TLD DNS) => naver.com (SLD DNS)

ISP란?

KT, SK브로드밴드, LG유플러스 등과 같이 인터넷 서비스를 제공하는 업체를 ISP라 한다.

DNS 계층 예시

참고자료
Recursive Query
https://www.netmanias.com/ko/post/blog/5353/dns/dns-basic-operation
DNS 계층
https://peemangit.tistory.com/52

4. 응답받은 IP주소를 이용하여 HTML문서 요청

웹 브라우저는 응답받은 www.naver.comIP주소를 사용하여 네이버 서버에 HTML파일을 요청하는 HTTP Request를 보낸다.

이때, TCP/IP 프로토콜을 사용하여 서버와 통신한다.

HTTP Request란?

HTTP Method(GET, PUT, POST 등)을 사용하여 클라이언트에서 서버로 전송하는 메시지이다.

TCP/IP 프로토콜이란?

TCP/IP프로토콜은 Transmission Control ProtocolInternet Protoco의 조합으로 이루어져있다.
TCP프로토콜은 연결 지향적 프로토콜로 데이터 전송 과정에서 데이터의 무손실 전송을 보장하고, 패킷의 순서를 보장하며 오류가 발생하면 재전송을 시도함으로써 신뢰성 있는 데이터 전송을 보장한다.
IP프로토콜은 비연결형 프로토콜로, 데이터 전송 과정에서 패킷의 라우팅을 담당한다.
신뢰성과 연결성을 위해 대부분의 인터넷 서비스는 TCP/IP 프로토콜을 사용한다.
3-way handshake를 사용해 연결하며 4-way handshake를 사용하여 연결을 종료한다.

DNS서버와 통신할때는 어떤 프로토콜을 사용할까?

DNS서버와 통싱할때에는 TCP/IP프로토콜을 사용하지 않고 UDP프로토콜을 사용한다.
UDPTCP보다 빠르며 대부분의 DNS요청은 크기가 매우 작다. (UDP 제한 : 512bit 이하)
또한, UDP는 연결을 유지하지 않으므로 DNS서버의 부하를 줄일 수 있기때문에 UDP를 사용한다.

5. 웹 서버는 WAS와의 상호작용을 통해 컨텐츠를 생성한다.

웹 서버는 정적 컨텐츠(ex. HTML, CSS, JS 등)를 제공하는 서버이다.

WAS(웹 어플링케이션 서버)는 동적 컨텐츠(ex. 페이지 생성, 비즈니스 로직 처리, DB 접근 등)을 처리하는 서버이다.

WAS만으로도 웹 서버의 기능을 구현할 수 있지만 트래픽 분산 및 보안 등의 이유로 웹 서버와 WAS를 함께 사용한다.

흔히 말하는 프론트 서버를 웹서버, 백엔드 서버를 WAS라고 볼 수 있다.

BFF

하지만, 프론트엔드 개발자가 Web Server만 다루는 것은 아니며, BFF(Backend for Frontend)등을 다루는 경우 Web Server뿐만 아니라 WAS를 함께 관리하고 다룬다.
BFF는 주로 MSA와 함께 사용되는 개념으로 프론트엔드를 요구사항에 맞게 구현하기 위한 도움을 주는 보조 서버의 의미를 갖는다.

6. 생성된 컨텐츠를 요청한 웹 브라우저(클라이언트)에게 전송한다.

웹 서버는 웹 브라우저에게 HTTP Response를 보낸다.

HTTP Responsestatus code를 포함한다.

주요 HTTP 상태 코드

1xx(정보) : 추가 정보가 있음을 전달합니다.
2xx(성공) : 서버가 요청을 처리했음을 전달합니다.
3xx(리다이렉트) : 다른 URI로 다시 리퀘스트하도록 요청합니다.
4xx(클라이언트 오류) : 요청에 문제가 있어 처리할 수 없음을 전달합니다.
5xx(서버 오류) : 서버 쪽에 문제가 있어 처리할 수 없음을 전달합니다.

참고자료
그림으로 배우는 네트워크 원리 p.105

⭐렌더링 과정

지금부터 다루는 내용은 렌더링 성능 최적화와 관련되며, 프론트엔드 개발자라면 지금부터의 내용이 매우 중요하다.

아래 그림은 브라우저의 렌더링 과정(critical rendering path)에 대해 간략하게 표현한 것이다.

참고자료
브라우저 동작 원리
https://poiemaweb.com/js-browser

7. 브라우저의 렌더링 엔진은 HTML을 파싱하고 DOM을 생성한다.

브라우저는 바이트형식으로 응답받은 데이터를 문자열로 변환한다.

이후 렌더링 엔진은 문자열을 한 줄씩 순차적으로 파싱하며 아래 단계를 거친다.

  1. 변환된 문자열을 문법적 의미를 갖는 최소 단위인 토큰들로 분해한다.

  2. 토큰을 객체로 변환하여 노드를 생성한다.

  3. 생성된 노드 객체를 트리 자료구조로 구성한다. (비동기 실행)

이때, 이 노드들로 구성된 트리 자료구조를 DOM(Document Object Model)이라 한다.

만약 파싱 과정에서 CSS를 로드하는 link태그나 style 태그를 만나면 CSS를 파싱하고 CSSOM 생성을 시작한다.

DOM 생성과 CSSOM 생성은 병렬적으로 실행된다.

만약 파싱 과정에서 <script> 태그를 만나면 DOM 생성이 중단되고 자바스크립트를 파싱하고 실행한다.

노드의 종류

노드 객체는 총 12개의 종류가 있다.
그 중 문서 노드, 요소 노드, 어트리뷰트 노드, 텍스트 노드를 주의깊게 보자.

렌더링 엔진이 아래 코드를 파싱하는 과정은 다음과 같다.

<html>
  <body>
    Hello world
  </body>
</html>

html 토큰 생성 -> HTMLHtmlElement 노드 생성 -> DOM트리에 HTMLHtmlElement 노드 추가 -> HTMLHeadElement 노드 생성 -> DOM트리에 HTMLHeadElement 노드 추가 -> body토큰 생성 -> HTMLBodyElement 노드 생성 -> DOM트리에 HTMLBodyElement 노드 추가 -> Hello world 토큰 생성 -> 텍스트 노드생성 -> DOM트리에 body 노드의 자식으로 텍스트 노드삽입 -> 종료

8. CSS를 파싱하고 CSSOM을 생성한다.

DOM생성과 같은 과정을 반복하여 CSSOM을 생성한다.

CSSOMCSS의 상속을 반영하여 생성한다.

아래 코드에서 렌더링 엔진이 link태그를 만나면 브라우저는 웹 서버에 CSS 파일을 요청하고 이후 CSS코드를 파싱하여 CSSOM을 생성한다.
이떄 브라우저의 렌더링 엔진은 CSSOM의 생성을 다른 스레드에 올려 DOMCSSOM의 생성을 병렬적으로 실행한다.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="style.css">
  </head>
<body>
  <ul>
    <li id="apple">Apple</li>
    <li id="banana">Banana</li>
    <li id="orange">Orange</li>
  </ul>
  <script src="app.js"></script>
</body>
</html>

9. 자바스크립트 파싱하고 실행한다.

렌더링 엔진이 HTML을 파싱하던 중 <script>태그를 만나면 HTML 파싱을 중단하고 자바스크립트를 파싱 및 실행한다.

이때 렌더링 엔진에서 자바스크립트 엔진으로 제어권이 넘어가며 자바스크립트 엔진은 코드를 해석하여 AST(추상적 구문 트리)를 생성한다.

<script> 태그의 위치

렌더링 엔진이 <script>태그를 만나면 HTML파싱이 중단된다.
<script> 태그의 위치에 따라 사용자가 보는 화면의 렌더링 시간이 달라질 수 있으며, DOM이 완성되지 않은 상태에서 DOM을 직접 조작하는 경우 에러가 발생할 수 있다.
따라서 이러한 에러를 방지하고 페이지 로딩 시간을 단축시키기 위해서는 <script>태그를 <body>태그의 가장 아래에 위치시키는 것이 좋다.
또는 asyncdefer키워드를 사용하여 비동기 처리를 할 수 있다.
단, asyncdefer키워드는 외부 자바스크립트 파일을 로드하는 경우에만 사용가능하다.

참고자료
async, defer
https://www.growingwiththeweb.com/2014/02/async-vs-defer-attributes.html

10. 렌더 트리(Render Tree)를 생성한다

DOMCSSOM가 완성되면 이 둘을 결합하여 렌더 트리를 생성한다.

만약 둘 중 하나만 완성된 경우, 둘다 완성 될때까지 기다렸다가 렌더 트리를 생성한다.

렌더 트리는 브라우저의 화면에 렌더링 되지 않는 노드(meta 태그, script태그 등)와 display : none으로 설정된 노드들은 포함하지 않는다.

display : none   vs   visibility : hidden

display : none으로 설정된 노드는 렌더트리에서 제외되고 화면에 보이지 않는다.
visibility : hidden으로 설정된 노드는 렌더트리에는 포함되어 공간을 차지하지만 보이지 않는다.
display : none으로 설정한 경우 display : block등으로 변경하면 ReflowRepaint가 모두 발생한다.
visibility : hidden으로 설정한 경우에는 Repaint만 발생한다.
따라서 렌더링이 불필요한 노드는 display : none으로 설정하여 성능을 올릴 수 있다.
display : nonevisibility : hidden 모두 스크린 리더가 읽지 않는다.

11. 레이아웃(Layout)을 계산한다.

완성된 렌더 트리를 기반으로 HTML요소의 레이아웃을 픽셀단위로 계산하여 렌더트리에 반영한다.

12. 화면에 페인팅(Painting)한다

렌더 트리의 각 노드가 텍스트, 색, 이미지 등 브라우저 창에 보이는 모든 것을 포함하여 화면에 픽셀을 렌더링한다.

13. 사용자의 브라우저에 네이버 화면이 렌더링된다.

렌더링 이후 UI가 업데이트 된다면?

1. Reflow

레이아웃을 다시 계산하는 것을 말한다.

노드 추가/삭제, 요소의 크기/위치 변경, 윈도우 리사이징 등 레이아웃에 영향을 주는 변경이 발생한 경우에 한하여 실행된다.

2. Repaint

재결합된 렌더 트리를 기반으로 다시 페인트하는 것을 말한다.

배경 이미지나 텍스트 색상, 그림자 등 레이아웃의 수치를 변화시키지 않는 스타일의 변경이 일어났을 때 실행된다.

3. Composite

레이아웃과 페인트를 수행하지 않고 레이어의 합성만 발생할 때 실행된다.

렌더링 성능을 최적화 하는 방법

Reflow가 최소한으로 발생하도록 개발해야한다.

https://csstriggers.com 에서 레이아웃, 페인트, 컴포지트를 발생시키는 CSS 요소를 확인할 수 있다.

참고자료
https://web.dev/rendering-performance/

profile
프론트엔드를 공부하고 있는 주니어 개발자입니다.

0개의 댓글