אסטרטגיות CDN Caching: Cache-Control, Edge Logic ו-Purging בקנה מידה

מאת צוות מדיה דיל · 05.08.2026 · DevOps · 8 דק׳

מדריך עומק ל-CDN caching: כותרות Cache-Control ו-Vary, edge computing, אסטרטגיות purging, ו-cache key design למניעת דליפת מידע.

הבעיה עם CDN caching היא שהיא נראית כמו "להוסיף שכבה מהירה בין המשתמש לשרת", אבל בפועל היא מערכת שלמה של כללים שקובעים מה נשמר, איפה, לכמה זמן, ולמי — וטעות בכל אחד מהם עלולה לגרום לתוצאה הפוכה מהמצופה: תוכן פרטי שדולף למשתמש אחר, או תוכן ציבורי שלא מתעדכן אף פעם. CDN (Content Delivery Network) הוא רשת שרתי edge שמפוזרים גיאוגרפית ומחזיקים עותקים מקומיים של תוכן, כדי לקצר את המרחק הפיזי בין המשתמש לתשובה — אבל הארכיטקטורה האמיתית שמאחוריו דורשת הבנה מדויקת של כותרות HTTP, מפתחות cache, ותהליכי עדכון. במאמר הזה נפרק את זה לעומק.

Cache-Control: השפה שה-CDN מדבר בה

כותרת Cache-Control ב-response היא ההוראה המרכזית שהשרת נותן ל-CDN (ולדפדפן) איך להתייחס לתוכן. public מאשר cache על ידי כל מתווך (CDN, proxies), בעוד private מגביל cache רק לדפדפן של המשתמש הספציפי — הבחנה קריטית עבור תוכן מותאם-אישית שאסור שיישמר ב-CDN משותף ויוגש למשתמש אחר. max-age קובע כמה שניות התוכן נחשב "טרי" בלי לבדוק מול השרת המקורי (origin), בעוד s-maxage מאפשר לקבוע ערך שונה ספציפית עבור shared caches (CDN) לעומת דפדפן — שימושי כשרוצים cache ארוך ב-CDN אך cache קצר יותר בדפדפן עצמו כדי שעדכונים יגיעו מהר יותר למשתמש הקצה. no-cache (שם מטעה) לא אוסר cache — הוא מחייב revalidation מול השרת בכל בקשה לפני הגשה מה-cache, בעוד no-store הוא ההוראה שבאמת אוסרת שמירה כלשהי.

ETag ו-Conditional Requests: Revalidation יעילה

ETag הוא זיהוי ייחודי (בדרך כלל hash) של גרסת התוכן. כשתוכן פג (או מוגדר עם no-cache), הדפדפן/CDN שולח בקשה מותנית עם If-None-Match שמכיל את ה-ETag שהוא כבר מחזיק — אם התוכן לא השתנה, השרת מחזיר 304 Not Modified ריק לגמרי (בלי גוף התשובה כלל), חוסך bandwidth משמעותי לעומת שליחת התוכן המלא מחדש כל פעם. זה שימושי במיוחד לתוכן שמתעדכן לעיתים רחוקות אך צריך תמיד להיות עדכני — revalidation מהירה כל פעם, אך שליחת הנתונים בפועל רק כשבאמת השתנו.

Vary Header: כשאותו URL מחזיר תוכן שונה

כותרת Vary קובעת אילו כותרות בקשה (request headers) משפיעות על התוכן שמוחזר, וכתוצאה מכך צריכות להיות חלק ממפתח ה-cache. Vary: Accept-Language אומר ל-CDN לשמור עותק נפרד לכל שפה, כדי שמשתמש דובר עברית לא יקבל בטעות תוכן שנשמר עבור משתמש דובר אנגלית תחת אותו URL. Vary: Accept-Encoding מבטיח שגרסה דחוסה (gzip) לא תוגש ללקוח שלא תומך בה. הטעות הנפוצה ביותר בהקשר הזה היא Vary: Cookie — אם cookies משתנים לכל משתמש (session ID ייחודי), הוספתם ל-Vary הופכת בפועל כל בקשה ל-cache miss, כי אין שני משתמשים עם אותו cookie, מה שמבטל את כל ערך ה-CDN.

