דחיסת נתונים היא טכניקה מוכרת ומומלצת לאופטימיזציה של הביצועים, שמפחיתה את הגודל של משאבי הדף שעומדים בדרישות. במשך זמן מה, השיטה הנפוצה הייתה להשתמש ב-gzip בעיקר בשרתי אינטרנט כדי לדחוס משאבי דפים נפוצים שמבוססים על טקסט, כמו קובצי HTML, CSS ו-JavaScript, ולשלוח אותם ללקוח שבו אפשר לבצע את הפעולה ההפוכה (decompression). התוצאה היא זמני טעינה מהירים יותר של משאבים בלי להשפיע על ההתנהגות המיועדת של הדף.
אמנם gzip יעיל מאוד בפני עצמו, אבל בשנים האחרונות בוצעו שיפורים נוספים בתחום הדחיסה באינטרנט. בשנת 2016, אלגוריתם Brotli שוחרר ב-Chrome, והוא מספק יחסי דחיסה טובים יותר באופן כללי למשאבים שעומדים בדרישות. עד סוף שנת 2017, כל הדפדפנים המודרניים תמכו ב-Brotli, והתמיכה בשרתים בו התחילה להתרחב. לאחרונה, הוספה ל-Chrome דחיסה של ZStandard.
אבל זה לא הכול! צוות Chrome עבד על האפשרות להשתמש במילונים משותפים באינטרנט. המילונים האלה זמינים עכשיו בגרסת ניסיון למקורות גם ל-Brotli וגם ל-ZStandard. מילונים משותפים יכולים להשלים את הדחיסה של Brotli ו-ZStandard כדי לספק יחסי דחיסה גבוהים יותר באופן משמעותי לאתרים ששולחים לעיתים קרובות קוד מעודכן, ובמקרים מסוימים הם יכולים לספק יחסי דחיסה של 90% או יותר. בפוסט הזה נסביר בפירוט איך מילונים משותפים פועלים ואיך אפשר להירשם לתוכנית הניסוי למקורות כדי להשתמש בהם ב-Brotli וב-ZStandard באתר שלכם.
הסבר על מילונים משותפים
דחיסה היא תהליך של איתור רצפים יתירים בקלט ושימוש במידע הזה כדי ליצור פלט קטן בהרבה, שניתן לבצע בו פעולה הפוכה מאוחר יותר. דחיסה פועלת היטב באינטרנט כי היא מקצרת באופן משמעותי את זמני הטעינה של המשאבים. אפשר לשפר את היעילות של Brotli ו-ZStandard באמצעות מילון דחיסה, שהוא אוסף של דפוסים נוספים שהאלגוריתמים האלה יכולים להשתמש בהם במהלך הדחיסה. למעשה, מידת היעילות הגבוהה של Brotli מושגת במידה מסוימת באמצעות שימוש במילון פנימי.
עם זאת, אפשר להשתמש במילונים מותאמים אישית שנוצרו על ידי משתמשים עם Brotli ו-ZStandard, שמכילים דפוסים ספציפיים למשאבים מסוימים. בפועל, מילון מותאם אישית הוא קובץ חיצוני שאפשר להחיל על כל קלט. מילונים יכולים להיות ספציפיים מאוד לקוד הייצור של אפליקציה, או לכל תוכן אחר. מידת ההתאמה של מילון נתון לקלט שלו יכולה להשפיע באופן משמעותי על יעילות הדחיסה הכוללת. מילונים שדומים מאוד לתוכן של קלט מניבים תוצאות עם יחסי דחיסה גבוהים יותר מאשר מילונים עם תוכן גנרי או תוכן שונה.
הנה דוגמה לאפקטיביות של מילון דחיסה בהתאמה אישית: נניח שהאתר שלכם משתמש במסגרת Angular, והגרסה הנוכחית שבה אתם משתמשים היא 1.7.9. הגרסה הזו של מסגרת Angular היא בערך 172KB ללא דחיסה. אחרי הדחיסה בהגדרות ברירת המחדל של Brotli, הגודל שלו נעשה כ-53KiB. כך מתקבל יחס דחיסה של כ-70%. עם זאת, נניח שבשלב מאוחר יותר תחליטו לשדרג ל-Angular 1.8.3. מכיוון שהגרסה הזו של Angular דומה בגודל לגרסה 1.7.9, אפשר לצפות ליחס דחיסה דומה לזה של הגרסה הקודמת.
כאן מילון מותאם אישית יכול להיות שימושי באמצעות תהליך שנקרא דחיסת דלתא. בתהליך הזה אפשר להשתמש במילון של גרסה קודמת של משאב כדי לדחוס גרסה מאוחרת יותר. בדוגמה הקודמת, אם דחיסתם את גרסה 1.8.3 של Angular באמצעות גרסה 1.7.9 כמילון, הפלט יהיה קצת יותר מ-4KiB. זהו יחס דחיסה של כמעט 98%. ברור שמילויים של דחיסת נתונים יכולים להשפיע מאוד על ביצועי הטעינה, והיעילות שלהם כבר הוכחה באפליקציות בעולם האמיתי.
עם זאת, יש קושי להפעיל את התהליך הזה באינטרנט. הבעיה היא שאם משתמשים במילון כדי לדחוס משאב, צריך את אותו מילון כדי לנתק את הדחיסה שלו. כבר ניסו בעבר להשתמש בתהליך הזה באינטרנט – SDCH – אבל היה קשה להטמיע אותו בצורה בטוחה. ההצעה האחרונה לדחיסת מילון משותף מטפלת בבעיות האלה ומספקת יתרונות משמעותיים גם למשאבים סטטיים וגם למשאבים דינמיים.
איך Chrome מכריז על תמיכה במילונים משותפים
כל הדפדפנים מפרסמים את אלגוריתמי הדחיסה שהם תומכים בהם באמצעות כותרת הבקשה Accept-Encoding
. תוכן הכותרת הוא רשימה של קידודים נתמכים, מופרדים בפסיקים:
Accept-Encoding: gzip, br, zstd
כותרת Accept-Encoding
הספציפית הזו מציינת שהדפדפן שמבקש את המשאב תומך באלגוריתמים לדחיסה gzip, Brotli ו-ZStandard. לאחר מכן, שרת האינטרנט שמגיב לבקשה יכול להחליט באיזה אלגוריתם להשתמש בתגובה לבקשה.
כשהתמיכה במילון משותף מופעלת ויש מילון רלוונטי שזמין למשאב, אסימונים נוספים מתווספים לכותרת Accept-Encoding
. האסימונים האלה הם br-d
עבור Brotli ו-zstd-d
עבור Zstandard. Chrome יכלול גם את ה-hash של מילון זמין, כפי שמתואר בהמשך.
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
, ושהיא נשלחת עם כותרת תגובה מסוג 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">
כש-Chrome נתקל ברכיב <link>
הזה, הוא עשוי לאחזר את המילון כשהדף לא פעיל, ובעדיפות נמוכה כדי להימנע ממאבק על רוחב הפס. התגובה למילון עצמו חייבת לציין כותרת Use-As-Dictionary
ולציין לאיזה נתיב משאב דינמי היא חלה:
Use-As-Dictionary: match="/product/*"
מכאן, התהליך דומה במידה רבה לזה של משאבים סטטיים. הדפדפן יראה שהמילון עצמו חל על משאבים תואמים, והדפדפן יצרף לבקשה כותרת Available-Dictionary
עם גיבוב של תוכן המילון, בדומה לתהליך של משאבים סטטיים שמתואר למעלה.
דחיסת משאבים סטטיים בזמן ה-build
אם אתם מכירים חבילות, יכול להיות שאתם מכירים גם יישומי פלאגין שונים שיכולים לדחוס משאבים בזמן ה-build, ולאחר מכן להציג את המשאבים הדחוסים האלה. לדוגמה, ב-Apache אפשר להשתמש בהוראות כדי להציג את המשאבים האלה שנלחצו מראש בזמן הבקשה.
רוב ה-bundlers שמבוססים על Node.js ותומכים בקיצור משתמשים בספריית Zlib המובנית של Node. Zlib תומך ב-Brotli, וחבילות האוספים שמשתמשות בו בדרך כלל מציעות ממשק להעברת אפשרויות ישירות ל-Zlib, שתומך בדחיסה בעזרת מילון. ריכזנו כאן כמה חבילות שאפשר להשתמש בהן במילונים:
CompressionWebpackPlugin
של webpack, דרך הממשקcompressionOptions
.rollup-plugin-brotli
מציע הגדרה שלoptions
שעוברת ישירות אל Zlib ב-Node.js, שבו אפשר לציין מילונים.- הפלאגין של צד שלישי
esbuild-plugin-compress
ל-esbuild גם מציע גישה לאפשרויות Zlib ב-Node.js.
חשוב לזכור שמילונים זמינים לגרסה מסוימת של משאב עשויים להשתמש באחת מהגרסאות הקודמות של המשאב. המשמעות היא שתצטרכו לנתח את תנועת המשתמשים ולתכנן בהתאם. כדאי לשאוף לאיזון וליצור משאבים שיעזרו למספר המקסימלי של משתמשים חוזרים, ככל האפשר. ספקי CDN עורכים כרגע ניסויים בקידוד דחוס של מילון משותף. עדיין אין הטמעות שזמינות לשימוש ציבורי, אבל אנחנו מצפים שהמצב ישתנה.
כדאי לנסות!
שילוב של דחיסת מילון משותף עם יכולות הדחיסה הקיימות של הדפדפן עשוי לשפר באופן משמעותי את ביצועי הטעינה של אתרים ששולחים לעיתים קרובות קוד ייצור מעודכן ומקבלים תנועה משמעותית ממבקרים חוזרים. אם אתם רוצים לנסות את דחיסת המילון המשותף, יש לכם שתי אפשרויות:
- אם אתם רוצים להתנסות בדחיסת מילון משותף בעצמכם כדי להבין איך זה עובד, תוכלו להפעיל את התכונה הניסיונית העברה של מילון דחיסה בדף
chrome://flags
. - אם אתם רוצים לנסות את התכונה הזו באתר הייצור שלכם ולראות איך דחיסת מילון משותף יכולה להועיל למשתמשים אמיתיים, עליכם להירשם לגרסת הטרום-השקה (Origin Trial) כדי לקבל אסימון, ולקרוא את המאמר איך פועלות גרסאות הטרום-השקה (Origin Trial).
סיכום
אנחנו מאוד שמחים על ההתקדמות המשמעותית הזו בטכנולוגיית הדחיסה באינטרנט, ועל כמה מהר יותר היא יכולה להפוך אפליקציות קיימות שבהן אנשים משתמשים כל יום. מומלץ לנסות את התכונה הזו, והכי חשוב – נשמח לשמוע את דעתכם אם תעשו זאת. אם מצאתם באג, דווחו עליו בכתובת crbug.com. למקורות מידע וכלים נוספים, אפשר להיכנס לאתר use-as-dictionary.com. לסיום, אם אתם רוצים להבין לעומק איך הכול עובד, הסרטון הוא השלב הבא שכדאי לכם לצפות בו.