웹 최적화
1. 웹 최적화란
1 - 1. 프런트엔드 최적화
- 스크립트를 병합하여 브라우저의 호출 개수를 줄임
- 스크립트 크기를 최소화하여 바이트 자체를 줄임
- 스크립트를 gzip 등으로 압축하여 전달
- WebP 등으로 브라우저 이미지 형식을 최적화
- 이미지 손실, 무손실 압축
- Cache-Control 응답 헤더를 통해 브라우저 캐시를 충실히 사용
- 도메인 수를 줄여 DNS 조회를 최소화
- DNS 정보 미리 읽어 오기
- CSS를 HTML 상단에, 자바스크립트를 HTML 하단에 위치시키기
- 페이지 미리 읽어오기 (page prefetching)
- 타사 스크립트가 웹 성능을 방해하지 않도록 조정
1 - 2. 백엔드 최적화
- DNS 응답이 빨라지도록 서버 증설
- DNS 응답을 빠르게 할 수 있도록 DNS 정보를 최대한 캐싱
- 웹 서버가 있는 데이터 센터의 네트워크 출력(throughput)/대역폭(bandwidth) 증설
- 웹 서버, 웹 애플리케이션 서버의 CPU/RAM 증설
- 프록시 서버를 설정하여 웹 콘텐츠를 캐싱
- CDN(Content Delivery Network)을 사용해 인터넷 상에 콘텐츠 캐싱
- 데이터베이스 정규화로 디스크 I/O 최적화
- 데이터베이스 캐싱으로 응답을 빠르게
- 로드 밸런싱을 통해 가장 성능이 좋은 웹 서버로 요청을 연결
- 웹 애플리케이션 로직을 가볍고 빠르게 개발
1 - 3. 프로토콜 최적화
- 웹 콘텐츠를 전달하는 HTTP/HTTPS 프로토콜 자체의 효과를 극대화
2. TCP/IP 프로토콜
TCP와 웹 성능도 밀접한 관련이 있어 TCP 성능이 나빠지는 웹 성능 역시 영향을 받는다.
- TCP 네트워크의 대표적인 성능 지표
- 대역폭(bandwidth): 특정 시간 동안 얼마나 많은 네트워크 트래픽을 보낼 수 있는지?
- 지연 시간(latency): 클라이언트 - 서버 간 콘텐츠 전달에 얼마만큼의 시간이 걸리는지?
2 - 1. TCP 혼잡 제어 (TCP congestion control)
TCP 혼잡 붕괴 (TCP congestion collapse): TCP 통신량이 실제 처리량보다 많아 문제가 발생하는 것
패킷을 보내는 쪽에서 네트워크에서 수용 가능한 양을 파악해 그 만큼의 패킷을 보내는 약속으로 TCP혼잡을 해결한다.
받는 쪽에서 패킷이 정상적으로 송신되었음을 알리는 ACK 패킷을 보내고, ACK 패킷을 받은 호스트에서는 지속적으로 패킷을 보낼 수 있다.
느린 시작 (slow start)
TCP 연결 시작 시 전송 가능한 버퍼 양인 혼잡 윈도우(Congestion Window, CWND)의 초깃값을 작게 설정하여 전송하고, 해당 패킷에 대한 ACK를 받으면, 처음 보낸 패킷의 2배에 해당하는 패킷을 전송한다. 이런 식으로 패킷 유실(packet drop)이 발생하여 적절한 혼잡 윈도우의 크기를 파악하기 전까지 반복한다.
빠른 재전송 (fast retransmit)
먼저 도착해야 할 패킷이 도착하지 않고 다음 패킷이 도착한 경우에도 수신자가 일단은 ACK 패킷을 보낸다. 중간에 패킷이 하나 손실되는 경우, 송신자가 중복된 ACK 패킷을 통해 이를 감지하고 전송되지 않은 패킷을 재전송한다. 중복된 패킷을 3개 받으면 반드시 손실된 패킷을 재전송하고, 동시에 혼잡 제어가 필요한 상황임을 인식해 혼잡 윈도우의 크기를 줄이는 작업도 수행한다.
흐름 제어 (flow control)
TCP 송신자가 데이터를 너무 빠르게 혹은 너무 많이 전송하여 수신자의 버퍼가 오버플로되는 현상을 방지하는 기술이다. 송신자가 데이터를 전송하는 속도를 애플리케이션 프로세스를 읽는 속도와 유사한 수준으로 만들어 트래픽 수신 속도를 송신 속도와 일치시킨다.
3. HTTP 프로토콜
웹은 HTTP 프로토콜을 통해 전달되므로, HTTP 성능의 개선 역시 웹 성능의 향상에 도움을 줄 수 있다.
3 - 1. HTTP 최적화 기술
HTTP/0.9 : 클라이언트 ~ 서버 간 인터넷 통신 정상화, 가용성, 신뢰성 등 기능에 초점
HTTP/1.0 : 클라이언트 ~ 서버 간 요청과 응답을 빠르게 할 수 있는 연구
HTTP/1.1 이후 : 멀티 호스트 기능과 클라이언트 ~ 서버 간 사이에서 TCP/IP 연결을 재사용하능 기능을 추가
3 - 2. HTTP 지속적 연결
3-way handshake: TCP 통신을 연결하는 방식으로, SYN, SYN-ACK, ACK
의 3번의 요청/응답으로 이루어짐.
HTTP 초기에서는 요청과 응답을 위해 이와 같은 방식으로 TCP 연결을 수행했으나, 매 요청과 응답 간에 TCP 연결을 맺고 끊는 것을 반복해야 했는데, 점차 웹 페이지에서는 많은 양의 웹 콘텐츠를 전달해야 했으므로, 이러한 방식에는 번거로움이 따랐다.
keep-alive 혹은 연결 재사용이라는 용어로 불리는 지속적 연결 방식은 클라이언트와 서버가 TCP 상에서 한번 연결되면 연결이 완전히 끊어지기 전까지 맺어진 연결을 지속적으로 재사용하는 기술이다. HTTP/1.0 기반에서 지속적 연결을 원하는 클아이언트가 해당 기능을 지원하는 웹 서버에 아래의 요청 헤더를 이용하여 지속적 연결을 요청할 수 있게 되었다.
Connection: keep-alive
HTTP/1.1 버전에서는 Connection 헤더를 사용하지 않아도 모든 요청과 응답이 이러한 지속적 연결을 기본으로 지원하며, HTTP 응답이 완료되거나 TCP 연결을 끊어야 하는 경우에만 이 Connection 헤더를 사용했다.
HTTP/2 버전은 단일 TCP 연결로 클라이어늩와 서버 사이 응답 지연 없이 스트림(stream) 형태로 다수의 HTTP 요청과 응답을 주고받을 수 있는 멀티플렉싱 기술의 토대를 만들었다. 즉, HTTP/2를 사용한다면 더 이상 지속적 연결에 대해 고민을 필요가 없어졌다.
3 - 3. HTTP 파이프라이닝
HTTP 파이프라이닝은 먼저 보낸 요청의 응답이 없어도 다음 요청을 병렬적으로 수신자 측에 전송하는 기술이다. 이는 기존의 선입선출(FIFO) 방식의 단점을 극복하기 위한 것으로, 중간에 응답 지연이 발생하더라도 클라이언트는 먼저 서버 측의 응답을 받을 수 있어 전반적으로 빠른 웹 로딩을 구현할 수 있다.
4. DNS
4 - 1. DNS 작동 원리
DNS는 인터넷 호스트명을 클라이언트와 서버가 이해할 수 있는 IP 주소로 변환해주는 시스템이다. DNS의 질의와 응답 성능이 나쁘면 웹 사이트 로딩에 영향을 줄 수 있다.
로컬 DNS 서버 -> 루트 DNS 서버 -> .com DNS 서버 -> example.com DNS 서버
4 - 2. 사용 중인 다양한 도메인 확인 방법
오픈소스 등으로 다양한 서비스들을 사용하게 되면서, 자신이 운영 중인 웹 서비스 도메인의 성능이 빠르다고 해서 DNS 조회 시에는 웹 성능에 문제가 업삳고 판단하기 어려워졌다. 이에 따라 특정 모듈 서비스의 DNS 조회가 불가능하거나 느리다면 해당 모듈을 자체 웹 서버에 업로드 후 제공하는 방법을 고려해야 한다.
4 - 3. 웹 성능을 최적화하는 도메인 운용 방법
직접 개발한 내부 서비스에 도메인 분할을 하고자 한다면 상위 도메인을 동일하게 해 DNS 질의를 최대한 적게 만들자.
HTML의 DNS 프리패치(prefetch) 기능을 사용하면 웹 페이지에 사용된 도메인들의 DNS를 조회하는 시간이 좀 더 빨라진다. 이는 웹 페이지를 여는 시점에 멀티스레드 방식으로 미리 DNS를 조회해 빠르게 IP 주소를 불러오도록 하는 기술이다.
<link rel="dns-prefetch" href="//img.feoorea.com" />
5. 브라우저
5 - 1. 네비게이션 타이밍 API
웹 사이트의 성능을 측정하는 데 사용할 수 있는 데이터를 Web API에서 제공한다. -> window.performance
5 - 2. 네비게이션 타이밍 속성
performance.timing은 페이지 요청 등의 탐색 이벤트 시간이나 DOM 로딩 시작 등의 페이지 로드 이벤트 시간을 파악하기 위해 사용할 수 있지만, 현 시점에서는 deprecated되고 있으므로, 이는 PerformanceNavigationTiming 인터페이스를 사용하는 것으로 대체되는 것이 좋겠다.