بازده فشرده سازی سوپرشارژ با دیکشنری های مشترک

منتشر شده: ۶ مارس ۲۰۲۴

فشرده‌سازی داده‌ها یک تکنیک بهینه‌سازی عملکرد است که در طول زمان آزمایش شده و اندازه منابع واجد شرایط صفحه را کاهش می‌دهد. مدتی، استفاده از gzip در سرورهای وب برای فشرده‌سازی منابع رایج صفحه مبتنی بر متن مانند فایل‌های HTML، CSS و جاوا اسکریپت و ارسال آنها به کلاینت که در آنجا می‌توانند از حالت فشرده خارج شوند، رایج بود. نتیجه، زمان بارگذاری سریع‌تر منابع بدون تأثیر بر رفتار مورد نظر یک صفحه است.

اگرچه gzip به خودی خود بسیار مؤثر است، اما در سال‌های اخیر پیشرفت‌های بیشتری در فشرده‌سازی در وب حاصل شده است. در سال ۲۰۱۶، الگوریتم Brotli در کروم ارائه شد و نسبت فشرده‌سازی بهتری را برای منابع واجد شرایط ارائه داد. تا پایان سال ۲۰۱۷، همه مرورگرهای مدرن از Brotli پشتیبانی کردند و پشتیبانی سرور از آن گسترده‌تر شد. اخیراً، کروم فشرده‌سازی ZStandard را ارائه کرده است .

کار به اینجا ختم نمی‌شود! تیم کروم مدتی است که روی قابل استفاده کردن دیکشنری‌های اشتراکی در وب کار می‌کند که اکنون در نسخه آزمایشی Origin برای Brotli و ZStandard در دسترس هستند. دیکشنری‌های اشتراکی می‌توانند فشرده‌سازی Brotli و ZStandard را تکمیل کنند تا نسبت فشرده‌سازی به مراتب بالاتری را برای وب‌سایت‌هایی که مرتباً کد به‌روزرسانی‌شده ارسال می‌کنند، ارائه دهند و در برخی موارد می‌توانند نسبت فشرده‌سازی ۹۰٪ یا بهتر را ارائه دهند. این پست به جزئیات بیشتری در مورد نحوه کار دیکشنری‌های اشتراکی و نحوه ثبت‌نام در نسخه آزمایشی Origin برای استفاده از آنها برای Brotli و ZStandard در وب‌سایت شما می‌پردازد. همچنین می‌توانید این ویدیو را تماشا کنید:

توضیح فرهنگ لغت‌های مشترک

فشرده‌سازی فرآیندی است که در آن توالی‌های اضافی در یک ورودی پیدا می‌شوند و از آن اطلاعات برای ایجاد یک خروجی بسیار کوچک‌تر استفاده می‌شود که بعداً می‌توان آن را معکوس کرد. فشرده‌سازی در وب به خوبی کار می‌کند زیرا زمان بارگذاری منابع را به میزان قابل توجهی کاهش می‌دهد. هم Brotli و هم ZStandard می‌توانند با استفاده از یک فرهنگ لغت فشرده‌سازی ، که مجموعه‌ای از الگوهای اضافی است که این الگوریتم‌ها می‌توانند در طول فشرده‌سازی استفاده کنند، اثربخشی خود را بیشتر افزایش دهند. در واقع، کارایی بالای Brotli تا حدی با استفاده از یک فرهنگ لغت داخلی حاصل می‌شود.

با این حال، می‌توان از دیکشنری‌های سفارشیِ تنظیم‌شده توسط کاربر با Brotli و ZStandard استفاده کرد که حاوی الگوهایی مختص به منابع خاص هستند. در عمل، یک دیکشنری سفارشی یک فایل خارجی است که می‌تواند برای هر ورودی اعمال شود. دیکشنری‌ها می‌توانند کاملاً مختص کد تولید یک برنامه یا در واقع هر محتوایی باشند. میزان کاربرد یک دیکشنری مشخص برای ورودی آن می‌تواند تأثیر زیادی بر کارایی کلی فشرده‌سازی داشته باشد. دیکشنری‌هایی که بسیار شبیه به محتوای یک ورودی هستند، خروجی‌هایی با نسبت فشرده‌سازی بالاتر نسبت به دیکشنری‌هایی با محتوای عمومی یا متفاوت ارائه می‌دهند.