Cache Key Design: המקור לדליפות מידע

ה-cache key שה-CDN משתמש בו כברירת מחדל הוא לרוב ה-URL בלבד. אם response משתנה לפי משתנים נוספים שלא נכללים ב-key (query params מסוימים, geo-location, A/B test bucket) בלי לעדכן את הגדרת ה-Vary או cache key מותאם, שני משתמשים שונים עלולים לקבל תוכן שנועד לצד השני — תרחיש דליפת מידע קלאסי, במיוחד חמור כשמדובר בתוכן מותאם-אישית (הצעות מחיר, נתונים אישיים). CDNs מודרניים (Cloudflare, Fastly, CloudFront) מאפשרים הגדרת cache key מותאם אישית ברמת עריכה עדינה — כולל אילו query params להתעלם מהם (למשל UTM tracking params שלא משפיעים על התוכן עצמו) ואילו לכלול (page param בעימוד תוצאות).

Edge Computing: לוגיקה שרצה ב-CDN עצמו

CDNs מודרניים חורגים מ"שרת קבצים סטטיים מבוזר" ומריצים קוד בפועל ב-edge (Cloudflare Workers, Fastly Compute, AWS CloudFront Functions) — לפני שהבקשה בכלל מגיעה ל-origin. זה מאפשר החלטות caching דינמיות (בדיקת A/B bucket ובחירת cache variant מתאים), שינוי תוכן on-the-fly (personalization קלה, i18n), או אפילו הגשת תשובה מלאה ישירות מה-edge בלי לגעת ב-origin כלל. הכוח הזה מגיע במחיר: קוד ב-edge רץ בסביבה מוגבלת (זמן ריצה קצר, ללא גישה למסד נתונים מלא), ולכן הוא מתאים ללוגיקה קלה — לא לחישובים כבדים או פניות רשת מרובות.

Purging: עדכון תוכן שכבר נשמר

כשתוכן שכבר ב-cache צריך להתעדכן מיידית (לא להמתין ל-TTL), נדרש purge יזום. Single URL purge מוחק entry ספציפי — מדויק אך לא ניתן להרחבה כשצריך לעדכן מאות URLs בבת אחת. Tag-based purging (נתמך ב-Fastly, Cloudflare Enterprise) מאפשר לתייג תוכן בזמן ה-cache (למשל, כל הדפים שמציגים מוצר מסוים מתויגים ב-product-123), ולבצע purge של כל התוכן עם אותו tag בפעולה אחת — קריטי עבור e-commerce שבו עדכון מוצר בודד משפיע על דפים רבים (דף מוצר, קטגוריה, חיפוש). Purge-everything הוא הכלי הגס ביותר ומסוכן בקנה מידה — הוא מוחק את כל ה-cache בבת אחת, מה שגורם ל-cache stampede מלא כשכל התעבורה פונה ל-origin בו-זמנית.

Stale-While-Revalidate: חוויית משתמש רציפה בזמן עדכון

הוראת stale-while-revalidate ב-Cache-Control מאפשרת ל-CDN להגיש תוכן ישן (stale) מיידית למשתמש בזמן שהוא בו-בזמן שולח בקשה ברקע ל-origin כדי לרענן את ה-cache עבור הבקשה הבאה. זה נותן latency מינימלי תמידית (המשתמש אף פעם לא ממתין לרענון), במחיר קבלת תוכן מיושן בחלון זמן קצר ומוגדר. שילוב עם stale-if-error מוסיף שכבת חוסן — אם ה-origin לא זמין בכלל, ה-CDN ממשיך להגיש את הגרסה הישנה במקום להחזיר שגיאה, מה שהופך את ה-CDN לשכבת הגנה גם מפני נפילת ה-origin, לא רק שכבת ביצועים.

