텍스트 기반 애셋의 인코딩 및 전송 크기 최적화

일리야 그리고릭
일리야 그리고릭

불필요한 리소스 다운로드를 제거한 후 페이지 로드 속도를 개선할 수 있는 가장 좋은 방법은 나머지 리소스를 최적화하고 압축하여 전체 다운로드 크기를 최소화하는 것입니다.

데이터 압축의 기초

사용하지 않는 리소스를 다운로드하지 않도록 웹사이트를 설정한 후 다음 단계는 브라우저에서 다운로드해야 하는 남은 사용 가능한 리소스를 압축하는 것입니다. 리소스 유형(텍스트, 이미지, 글꼴 등)에 따라 웹 서버에서 사용 설정할 수 있는 일반 도구, 특정 콘텐츠 유형에 대한 사전 처리 최적화, 개발자의 입력이 필요한 리소스별 최적화 등 다양한 기술 중에서 선택할 수 있습니다.

최상의 성능을 제공하려면 다음 기법을 모두 조합해야 합니다.

  • 압축은 더 적은 비트를 사용하여 정보를 인코딩하는 프로세스입니다.
  • 불필요한 데이터를 제거하면 항상 최상의 결과를 얻을 수 있습니다.
  • 다양한 압축 기술과 알고리즘이 있습니다.
  • 최상의 압축을 달성하려면 다양한 기술이 필요합니다.

데이터 크기를 줄이는 프로세스를 데이터 압축이라고 합니다. 많은 사람이 다양한 압축 알고리즘에 필요한 압축 비율, 압축 속도, 메모리를 개선하기 위해 알고리즘, 기술, 최적화에 기여했습니다.

데이터 압축에 대한 자세한 설명은 이 가이드에서 다루지 않습니다. 그러나 압축이 작동하는 방식과 페이지에 필요한 다양한 애셋의 크기를 줄이기 위해 사용할 수 있는 기법을 개략적으로 이해하는 것이 중요합니다.

이러한 기법의 핵심 원리를 설명하기 위해, 이 예에만 고안된 간단한 텍스트 메시지 형식을 최적화하는 프로세스를 생각해 보겠습니다.

# Below is a secret message, which consists of a set of headers in
# key-value format followed by a newline and the encrypted message.
format: secret-cipher
date: 08/25/16
AAAZZBBBBEEEMMM EEETTTAAA
  1. 메시지에는 '#' 접두사로 표시된 임의의 주석(주석이라고도 함)이 포함될 수 있습니다. 주석은 메시지의 의미나 메시지 동작에 영향을 주지 않습니다.
  2. 메시지에는 headers가 포함될 수 있습니다. 헤더는 메시지 시작 부분에 표시되는 키-값 쌍 (앞의 예에서는 ":"로 구분됨)입니다.
  3. 메시지는 텍스트 페이로드를 전달합니다.

200자(영문 기준)부터 시작하는 이전 메시지의 크기를 줄이려면 어떻게 해야 하나요?

  1. 주석은 흥미롭지만 메시지의 의미에는 영향을 주지 않습니다. 메시지를 전송할 때 이를 제거합니다.
  2. 헤더를 효율적으로 인코딩하는 데 유용한 기법이 있습니다. 예를 들어 모든 메시지에 '형식'과 '날짜'가 있다는 것을 알고 있다면 이러한 메시지를 짧은 정수 ID로 변환하여 전송할 수 있습니다. 하지만 그렇지 않을 수도 있으므로 지금은 그대로 두는 것이 좋습니다.
  3. 페이로드는 텍스트 전용입니다. 그 내용이 실제로 무엇인지는 모르지만 ("secret-cipher"를 사용하고 있음) 텍스트를 보기만 해도 텍스트에 많은 중복성이 있음을 알 수 있습니다. 아마도 반복되는 문자를 보내는 대신 반복되는 문자의 수를 세어 이를 더 효율적으로 인코딩할 수 있습니다. 예를 들어 "AAA"는 3개의 A 시퀀스를 나타내는 "3A"가 됩니다.

이러한 기법을 조합하면 다음과 같은 결과가 생성됩니다.

format: secret-cipher
date: 08/25/16
3A2Z4B3E3M 3E3T3A

새 메시지의 길이는 56자입니다. 즉, 원본 메시지를 72% 압축한 것입니다. 상당한 감소율입니다.