در اینجا مثالی از میزان اثربخشی یک دیکشنری فشرده‌سازی سفارشی ارائه شده است: فرض کنید وب‌سایت شما از چارچوب Angular استفاده می‌کند و نسخه فعلی که استفاده می‌کنید نسخه ۱.۷.۹ است. این نسخه از چارچوب Angular حدود ۱۷۲ کیلوبایت فشرده نشده دارد. وقتی با تنظیمات پیش‌فرض Brotli فشرده می‌شود، اندازه آن حدود ۵۳ کیلوبایت می‌شود. این تقریباً نسبت فشرده‌سازی ۷۰٪ را به همراه دارد. با این حال، فرض کنید تصمیم دارید بعداً به Angular 1.8.3 ارتقا دهید. با توجه به اینکه این نسخه از Angular تقریباً اندازه‌ای مشابه نسخه ۱.۷.۹ دارد، می‌توانید تقریباً همان نسبت فشرده‌سازی نسخه قبلی را انتظار داشته باشید.

اینجاست که یک دیکشنری سفارشی می‌تواند با استفاده از فرآیندی به نام فشرده‌سازی دلتا مفید واقع شود، که زمانی است که می‌توان از دیکشنری نسخه قبلی یک منبع برای فشرده‌سازی نسخه بعدی استفاده کرد. با استفاده از مثال قبلی، اگر نسخه ۱.۸.۳ از Angular را با استفاده از نسخه ۱.۷.۹ به عنوان دیکشنری فشرده کنید، خروجی کمی بیش از ۴ کیلوبایت خواهد بود. این نشان دهنده نسبت فشرده‌سازی تقریباً ۹۸٪ است. واضح است که دیکشنری‌های فشرده‌سازی می‌توانند تأثیر زیادی بر عملکرد بارگذاری داشته باشند و اثربخشی آنها قبلاً در برنامه‌های دنیای واقعی محقق شده است!

با این حال، چالشی در اجرای این جریان در وب وجود دارد. نکته این است که اگر از یک دیکشنری برای فشرده‌سازی یک منبع استفاده کنید، برای خارج کردن آن از حالت فشرده به همان دیکشنری نیاز دارید. این جریان قبلاً در وب - یعنی SDCH - مورد آزمایش قرار گرفته است، اما پیاده‌سازی ایمن آن چالش‌برانگیز بود. این پیشنهاد اخیر برای فشرده‌سازی دیکشنری مشترک ، این نگرانی‌ها را برطرف می‌کند و در عین حال مزایای قابل توجهی را برای منابع ایستا و پویا فراهم می‌کند.

چگونه کروم پشتیبانی از فرهنگ لغت‌های مشترک را تبلیغ می‌کند

همه مرورگرها الگوریتم‌های فشرده‌سازی پشتیبانی‌شده توسط خود را از طریق سربرگ درخواست Accept-Encoding اعلام می‌کنند. محتوای سربرگ، فهرستی از کدگذاری‌های پشتیبانی‌شده است که با کاما از هم جدا شده‌اند:

Accept-Encoding: gzip, br, zstd

این هدر Accept-Encoding خاص بیان می‌کند که مرورگر درخواست‌کننده منبع از الگوریتم‌های فشرده‌سازی gzip، Brotli و ZStandard پشتیبانی می‌کند. سپس یک وب سرور که به درخواست پاسخ می‌دهد، می‌تواند تصمیم بگیرد که از کدام الگوریتم هنگام پاسخ به درخواست استفاده کند.

وقتی پشتیبانی از دیکشنری مشترک فعال باشد و دیکشنری مرتبطی برای یک منبع در دسترس باشد، توکن‌های اضافی به هدر Accept-Encoding اضافه می‌شوند. این توکن‌ها برای Brotli، br-d و برای Zstandard، zstd-d هستند. کروم همچنین هش یک دیکشنری موجود را که در ادامه به آن پرداخته خواهد شد، در خود جای می‌دهد.

Accept-Encoding: gzip, br, zstd, br-d, zstd-d
Available-Dictionary: :pZGm1Av0IEBKARczz7exkNYsZb8LzaMrV7J32a2fFG4=:

اگر یک وب سرور طوری پیکربندی شده باشد که این توکن را تشخیص دهد و دیکشنری را تشخیص دهد، می‌تواند به آن درخواست با منبعی که با استفاده از دیکشنری برای کدگذاری مربوطه فشرده شده است، پاسخ دهد. چگونگی دستیابی به این امر در عمل بستگی به این دارد که آیا درخواست برای یک منبع ایستا است یا پویا.

فشرده‌سازی دیکشنری مشترک برای منابع استاتیک

یک منبع صفحه استاتیک، منبعی است که همیشه پاسخ یکسانی را برای یک URL درخواستی تولید می‌کند. نمونه‌های رایج از منابع صفحه استاتیک قابل فشرده‌سازی، فایل‌های جاوا اسکریپت و CSS هستند. این منابع معمولاً به نوعی برای اهداف ذخیره‌سازی نسخه‌بندی می‌شوند - گاهی اوقات با هش محتوای فایل در نام فایل (به عنوان مثال styles.abcd1234.css ) یا روش دیگری برای انگشت‌نگاری منبع. این نوع منابع، کاندیدای خوبی برای فشرده‌سازی دلتا هستند که دیکشنری‌های اشتراکی ارائه می‌دهند، زیرا منابع استاتیک اغلب برای مدت طولانی در حافظه پنهان ذخیره می‌شوند و تمایل دارند با فرکانس خاصی به‌روزرسانی شوند.