Origin Shield: הגנה על השרת המקורי

ל-CDN יש עשרות או מאות edge nodes ברחבי העולם, וכל אחד מהם, ללא תיאום, עלול לשלוח בקשת cache miss נפרדת ל-origin עבור אותו תוכן בדיוק — למשל תוכן שהפך פופולרי פתאום (viral) ולא היה עדיין ב-cache באף edge node. בלי הגנה, זה יוצר עומס מוכפל על ה-origin בדיוק ברגע שהוא הכי צריך יציבות. Origin Shield (תכונה שמציעים רוב ה-CDNs המובילים) מוסיף שכבת ביניים — origin location מרכזי יחיד שכל ה-edge nodes פונים אליו במקום ישירות ל-origin האמיתי, כך שרק בקשה אחת מגיעה בפועל ל-origin האמיתי גם אם מאות edge nodes ביקשו את אותו תוכן כמעט בו-זמנית. השכבה הזו היא בעצם יישום של cache stampede protection ברמת ה-CDN עצמו.

HTTP/2, HTTP/3 והשפעתם על אסטרטגיית Caching

מעבר מ-HTTP/1.1 ל-HTTP/2 ו-HTTP/3 (מבוסס QUIC) לא שינה את סמנטיקת ה-Cache-Control עצמה, אך שינה את הכדאיות הכלכלית של כמה החלטות caching ותיקות. ב-HTTP/1.1, הפרקטיקה הנפוצה הייתה לאחד קבצי CSS/JS רבים לקובץ בודד (bundling) כדי לצמצם את מספר הבקשות, כי כל בקשה נפרדת הייתה יקרה. ב-HTTP/2 עם multiplexing (בקשות מרובות על אותו חיבור במקביל), bundling אגרסיבי מדי דווקא פוגע ב-caching — קובץ ענק אחד שמשתנה מעט גורם ל-cache invalidation מלא של כל התוכן, בעוד קבצים קטנים ונפרדים יכולים להישאר ב-cache גם כשרק חלק מהם השתנה. זה שינה את האסטרטגיה המומלצת ל-code splitting מדויק יותר, עם קבצים קטנים יותר שמנוצלים ל-caching ארוך טווח בנפרד.

Trade-offs: כמה אגרסיבי להיות עם TTL

TTL ארוך מקטין עומס על ה-origin ומשפר latency, אבל מאריך את הזמן שלוקח לעדכונים להגיע לכל המשתמשים. TTL קצר מבטיח עדכניות אך מקטין את היתרון של ה-CDN כי יותר בקשות עוברות דרך ל-origin. הגישה המקצועית: תוכן סטטי (תמונות, JS/CSS עם hash בשם הקובץ) מקבל TTL ארוך מאוד (שנה או יותר) כי כל שינוי יוצר URL חדש לגמרי; תוכן דינמי אך לא רגיש לזמן (מאמרי בלוג, דפי מוצר) מקבל TTL בינוני עם purge יזום בעדכון; תוכן שדורש עדכניות קשיחה (מחירים, מלאי) לרוב נשאר עם no-cache ו-revalidation מהירה, או מוגש ישירות מ-origin.

מוניטורינג: Cache Hit Ratio ברמת CDN

מדד המפתח למדידת יעילות CDN הוא cache hit ratio — אחוז הבקשות שנענו ישירות מה-edge בלי לפנות בכלל ל-origin. ירידה פתאומית במדד הזה היא סימן אזהרה מוקדם לבעיה — אולי שינוי בקוד הוסיף בטעות header שמבטל caching (כמו Set-Cookie על כל response), אולי שינוי בפרונט-אנד הוסיף query param אקראי לכל בקשה (cache buster לא מכוון) שהופך כל URL לייחודי. מרבית ה-CDNs מספקים dashboard עם hit ratio לפי נתיב (path) או סוג נכס, מה שמאפשר לזהות בדיוק אילו חלקים באתר לא נהנים מ-caching אפקטיבי ולמה. ניטור המדד הזה לאורך זמן, ולא רק בדיקה חד-פעמית בזמן הקמה, חושף רגרסיות שנכנסות עם שינויי קוד עתידיים שאף אחד לא קישר במודע ל-caching.