이는 압축 알고리즘이 텍스트 기반 리소스의 전송 크기를 줄이는 데 얼마나 효과적인지 보여주는 실제적인 예입니다. 실제로 압축 알고리즘은 이전 예시보다 훨씬 정교하며 웹에서는 압축 알고리즘을 사용하여 리소스의 다운로드 시간을 크게 줄일 수 있습니다. 텍스트 기반 애셋에 압축을 적용하면 웹페이지에서 리소스 로드 시간을 줄일 수 있으므로 사용자가 압축을 하지 않을 때보다 더 빨리 리소스의 효과를 확인할 수 있습니다.

압축: 사전 처리 및 상황별 최적화

여기에서 설명하는 첫 번째 기법은 축소입니다. 압축은 엄격히 압축 알고리즘이 아니지만 소스 코드에 사용되는 불필요하고 중복 문자를 제거하여 사람이 리소스를 더 쉽게 읽을 수 있도록 하는 방법입니다. 그러나 이러한 가독성은 프로덕션 웹사이트에서 해당 소스 코드의 기능을 유지하는 데 필요하지 않으며 웹에서 리소스 로드를 지연시킬 수 있습니다.

축소는 제공되는 리소스의 크기를 크게 줄일 수 있는 콘텐츠별 최적화 유형이며 최적화는 빌드 및 배포 프로세스의 일부로 가장 잘 적용됩니다. 예를 들어 번들러는 새로운 프로덕션 코드를 웹사이트에 배포하기 직전에 리소스를 자동으로 축소할 수 있는 흔히 사용되는 소프트웨어 유형입니다.

중복되거나 불필요한 데이터를 압축하는 가장 좋은 방법은 이를 제거하는 것입니다. 그러나 임의의 데이터만 삭제할 수는 없습니다. 그러나 데이터 형식과 그 속성에 관한 콘텐츠별 지식이 있는 일부 상황에서는 실제 의미나 기능에 영향을 주지 않고 페이로드의 크기를 크게 줄일 수 있습니다.

<html>
  <head>
    <style>
      /* awesome-container is only used on the landing page */
      .awesome-container {
        font-size: 120%;
      }

      .awesome-container {
        width: 50%;
      }
    </style>
  </head>
  <body>
    <!-- awesome container content: START -->
    <div>
      This is my awesome container, and it is <em>so</em> awesome.
    </div>
    <!-- awesome container content: END -->
    <script>
      awesomeAnalytics(); // Beacon conversion metrics
    </script>
  </body>
</html>

앞서 살펴본 HTML 스니펫과 이 스니펫에 포함된 3가지 콘텐츠 유형을 생각해 보세요.

  1. HTML 마크업
  2. 페이지의 프레젠테이션을 맞춤설정하는 CSS입니다.
  3. JavaScript로 상호작용 및 기타 고급 페이지 기능을 지원합니다.