می‌توان با تنظیم هدر پاسخ Use-As-Dictionary برای یک منبع ایستا، یک دیکشنری را برای آن مشخص کرد. این هدر یکی از چند جفت کلید/مقدار را می‌گیرد، اما تنها جفت مورد نیاز match است که سینتکس URLPattern را می‌پذیرد و مسیر منبعی را که دیکشنری باید در آن استفاده شود، مشخص می‌کند:

Use-As-Dictionary: match="/dist/styles.*.css"

هدر Use-As-Dictionary را به عنوان مکانیزمی در نظر بگیرید که برای نسخه‌های آینده‌ی یک منبع که با الگوی مشخص شده در آن مطابقت دارند، اعمال می‌شود. بنابراین، فرض کنید وب‌سایت شما تمام استایل‌های خود را در یک فایل CSS واحد ارسال می‌کند. برای سادگی، فرض کنید اولین نسخه از آن منبع در /dist/styles.v1.css قرار دارد و با یک هدر پاسخ Use-As-Dictionary حاوی مقدار match /dist/styles.*.css ارسال می‌شود.

پس از گذشت مدتی، CSS وب‌سایت خود را به‌روزرسانی می‌کنید و نسخه جدیدی از آن را که در /dist/styles.v2.css قرار دارد، ارسال می‌کنید. از آنجا که مقدار match استفاده شده در هدر پاسخ Use-As-Dictionary از نسخه قبلی برای این درخواست اعمال می‌شود، مرورگر یک هدر Available-Dictionary حاوی هش دیکشنری که به صورت یک رشته بایت فیلد ساختاریافته کدگذاری شده است، ارسال می‌کند:

Accept-Encoding: gzip, br, zstd, br-d, zstd-d
Available-Dictionary: :pZGm1Av0IEBKARczz7exkNYsZb8LzaMrV7J32a2fFG4=:

در این مرحله، پیکربندی فشرده‌سازی در سمت سرور به منظور اطمینان از استفاده از دیکشنری منطبق، بر عهده‌ی آن است. سپس منبع فشرده‌شده با آن دیکشنری ارسال می‌شود و دیکشنری موجود در حافظه‌ی پنهان مرورگر کاربر برای خارج کردن آن از حالت فشرده استفاده می‌شود.

اگر مرتباً کد جدیدی برای وب‌سایت خود ارسال می‌کنید، فشرده‌سازی دلتا می‌تواند بسیار مفید باشد. با این حال، این فرآیند انعطاف‌پذیر است. اگر مرورگر تشخیص ندهد که یک دیکشنری در حافظه پنهان مرورگر کاربر موجود است، توکن‌های اضافی br-d یا zstd-d را در هدر Accept-Encoding مشخص نمی‌کند . در این صورت، جریان فشرده‌سازی استاندارد اعمال می‌شود.

فشرده‌سازی دیکشنری مشترک برای منابع پویا

منابع پویا همچنین می‌توانند از فشرده‌سازی دیکشنری مشترک بهره‌مند شوند. منابع پویا منابعی هستند که بر اساس یک زمینه تغییر می‌کنند - مانند یک وب‌سایت خبری که صفحه اصلی آن مرتباً با انتشار اخبار به‌روز می‌شود. اسناد HTML اغلب منابع پویا هستند. در چنین مواردی، دیکشنری می‌تواند شامل بیشتر ساختار HTML رایج سایت و کد قالب باشد که منجر به صفحات فشرده شده‌ای می‌شود که در آنها فقط بخش‌های منحصر به فرد هر صفحه ارسال می‌شوند.

با توجه به ماهیت منابع تولید شده به صورت پویا، یک دیکشنری باید برای استفاده بعدی روی کلاینت بارگذاری شود. بارگذاری یک دیکشنری قبل از زمان به این معنی است که اعمال فشرده‌سازی دیکشنری مشترک به منابع پویا، امری حدسی است. در چنین مواردی امید این است که وب‌سایت شما ترافیک کافی دریافت کند تا هزینه دیکشنری بتواند در تعداد زیادی از پیمایش‌ها مستهلک شود. اگر تصمیم به امتحان کردن آن دارید، اولین قدم مشخص کردن مکان دیکشنری از طریق یک عنصر <link> در HTML صفحه شما است:

<link rel="dictionary" href="/dictionary.dat">