אבטחה: הגנה מפני Cache Poisoning

תרחיש אבטחה חמור המכונה cache poisoning מתרחש כשתוקף מצליח לגרום ל-CDN לשמור תגובה זדונית תחת URL לגיטימי, שמוגשת לאחר מכן לכל משתמש תמים שמבקש את אותו URL. זה קורה לרוב כשה-cache key לא כולל header שמשפיע בפועל על ה-response — למשל אם ה-origin מחזיר תוכן שונה בהתאם ל-header X-Forwarded-Host אך ה-CDN לא כולל אותו ב-cache key ולא ב-Vary, תוקף יכול לשלוח בקשה עם header מזויף שגורם ל-origin להחזיר תוכן פוגעני (למשל redirect לאתר זדוני), וה-CDN ישמור את התגובה הזו ויגיש אותה לכל משתמש עתידי שמבקש את אותו URL התמים. ההגנה היא בדיקה קפדנית של כל header שמשפיע על ה-response ווידוא שהוא נכלל כראוי במפתח ה-cache או שה-origin מתעלם ממנו לחלוטין אם הוא לא צריך להשפיע על שום דבר.

טעויות נפוצות בפרודקשן

הטעות הראשונה היא הוספת Vary: Cookie בלי הבנה שזה מבטל cache בפועל. השנייה היא cache key שלא כולל את כל הפרמטרים הרלוונטיים, מה שגורם לדליפת תוכן בין משתמשים. השלישית היא Purge-everything כברירת מחדל לכל שינוי קטן — במקום tag-based purging ממוקד, מה שיוצר stampede מיותר ב-origin. הרביעית היא TTL זהה לכל סוגי הנכסים (assets), בלי להבדיל בין תוכן שמשתנה לעיתים רחוקות לתוכן דינמי — מה שגורם או ל-staleness לא רצוי או לביטול חלק גדול מיתרון ה-CDN. חמישית — הזנחת מוניטורינג hit ratio, מה שגורם לרגרסיות בביצועי caching להישאר בלתי מזוהות לאורך שבועות עד שמישהו שם לב לעלייה לא מוסברת בעומס על ה-origin.

מתי CDN לא מספיק

CDN פותר בעיות latency גיאוגרפי ועומס על origin, אך לא פותר בעיות ביצועים במסד הנתונים או בשכבת האפליקציה עצמה. תוכן שדורש חישוב אישי לכל משתמש (dashboard פרטי, נתונים בזמן אמת) פשוט לא מתאים ל-CDN caching רגיל, ודורש שילוב עם שכבת caching מבוזרת ברמת האפליקציה כדי לקבל תועלת דומה בלי לוותר על התאמה אישית.

סיכום

אסטרטגיית CDN caching טובה נבנית על שליטה מדויקת בכותרות Cache-Control ו-Vary, cache key design שמונע דליפת תוכן בין משתמשים, אסטרטגיית purging ממוקדת (tag-based) במקום גסה, ו-TTL מותאם לאופי כל סוג תוכן. הצוותים שמצליחים בזה הם אלה שמתייחסים ל-CDN כשכבה עם כללים מדויקים משלה, ולא כ"קסם" שפשוט הופך הכל למהיר יותר בלי צורך בהבנה מעמיקה של איך הוא מקבל החלטות.

תגיות: CDN · Caching Strategy · Cache-Control · Edge Computing · Purging · Web Performance · DevOps

← חזרה לבלוג · צור קשר