이러한 각 콘텐츠 유형은 유효한 콘텐츠를 구성하는 항목에 관한 규칙, 주석 지정에 관한 규칙 등이 서로 다릅니다. 하지만 남아 있는 질문은 '이 페이지의 크기를 어떻게 줄일 수 있는가'입니다.

  • 코드 주석은 개발자에게 가장 좋은 방법이지만, 브라우저에는 코드 주석이 필요하지 않습니다. CSS (/* ... */), HTML (<!-- ... -->), 자바스크립트(// ...) 주석을 제거하면 페이지 및 하위 리소스의 총 전송 크기가 줄어듭니다.
  • '스마트한' CSS 압축 프로그램은 .awesome-container의 규칙을 정의하는 비효율적인 방법을 사용하고 있음을 알아차릴 수 있으며, 다른 스타일에 영향을 주지 않고 두 선언을 하나로 축소하여 더 많은 바이트를 절약할 수 있습니다. 많은 CSS 규칙에서 이러한 종류의 중복성을 제거하면 커질 수 있지만 선택기는 미디어 쿼리와 같은 다른 컨텍스트에서 반드시 중복되는 경우가 많으므로 적극적으로 적용할 수 있는 방법은 아닐 수 있습니다.
  • 공백과 탭은 HTML, CSS 및 JavaScript에서 개발자의 편의를 위해 제공됩니다. 추가 압축 프로그램을 사용하면 모든 탭과 공백을 제거할 수 있습니다. 다른 중복 삭제 기법과 달리 이러한 종류의 최적화는 페이지를 표시하는 데 이러한 공백이나 탭이 필요하지 않다면 상당히 적극적으로 적용할 수 있습니다. 예를 들어 HTML 문서에서 텍스트 실행 내에 공백을 보존하면 사용자가 실제로 보게 되는 콘텐츠의 가독성이 보장됩니다.
<html><head><style>.awesome-container{font-size:120%;width:50%}</style></head><body><div>This is my awesome container, and it is <em>so</em> awesome.</div><script>awesomeAnalytics()</script></body></html>

이전 단계를 적용하면 페이지가 516자에서 204자로 줄어들어 약 60%가 절약됩니다. 당연히 읽기는 어렵지만 사용하기 위해 필요하지는 않습니다. 또한 최신 개발 방식을 통해 형식이 올바르고 읽기 쉬운 버전의 소스 코드를 프로덕션에 제공하는 최적화된 코드와 분리할 수 있습니다. 변환된 프로덕션 코드를 읽을 수 있게 표시하는 소스 맵과 함께 사용하면 프로덕션의 버그 문제를 더 쉽게 해결할 수 있으며 사용자 환경을 위해 성능을 최적화하면서 우수한 개발자 환경을 누릴 수 있습니다.

앞의 예는 중요한 점을 보여줍니다. 즉, 임의의 텍스트를 압축하도록 설계된 범용 압축기는 이전 예에서 페이지를 꽤 잘 압축할 수 있지만 주석을 삭제하거나 CSS 규칙을 접거나 수십 개의 다른 콘텐츠별 최적화 작업을 수행할 수는 없습니다. 따라서 사전 처리, 축소, 기타 컨텍스트 인식 최적화가 중요합니다.

마찬가지로 위에서 설명한 기술은 텍스트 기반 애셋 이상으로 확장할 수 있습니다. 이미지, 동영상, 기타 콘텐츠 유형은 모두 고유한 형식의 메타데이터와 다양한 페이로드를 포함합니다. 예를 들어 카메라로 사진을 찍을 때마다 파일에 카메라 설정, 위치 등의 많은 추가 정보가 삽입됩니다. 애플리케이션에 따라 이 데이터는 중요할 수도 있고(예: 사진 공유 사이트) 전혀 쓸모가 없을 수도 있습니다. 삭제할 가치가 있는지 고려해야 합니다. 실제로 모든 이미지에 이 메타데이터로 인해 최대 수십 킬로바이트가 추가될 수 있습니다.

간단히 말해 애셋의 효율성을 최적화하기 위한 첫 번째 단계로 다양한 콘텐츠 유형의 인벤토리를 빌드하고 크기를 줄이기 위해 적용할 수 있는 콘텐츠별 최적화의 종류를 고려하세요. 그런 다음 적용할 수 있는 최적화 유형을 파악했다면 빌드 및 출시 단계에 이러한 최적화를 추가하여 자동화하여 프로덕션에 새 버전을 출시할 때마다 최적화가 일관되게 적용되도록 합니다.

압축 알고리즘을 사용한 텍스트 압축

텍스트 기반 애셋의 크기를 줄이는 다음 단계는 애셋 기반 애셋에 압축 알고리즘을 적용하는 것입니다. 이는 사용자에게 전송하기 전에 텍스트 기반 페이로드에서 반복 가능한 패턴을 적극적으로 검색하고 사용자의 브라우저에 도착하면 압축을 해제하는 방식으로 한 단계 더 발전했습니다. 그 결과 이러한 리소스가 더욱 크게 감소하고 다운로드 속도가 빨라집니다.

  • gzip 및 Brotli는 텍스트 기반 애셋(CSS, JavaScript, HTML)에서 가장 잘 작동하는 일반적으로 사용되는 압축 알고리즘입니다.
  • 모든 최신 브라우저는 gzip 및 Brotli 압축을 지원하며 Accept-Encoding HTTP 요청 헤더에서 둘 다 지원을 알립니다.
  • 압축을 사용할 수 있도록 서버를 구성해야 합니다. 웹 서버 소프트웨어는 기본적으로 모듈이 텍스트 기반 리소스를 압축하도록 하는 경우가 많습니다.
  • gzip과 Brotli를 모두 미세 조정하여 압축 수준을 조정하여 압축 비율을 개선할 수 있습니다. gzip의 경우 압축 설정 범위는 1~9이며 9가 가장 좋습니다. 브로틀리의 경우 이 범위는 0~11이며 11이 가장 좋습니다. 그러나 압축 설정이 높을수록 시간이 더 많이 필요합니다. 동적으로 압축된 리소스(즉, 요청 시)의 경우 범위 중간에 있는 설정이 압축 비율과 속도 간에 최적의 균형을 제공하는 경향이 있습니다. 하지만 정적 압축이 가능합니다. 즉, 응답이 미리 압축되므로 각 압축 알고리즘에 사용 가능한 가장 공격적인 압축 설정을 사용할 수 있습니다.
  • 콘텐츠 전송 네트워크 (CDN)는 일반적으로 자격을 갖춘 리소스의 자동 압축을 제공합니다. CDN은 동적 및 정적 압축을 관리할 수도 있으므로 압축과 관련된 걱정이 줄어듭니다.

gzipBrotli는 모든 바이트 스트림에 적용할 수 있는 일반적인 압축 프로그램입니다. 내부적으로는 파일의 이전에 검사한 내용의 일부를 기억한 후 효율적인 방법으로 중복된 데이터 프래그먼트를 찾아 바꾸려고 시도합니다.

실제로 gzip과 Brotli 모두 텍스트 기반 콘텐츠에서 가장 잘 작동하며 종종 더 큰 파일의 경우 70~90% 의 압축률을 달성합니다. 그러나 대체 알고리즘을 사용하여 이미 압축된 알고리즘 애셋(예: 무손실 또는 손실 압축 기법을 사용하는 대부분의 이미지 형식)을 실행해도 개선이 거의 또는 전혀 없습니다.

모든 최신 브라우저는 Accept-Encoding HTTP 요청 헤더에서 gzip 및 Brotli 지원을 알립니다. 하지만 클라이언트가 요청할 때 압축된 리소스를 제공하도록 웹 서버가 올바르게 구성되었는지 확인하는 것은 호스팅 업체의 책임입니다.

파일 알고리즘 압축되지 않은 크기 압축된 크기 압축비
angular-1.8.3.js 브로틀리 1,346 KiB 256 KiB 81%
angular-1.8.3.js gzip 1,346 KiB 329 KiB 76%
angular-1.8.3.min.js 브로틀리 173 KiB 53 KiB 69%
angular-1.8.3.min.js gzip 173 KiB 60 KiB 65%
jquery-3.7.1.js 브로틀리 302 KiB 69 KiB 77%
jquery-3.7.1.js gzip 302 KiB 83 KiB 73%
jquery-3.7.1.min.js 브로틀리 85 KiB 27 KiB 68%
jquery-3.7.1.min.js gzip 85 KiB 30 KiB 65%
lodash-4.17.21.js 브로틀리 531 KiB 73 KiB 86%
lodash-4.17.21.js gzip 531 KiB 94 KiB 82%
lodash-4.17.21.min.js 브로틀리 71 KiB 23 KiB 68%
lodash-4.17.21.min.js gzip 71 KiB 25 KiB 65%

위의 표는 몇 가지 잘 알려진 JavaScript 라이브러리에 Brotli와 gzip 압축을 모두 적용할 수 있는 경우의 절감 효과를 보여줍니다. 파일 및 알고리즘에 따라 절감되는 정도는 65~86%입니다. 참고로 Brotli와 gzip의 각 파일에 최대 압축 수준이 적용되었습니다. 가능하다면 gzip보다는 Brotli를 사용하세요.

압축 사용 설정은 구현하기에 가장 간단하고 효과적인 최적화 중 하나입니다. 웹사이트에서 이를 활용하지 않으면 사용자 실적을 개선할 수 있는 큰 기회를 놓치고 있는 것입니다. 다행히도 많은 웹 서버에서 이러한 중요한 최적화를 가능하게 하는 기본 구성을 제공하며, 특히 CDN은 압축 속도와 비율의 균형을 이루는 방식으로 이를 구현하는 데 매우 효과적입니다.

압축이 실제로 적용된 모습을 빠르게 확인하는 방법은 Chrome DevTools를 열고 Network 패널을 연 다음 선택한 페이지를 로드하고 네트워크 패널의 맨 아래를 관찰하는 것입니다.

DevTools의 실제 판독 및 전송 크기 비교
모든 페이지 리소스의 전송 크기 (즉, 압축된)와 Chrome DevTools의 네트워크 패널에 시각화된 실제 크기를 비교하여 나타냅니다.

이전 이미지와 같이 다음과 같은 분석 결과가 표시됩니다.

  • 요청 수(페이지에 로드된 리소스 수)
  • 모든 요청의 전송 크기입니다. 이는 페이지 리소스에 적용된 압축의 효과를 반영합니다.
  • 모든 요청의 리소스 크기입니다. 이는 압축이 해제된 페이지의 리소스 크기를 나타냅니다.

코어 웹 바이탈에 미치는 영향

이러한 개선사항을 반영하는 측정항목이 없으면 성능 개선사항을 측정할 수 없습니다. 코어 웹 바이탈 이니셔티브는 실제 사용자 환경을 반영하는 측정항목을 만들고 이에 관한 인지도를 높이기 위한 것입니다. 이는 단순한 페이지 로드 시간과 같이 사용자 환경 품질로 명확하게 변환되지 않는 측정항목과 대조됩니다.

이 가이드에 설명된 최적화를 웹사이트의 리소스에 적용하면 최적화된 리소스 및 관련 측정항목에 따라 코어 웹 바이탈에 미치는 영향이 달라질 수 있습니다. 하지만 다음과 같은 경우에는 이러한 최적화를 적용하면 웹사이트의 코어 웹 바이탈이 개선될 수 있습니다.

  • 축소 및 압축된 HTML 리소스는 HTML 로드 및 하위 리소스의 검색 가능성을 향상할 수 있으므로 하위 리소스의 로드를 개선할 수 있습니다. 이 방법은 페이지의 콘텐츠가 포함된 최대 페인트(LCP) 문제를 해결하는 데 유용할 수 있습니다. rel="preload"와 같은 리소스 힌트는 리소스 검색 가능성에 영향을 미치는 데 사용될 수 있지만 너무 많은 힌트를 사용하면 대역폭 경합에 문제가 발생할 수 있습니다. 탐색 요청의 HTML 응답이 압축되도록 하면 미리 로드 스캐너에서 응답 내의 리소스를 최대한 빨리 검색할 수 있습니다.
  • 압축을 사용하면 일부 LCP 후보를 더 빠르게 로드할 수도 있습니다. 예를 들어 LCP 후보인 SVG 이미지는 텍스트 기반 압축을 통해 리소스 로드 시간을 줄일 수 있습니다. 이는 JPEG 이미지가 손실(lossy) 압축을 사용하는 방식과 같이 다른 압축 방법을 통해 본질적으로 압축되는 다른 이미지 유형에 적용하는 최적화와 다릅니다.
  • 또한 텍스트 노드는 LCP 후보가 될 수 있습니다. 이 가이드에 설명된 기법은 웹페이지의 텍스트에 웹 글꼴을 사용하는지 여부에 따라 다릅니다. 웹 글꼴을 사용하는 경우 웹 글꼴 최적화 권장사항이 적용됩니다. 그러나 웹 글꼴을 사용하지 않는 경우(리소스 로드 시간을 유발하지 않고 표시되는 시스템 글꼴을 사용하는 경우) CSS를 축소하고 압축하면 로드 시간이 단축되므로 잠재적인 LCP 텍스트 노드의 렌더링이 더 빨리 발생할 수 있습니다.

결론

텍스트 기반 애셋의 인코딩과 전송을 최적화하는 방법은 기본적인 성능 개념이지만, 중요한 영향을 미치는 개념입니다. 압축 및 압축이 가능한 리소스가 이러한 최적화의 이점을 누릴 수 있도록 할 수 있는 모든 조치를 취해야 합니다.

무엇보다도 이러한 프로세스가 자동화되고 있는지 확인하는 것이 중요합니다. 축소의 경우 번들러를 사용하여 요건을 충족하는 리소스에 축소를 적용하세요. 웹 서버 구성이 압축을 지원해야 하지만 그 이상은 사용 가능한 가장 효과적인 압축을 사용해야 합니다. CDN을 사용하면 리소스를 압축할 수 있을 뿐만 아니라 매우 빠르게 압축할 수 있으므로 이를 최대한 간단하게 만들려면 CDN을 사용하여 압축을 자동화하세요.

이러한 기본 성능 개념을 웹사이트 아키텍처에 통합하면 성능 최적화를 위한 노력을 기울일 수 있으며, 후속 최적화를 견고한 기준선으로 확고히 할 수 있습니다.