وقتی کروم با این عنصر <link> مواجه می‌شود، ممکن است پس از غیرفعال بودن صفحه و با اولویت پایین، دیکشنری را دریافت کند تا از تداخل پهنای باند جلوگیری شود. پاسخ مربوط به خود دیکشنری باید یک هدر Use-As-Dictionary را مشخص کند و مشخص کند که به کدام مسیر منبع پویا اعمال می‌شود:

Use-As-Dictionary: match="/product/*"

از اینجا به بعد، روند کار تا حد زیادی مشابه منابع استاتیک است. مرورگر متوجه می‌شود که خود دیکشنری برای منابع منطبق اعمال می‌شود و یک هدر Available-Dictionary به همراه هش محتوای دیکشنری به درخواست پیوست می‌کند، که باز هم مشابه روند کار منابع استاتیک است که قبلاً توضیح داده شد.

فشرده‌سازی منابع استاتیک در زمان ساخت

اگر با bundlerها آشنا باشید، ممکن است با افزونه‌های مختلفی برای آنها آشنا باشید که می‌توانند منابع را در زمان ساخت فشرده کنند و متعاقباً آن منابع فشرده شده را ارائه دهند. به عنوان مثال، آپاچی به شما امکان می‌دهد از دستورالعمل‌ها برای ارائه آن منابع از پیش فشرده شده در زمان درخواست استفاده کنید .

بیشتر bundler های مبتنی بر Node.js که از فشرده‌سازی پشتیبانی می‌کنند، از کتابخانه داخلی Zlib نود استفاده می‌کنند. Zlib از Brotli پشتیبانی می‌کند و bundler هایی که از آن استفاده می‌کنند، معمولاً رابطی برای ارسال مستقیم گزینه‌ها به Zlib ارائه می‌دهند که از فشرده‌سازی به کمک دیکشنری پشتیبانی می‌کند . در اینجا چند bundler که از استفاده از دیکشنری‌ها پشتیبانی می‌کنند، آورده شده است:

توجه داشته باشید که دیکشنری‌های موجود برای هر نسخه از یک منبع ممکن است از یکی از نسخه‌های قبلی آن منبع استفاده کنند. این بدان معناست که شما باید ترافیک کاربران را تجزیه و تحلیل کرده و بر اساس آن برنامه‌ریزی کنید. به دنبال تعادل باشید و منابعی تولید کنید که تا حد امکان برای حداکثر تعداد کاربران فعلی مفید باشد. ارائه دهندگان CDN در حال حاضر در حال آزمایش فشرده‌سازی دیکشنری مشترک هستند. هنوز هیچ پیاده‌سازی برای استفاده عمومی در دسترس نیست، اما انتظار داریم این وضعیت تغییر کند!

امتحانش کن!

ادغام فشرده‌سازی دیکشنری مشترک با قابلیت‌های فشرده‌سازی موجود مرورگر، پتانسیل بهبود قابل توجه عملکرد بارگذاری وب‌سایت‌هایی را دارد که مرتباً کد تولید به‌روزرسانی‌شده ارسال می‌کنند و ترافیک قابل توجهی از بازدیدکنندگان دائمی دریافت می‌کنند. اگر علاقه‌مند به امتحان کردن فشرده‌سازی دیکشنری مشترک هستید، دو گزینه دارید:

  1. اگر فقط می‌خواهید خودتان فشرده‌سازی دیکشنری مشترک را دستکاری کنید تا با نحوه‌ی کار آن آشنا شوید، می‌توانید ویژگی آزمایشی انتقال دیکشنری فشرده‌سازی را در صفحه‌ی chrome://flags فعال کنید.
  2. اگر علاقه‌مند به امتحان کردن این مورد در وب‌سایت تولیدی خود هستید و می‌خواهید ببینید که فشرده‌سازی دیکشنری مشترک چگونه می‌تواند برای کاربران واقعی مفید باشد، برای دریافت توکن در نسخه آزمایشی origin ثبت‌نام کنید و در مورد نحوه کار نسخه‌های آزمایشی origin مطالعه کنید.

نتیجه‌گیری

ما از این پیشرفت بزرگ در فناوری فشرده‌سازی در وب و اینکه چقدر می‌تواند برنامه‌های موجود مورد استفاده روزانه مردم را سریع‌تر کند، بسیار هیجان‌زده‌ایم. شما را تشویق می‌کنیم که آن را امتحان کنید و از همه مهم‌تر، اگر نظری دارید، می‌خواهیم نظرات شما را بشنویم ! اگر اشکالی پیدا کردید، آن را در crbug.com ثبت کنید . برای منابع و ابزارهای بیشتر، use-as-dictionary.com را بررسی کنید. در نهایت، اگر علاقه‌مند به بررسی عمیق‌تر نحوه عملکرد آن هستید، این توضیح‌دهنده گام بعدی خوبی است!