게시일: 2024년 3월 6일
데이터 압축은 자격 요건을 충족하는 페이지 리소스의 크기를 줄이는 오랜 성능 최적화 기법입니다. 한동안 웹 서버에서 gzip을 주로 사용하여 HTML, CSS, JavaScript 파일과 같은 일반적인 텍스트 기반 페이지 리소스를 압축하고 압축 해제할 수 있는 클라이언트로 전송하는 것이 일반적인 관행이었습니다. 그 결과 페이지의 의도된 동작에 영향을 미치지 않고 리소스의 로드 시간이 빨라집니다.
gzip은 자체적으로 매우 효과적이지만 최근 몇 년 동안 웹의 압축이 더욱 개선되었습니다. 2016년에는 Chrome에 Brotli 알고리즘이 제공되어 자격 요건을 충족하는 리소스의 전반적인 압축률이 개선되었습니다. 2017년 말까지 모든 최신 브라우저에서 Brotli를 지원했으며 서버 지원이 더욱 확산되기 시작했습니다. 최근에는 Chrome에서 ZStandard 압축을 제공했습니다.
하지만 여기서 끝이 아닙니다. Chrome팀은 웹에서 공유 사전을 사용할 수 있도록 작업해 왔으며 이제 Brotli와 ZStandard 모두에서 오리진 트라이얼로 사용할 수 있습니다. 공유 사전은 Brotli 및 ZStandard 압축을 보완하여 업데이트된 코드를 자주 제공하는 웹사이트의 압축률을 크게 높일 수 있으며 경우에 따라 90% 이상의 압축률 을 제공할 수 있습니다. 이 게시물에서는 공유 사전의 작동 방식과 오리진 트라이얼에 등록하여 웹사이트의 Brotli 및 ZStandard에 공유 사전을 사용하는 방법을 자세히 설명합니다. 다음 동영상도 확인해 보세요.
공유 사전 설명
압축은 입력에서 중복된 시퀀스를 찾고 이 정보를 사용하여 나중에 되돌릴 수 있는 훨씬 작은 출력을 만드는 프로세스입니다. 압축은 리소스 로드 시간을 크게 줄이므로 웹에서 잘 작동합니다. Brotli와 ZStandard는 모두 압축 중에 이러한 알고리즘이 사용할 수 있는 추가 패턴 모음인 압축 사전을 사용하여 효율성을 더욱 높일 수 있습니다. 실제로 Brotli의 높은 효율성은 내부 사전을 사용하여 어느 정도 달성됩니다.
하지만 특정 리소스에 고유한 패턴이 포함된 Brotli 및 ZStandard와 함께 커스텀 사용자 큐레이션 사전을 사용할 수 있습니다. 실제로 커스텀 사전은 모든 입력에 적용할 수 있는 외부 파일입니다. 사전은 애플리케이션의 프로덕션 코드 또는 모든 콘텐츠에 매우 구체적일 수 있습니다. 특정 사전이 입력에 얼마나 적용 가능한지는 전반적인 압축 효율성에 큰 영향을 미칠 수 있습니다. 입력의 콘텐츠와 매우 유사한 사전은 일반적이거나 유사하지 않은 콘텐츠가 포함된 사전보다 압축률이 높은 출력을 생성합니다.
다음은 커스텀 압축 사전이 얼마나 효과적인지 보여주는 예입니다. 웹사이트에서 Angular 프레임워크를 사용하고 현재 사용 중인 버전이 1.7.9라고 가정해 보겠습니다. 이 버전의 Angular 프레임워크는 압축되지 않은 상태에서 약 172KiB입니다. Brotli의 기본 설정으로 압축하면 크기가 약 53KiB가 됩니다. 이는 거의 70% 의 압축률을 나타냅니다. 하지만 나중에 Angular 1.8.3으로 업그레이드하기로 결정했다고 가정해 보겠습니다. 이 버전의 Angular는 버전 1.7.9와 크기가 거의 동일하므로 이전 버전과 거의 동일한 압축률을 기대할 수 있습니다.
이때 이전 버전의 리소스 사전이 이후 버전을 압축하는 데 사용할 수 있는 델타 압축 이라는 프로세스를 사용하여 커스텀 사전이 유용할 수 있습니다. 이전 예시를 사용하여 버전 1.7.9를 사전으로 사용하여 Angular 버전 1.8.3을 압축하면 출력은 4KiB를 약간 넘습니다. 이는 거의 98% 의 압축률을 나타냅니다. 압축 사전은 로드 성능에 큰 영향을 미칠 수 있으며 그 효과는 이미 실제 애플리케이션에서 실현되었습니다.
하지만 이 흐름을 웹에서 작동하도록 하는 데는 어려움이 있습니다. 사전을 사용하여 리소스를 압축하는 경우 압축 해제 하려면 동일한 사전이 필요합니다. 이 흐름은 이전에 웹에서 시도되었지만(SDCH) 안전하게 구현하기가 어려웠습니다. 공유 사전 압축에 관한 이 최신 제안은 이러한 문제를 해결하면서 정적 리소스와 동적 리소스 모두에 상당한 이점을 제공합니다.
Chrome에서 공유 사전 지원을 알리는 방법
모든 브라우저는 Accept-Encoding 요청 헤더를 통해 지원하는 압축 알고리즘을 알립니다. 헤더의 콘텐츠는 지원되는 인코딩의 쉼표로 구분된 목록입니다.
Accept-Encoding: gzip, br, zstd
이 특정 Accept-Encoding 헤더는 리소스를 요청하는 브라우저가 gzip, Brotli, ZStandard 압축 알고리즘을 지원한다고 명시합니다. 요청에 응답하는 웹 서버는 요청에 응답할 때 사용할 알고리즘을 결정할 수 있습니다.
공유 사전 지원이 사용 설정되고 리소스에 관련 사전이 있는 경우 추가 토큰이 Accept-Encoding 헤더에 추가됩니다. 이러한 토큰은 Brotli의 경우 br-d, ZStandard의 경우 zstd-d입니다. Chrome에는 사용 가능한 사전의 해시도 포함됩니다. 이는 다음에 설명합니다.
Accept-Encoding: gzip, br, zstd, br-d, zstd-d
Available-Dictionary: :pZGm1Av0IEBKARczz7exkNYsZb8LzaMrV7J32a2fFG4=:
웹 서버가 이 토큰을 인식하도록 구성되어 있고 사전을 인식하는 경우 해당 요청에 적용 가능한 인코딩의 사전을 사용하여 압축된 리소스로 응답할 수 있습니다. 실제로 이 작업이 수행되는 방식은 요청이 정적 리소스인지 동적 리소스인지에 따라 다릅니다.
정적 리소스의 공유 사전 압축
정적 페이지 리소스는 요청된 URL에 대해 항상 동일한 응답을 생성하는 리소스입니다. 압축 가능한 정적 페이지 리소스의 일반적인 예는 JavaScript 및 CSS 파일입니다. 이러한 리소스는 일반적으로 캐싱을 위해 어떤 방식으로든 버전이 지정됩니다. 파일 이름에 파일 콘텐츠의 해시가 포함되거나 (예: styles.abcd1234.css) 리소스의 지문 생성 방법이 사용됩니다. 이러한 리소스 유형은 공유 사전에서 제공하는 델타 압축에 적합합니다. 정적 리소스는 오랫동안 캐시되는 경우가 많고 자주 업데이트되는 경향이 있기 때문입니다.
정적 리소스에 대한 Use-As-Dictionary 응답 헤더를 설정하여 사전을 지정할 수 있습니다. 헤더는 몇 가지 키-값 쌍 중 하나를 사용하지만 필수 키-값 쌍은 match 사전이 사용되어야 하는 리소스 경로를 지정하는 URLPattern 구문을 허용하는 뿐입니다.
Use-As-Dictionary: match="/dist/styles.*.css"
Use-As-Dictionary 헤더는 헤더 내에 지정된 패턴과 일치하는 리소스의 향후 버전에 적용되는 메커니즘이라고 생각하면 됩니다. 웹사이트에서 모든 스타일을 단일 CSS 파일로 제공한다고 가정해 보겠습니다. 간단히 말해 해당 리소스의 첫 번째 버전은 /dist/styles.v1.css에 있으며 match 값이 /dist/styles.*.css인 Use-As-Dictionary 응답 헤더와 함께 전송됩니다.
시간이 지나면 웹사이트의 CSS를 업데이트하고 /dist/styles.v2.css에 있는 새 버전을 제공합니다. 이전 버전의 Use-As-Dictionary 응답 헤더에 사용된 match 값이 이 요청에 적용되므로 브라우저는 구조화된 필드 바이트 시퀀스로 인코딩된 사전의 해시가 포함된 Available-Dictionary 헤더를 전송합니다.
Accept-Encoding: gzip, br, zstd, br-d, zstd-d
Available-Dictionary: :pZGm1Av0IEBKARczz7exkNYsZb8LzaMrV7J32a2fFG4=:
이때 서버는 일치하는 사전이 사용되도록 자체적으로 압축을 구성해야 합니다. 그러면 해당 사전으로 압축된 리소스가 전송되고 사용자의 브라우저 캐시에 있는 사용 가능한 사전이 압축 해제하는 데 사용됩니다.
웹사이트에 새 코드를 자주 제공하는 경우 델타 압축이 큰 도움이 될 수 있습니다. 하지만 프로세스는 유연합니다. 브라우저가 사용자의 브라우저 캐시에 사전이 있다고 판단하지 않으면 Accept-Encoding 헤더에 추가 br-d 또는 zstd-d 토큰을 지정하지 않습니다. 이 경우 표준 압축 흐름이 적용됩니다.
동적 리소스의 공유 사전 압축
동적 리소스도 공유 사전 압축의 이점을 누릴 수 있습니다. 동적 리소스는 컨텍스트에 따라 변경되는 리소스입니다. 예를 들어 뉴스가 보도될 때 기본 페이지가 자주 업데이트되는 뉴스 웹사이트가 있습니다. HTML 문서는 동적 리소스인 경우가 많습니다. 이러한 경우 사전에는 사이트의 일반적인 HTML 구조와 템플릿 코드가 대부분 포함되어 압축된 페이지가 생성되며 각 페이지의 고유한 부분만 전송됩니다.
동적으로 생성된 리소스의 특성으로 인해 나중에 사용하려면 클라이언트에 사전을 로드해야 합니다. 사전을 미리 로드하면 동적 리소스에 공유 사전 압축을 적용하는 것이 추측에 기반한 작업이 됩니다. 이러한 경우 웹사이트에서 사전 비용을 많은 탐색에 걸쳐 상각할 수 있을 만큼 충분한 트래픽을 수신하기를 바랍니다. 시도하기로 결정한 경우 첫 번째 단계는 페이지 HTML에서 <link> 요소를 통해 사전의 위치를 지정하는 것입니다.
<link rel="dictionary" href="/dictionary.dat">
Chrome에서 이 <link> 요소를 발견하면 대역폭 경합을 방지하기 위해 페이지가 유휴 상태일 때 낮은 우선순위로 사전을 가져올 수 있습니다. 사전 자체의 응답은 Use-As-Dictionary 헤더를 지정하고 적용되는 동적 리소스 경로를 지정해야 합니다.
Use-As-Dictionary: match="/product/*"
여기서부터 흐름은 정적 리소스와 거의 동일합니다. 브라우저는 사전 자체가 일치하는 리소스에 적용되는 것을 확인하고 브라우저는 사전 콘텐츠의 해시가 포함된 Available-Dictionary 헤더를 요청에 연결합니다. 이는 앞에서 설명한 정적 리소스 흐름과 유사합니다.
빌드 시 정적 리소스 압축
번들러에 익숙하다면 빌드 시 리소스를 압축하고 압축된 리소스를 제공할 수 있는 다양한 플러그인에 익숙할 것입니다. 예를 들어 Apache를 사용하면 요청 시 이러한 사전 압축된 리소스를 제공하는 데 지시어를 사용할 수 있습니다.
압축을 지원하는 대부분의 Node.js 기반 번들러는 Node의 기본 Zlib 라이브러리를 사용합니다. Zlib은 Brotli를 지원하며 이를 사용하는 번들러는 일반적으로 사전 지원 압축을 지원하는 Zlib에 직접 옵션을 전달하는 인터페이스를 제공합니다. 다음은 사전을 사용하는 것을 지원하는 몇 가지 번들러입니다.
- webpack의
CompressionWebpackPlugin,compressionOptions인터페이스를 통해 제공됩니다. rollup-plugin-brotli는 Node.js의 Zlib에 직접 전달되는options구성을 제공하며 여기서 사전을 지정할 수 있습니다.- esbuild용
esbuild-plugin-compress서드 파티 플러그인도 Node.js의 Zlib 옵션에 대한 액세스를 제공합니다.
리소스의 특정 버전에 사용 가능한 사전은 이전 버전의 리소스 중 하나를 사용할 수 있습니다. 즉, 사용자 트래픽을 분석하고 그에 따라 계획해야 합니다. 균형을 맞추고 최대한 많은 재방문 사용자에게 도움이 되는 리소스를 생성하는 것을 목표로 하세요. CDN 제공업체는 현재 공유 사전 압축을 실험하고 있습니다. 아직 공개적으로 사용할 수 있는 구현은 없지만 변경될 것으로 예상됩니다.
직접 사용해 보세요.
공유 사전 압축을 브라우저의 기존 압축 기능과 통합하면 업데이트된 프로덕션 코드를 자주 제공하고 재방문자로부터 상당한 트래픽을 수신하는 웹사이트의 로드 성능을 크게 개선할 수 있습니다. 공유 사전 압축을 사용해 보려면 다음 두 가지 옵션이 있습니다.
- 공유 사전 압축의 작동 방식을 파악하기 위해 직접 사용해 보려면
chrome://flags페이지에서 압축 사전 전송 실험용 기능을 사용 설정하면 됩니다. - 프로덕션 웹사이트에서 이를 사용해 보고 공유 사전 압축이 실제 사용자에게 어떤 이점을 제공할 수 있는지 알아보려면 오리진 트라이얼에 등록하여 토큰을 받고 오리진 트라이얼의 작동 방식을 알아보세요.
결론
Google은 웹의 압축 기술에서 이 중요한 발전과 사람들이 매일 사용하는 기존 애플리케이션을 얼마나 더 빠르게 만들 수 있는지에 대해 매우 기대하고 있습니다. 사용해 보시기 바라며 가장 중요한 것은 사용해 보신다면 의견을 들려주세요. 버그를 발견하면 crbug.com에 신고하세요. 추가 리소스 및 도구는 use-as-dictionary.com을 참고하세요. 마지막으로 모든 작동 방식을 자세히 알아보려면 설명이 좋은 다음 단계입니다.