웹 사이트 성능을 개선하는 기본적인 방법

1. HTTP 요청 수 줄이기

1 - 1. 스크립트 파일 병합

여러 개로 나뉜 JS 파일을 하나로 병합하여 사용한다. 이는 요청을 줄일 뿐더러, 인터넷 상 프록시나 브라우저에 캐시될 확률을 좀 더 높인다.

1 - 2. 인라인 이미지

이미지 파일을 따로 호출하여 받아오는 대신, base64 등을 이용해 이미지를 인라인으로 삽입하는 방식이다. 다만, 이 경우 이미지 파일 자체는 인터넷이나 브라우저를 통해 캐시되지 않으므로, 무조건적인 성능 향상을 보장하진 않기 때문에, 선택적으로 사용해야 한다.

1- 3. CSS 스프라이트

여러 이미지를 하나의 이미지로 결합해, 필요한 이미지가 위치한 픽셀 좌표 정보를 사용해 필요한 이미지만 가져다 사용하는 방식이다. 주로 아이콘이나 버튼 같은 작은 이미지를 사용할 때 유용하다.

2. 콘텐츠 파일 크기 줄이기

2 - 1. 스크립트 파일 압축 전달

HTTP 프로토콜은 Accept-Encoding, Content-Encoding 헤더를 사용해 파일 압축 방식의 정보 교환을 지원한다. 요청 헤더는 Accept-Encoding, 응답 헤더는 Content-Encoding을 사용한다.

// 클라이언트 요청 헤더
Accept-Encoding: gzip, deflate, sdch

// 웹 서버의 응답 헤더
Content-Encoding: gzip

2 - 2. 스크립트 파일 최소화

HTML, CSS, JS 파일 내 실제 로직에는 아무 영향을 주지 않는 부분을 제거하거나, 간소화시켜 파일을 최소화하는 방법이다.

2 - 3. 이미지 파일 압축

tinyPNG 등의 서비스를 사용하여 손실 압축 방식으로 이미지 파일을 압축할 수 있다.

2 - 4. 브라우저가 선호하는 이미지 포맷 사용

  • 구글 - WebP
  • 마이크로소프트 - JPEG XR

2 - 5. 큰 파일은 작게 나누어 전송

몇 GB에 해당하는 동영상 파일을 웹 사이트에 삽입했다고 하는 경우, 해당 파일을 한꺼번에 가져오는 것은 버퍼링을 유발할 수도 있고, 실제로 보지 않을 부분까지 가져올 가능성도 있어 자원 낭비가 이루어진다.

이에 부분 요청/응답을 수행할 수 있는데, 해당 기능의 지원 여부는 아래와 같이 웹 서버의 응답 헤더를 통해 확인할 수 있다.

curl -I http://www.example.com/bigfile.jpg

HTTP/1.1
// ...
Accept-Ranges: bytes
Content-Length: 50000000
  • Accept-Ranges: byte 단위로 파일의 부분 지원 기능을 수락한다는 의미.
  • Content-Length: 해당 파일의 전체 크기가 50MB라는 정보를 전달.

이 응답의 내용에 기반하여 클라이언트가 특정 부분을 요청할 수 있다.

curl -v http://www.example.com/bigfile.jpg -H "Range: bytes=0-1023"

HTTP/1.1 206 Partial Content
Content-Range: bytes 0-1023/50000000
Content-Length: 1024
  • Range: bytes=0-1023: 파일의 처음(0)부터 1023바이트까지만 요청
  • Content-Range: bytes 0-1023/50000000: 전체 파일 범위(50000000 중 처음부터 1023 바이트 까지만 전달한다는 의미
  • Content-Length: 1024: 현재 전달한 부분 파일의 전체 용량이 시작 위치와 끝 위치를 알려주는 데이터를 포함하여 1024 바이트임을 명시

이러한 요청을 여러 개의 범위를 갖는 것도 가능하다.

curl -v http://www.example.com/bigfile.jpg -H "Range: bytes=0-50, 100-150"

3. 캐시 최적화하기

3 - 1. 인터넷 캐시 사용

프록시 서버 - 서버와 클라이언트 간에 통신을 대신해주는 역할을 하는 서버

3 - 2. 브라우저 캐시 사용

웹 콘텐츠 중 일부를 클라이언트 측에 저장해 인터넷 상의 요청을 아예 수행하지 않도록 할 수 있다.

특정 콘첸츠를 브라우저에서 캐시하도록 하고, 얼마나 오랫동안 할 것인지에 대해 웹 서버는 Cache-Control 응답 헤더에 캐시 기간을 설정하여 클라이언트에게 전달한다. 해당 기간을 캐시의 생존 기간이라는 의미에서 TTL(Time To Live)이라고도 한다.

Cache-Control: max-age=3600 // 1시간

Cache-Control의 설정값에는 다음과 같은 것들이 있다.

  • no-store: 브라우저가 캐시하지 않도록 설정함(ex. 민감 정보 등 절대 캐시해선 안되는 콘텐츠)
  • no-cache: 브라우저 캐시를 사용하되, 원본 서버의 콘텐츠 갱신 여부를 미리 조사해 변경이 없을 때만 캐시 콘텐츠를 사용
  • must-revalidate: 캐시 사용 전 웹 서버에서 설정한 캐시 가능 주기를 먼저 확인하여 해당 시간 범위 내에서만 캐시를 사용
  • public: 해당 콘텐츠를 명확히 캐시할 수 있음

반면, 콘텐츠를 특정 날짜의 특정 시간까지, datetime의 형태로 설정하고자 하는 경우에는 Expires 응답 헤더를 사용한다.

Expires: Mon, 30 Nov 2020 07:00:00 GMT

4. CDN 사용하기

CDN(Content Delivery Network): 인터넷 상에서 생산/소비되는 웹 콘텐츠를 사용자에게 빠르게 전달하기 위해 대용량 인터넷 캐시 영역에 콘텐츠를 저장해 사용하는 네트워크 방식이다. 여러 개의 분산된 서버로 이루어져 있고, 원본 서버라 불리는 콘텐츠 서버와 사용자 사이에서 프록시 역할을 한다.

CDN을 사용하면 다음과 같은 장점을 얻을 수 있다.

  1. 인터넷 상 원거리에 있는 콘텐츠를 전달받는 과정에서 발생할 수 있는 네트워크 지연(network latency)와 패킷 손실(packet loss) 현상을 줄일 수 있다.
  2. 사용자는 가까운 에지 서버에 캐시된 콘텐츠를 전달받으므로, 전송에 필요한 RTT(Rount Trip Time)이 줄어들어 빠르게 콘텐츠를 받을 수 있다.
  3. CDN의 에지 서버가 캐시된 콘텐츠를 전송하므로 원본 서버의 부하를 줄일 수 있다.
  4. 콘텐츠가 에지 서버와 주변 에지 서버 사이에 ICP(Internet Cache Protocol)를 이용한 서버 전파를 할 수 있어 캐시 콘텐츠의 재사용률이 매우 높다.
  5. CDN 서비스들은 사용자 요청 트래픽이나 기술적 특이 사항을 모니터링하는 시스템을 갖추고 있어 인터넷 전송이 필요한 콘텐츠의 시스템과 인적 관리 비용이 절감된다.