1. Biblioteca
  2. HTTP והרשת
  3. ארכיטקטורת ווב

Actualizado hace 1 mes

הבקשה המהירה ביותר היא זו שלעולם לא שולחים.

בכל פעם שמשתמש טוען את הדף שלך, עשרות משאבים צריכים להיאסף: HTML, CSS, JavaScript, תמונות, גופנים, נתוני API. ללא מטמון, כל משאב דורש מסלול הלוך-וחזור לשרתים שלך. חמישים משאבים פירושם חמישים בקשות, כל אחת שורפת זמן וכוח עיבוד.

מטמון הופך את הסדר. שמור עותקים של נתונים קרוב יותר למקום שבו הם נחוצים — בדפדפן, בשרתי קצה, בזיכרון — ורוב הבקשות לא עוברות כלל בקו התקשורת. דף שלקח 3 שניות נטען תוך 300 אלפיות שנייה. השרת שטיפל במיליון בקשות מטפל עכשיו במאה אלף.

אבל מטמון הוא עסקה עם השטן. אתה מגיש עותקים, לא מקוריים. כש המקור משתנה, העותקים משקרים. לדעת מתי לרענן נתונים ישנים — ביטול תוקף מטמון — הוא אחת הבעיות הקשות באמת בעולם המחשוב.

היכן נמצאים המטמונים

מטמון מתרחש בשכבות מרובות, לכל אחת פשרות שונות.

מטמון הדפדפן שומר משאבים במכשיר של המשתמש. תמונות, CSS וקבצי JavaScript נשמרים מקומית לאחר ההורדה הראשונה. ביקורים עוקבים טוענים אותם מיד — אפס זמן המתנה לרשת. הבעיה: זה עוזר רק למבקרים חוזרים, ויש לך שליטה מוגבלת על מה שדפדפנים שומרים ולכמה זמן.

מטמון CDN שומר תוכן בשרתי קצה המפוזרים ברחבי העולם. משתמש בטוקיו מקבל משאבים משרת בטוקיו, לא מהשרת המקורי שלך בווירג'יניה. זה עוזר לכולם — מבקרים חדשים ומבקרים חוזרים כאחד — ובולע עומסי תנועה לפני שהם מגיעים לתשתית שלך.

מטמון פרוקסי הפוך יושב לפני שרתי האפליקציה שלך ומאחסן תגובות שלמות במטמון. כש אותה נקודת קצה API מתבקשת שוב ושוב, הפרוקסי מגיש תוצאות שמורות מבלי לגעת בצד השרת שלך. Varnish, Nginx ומאזני עומס בענן כולם עושים זאת.

מטמון אפליקציה שומר נתונים במערכות זיכרון כמו Redis או Memcached. תוצאות שאילתות מסד נתונים, ערכים מחושבים, תגובות API יקרות — כל דבר שאיטי לייצור אך נדרש לעתים קרובות. שכבה זו נמצאת בשליטתך המלאה.

מטמון מסד הנתונים מובנה במסד הנתונים עצמו, ושומר נתונים פעילים ותוצאות שאילתות בזיכרון. אינך שולט בזה ישירות, אבל הבנתו מסבירה מדוע שאילתות חוזרות מהירות יותר מהפעלות ראשונות.

כותרות מטמון HTTP

ל-HTTP יש מנגנון מובנה לשליטה במטמון. כותרות על תגובות מספרות לדפדפנים ולמתווכים בדיוק כיצד לטפל בתוכן.

Cache-Control הוא ההוראה הראשית. max-age=3600 פירושו "שמור זאת במטמון למשך שעה אחת." no-cache פירושו "אתה יכול לשמור אותו, אבל בדוק איתי לפני השימוש." no-store פירושו "אל תשמור זאת במטמון כלל" — חיוני עבור נתונים רגישים. public מאפשר לשמור את התגובה במטמונים משותפים (CDNים); private מגביל את השמירה במטמון לדפדפן בלבד.

הוראות משולבות: Cache-Control: public, max-age=86400, immutable מספר למטמונים שמשאב זה לעולם לא ישתנה וניתן לאחסן אותו למשך 24 שעות ללא אימות מחדש.

ETag הוא טביעת אצבע לגרסה ספציפית של משאב. כש התוכן משתנה, ה-ETag משתנה. בבקשות עוקבות, דפדפנים שולחים את ה-ETag הישן בכותרת If-None-Match. אם הוא עדיין תואם, השרת מגיב עם 304 Not Modified — תגובה קטנה במקום המטען המלא.

Last-Modified פועל באופן דומה אך משתמש בחותמות זמן. דפדפנים שולחים If-Modified-Since, ושרתים מגיבים עם 304 אם לא השתנה דבר.

כותרות אלו מאפשרות בקשות מותנות: "האם זה השתנה מאז ששאלתי לאחרונה?" רוב הזמן התשובה היא לא, ותגובת 304 בגודל 200 בייט מחליפה הורדה של 200 קילובייט.

הבעיה הקשה: ביטול תוקף

פיל קרלטון: "יש רק שני דברים קשים במדעי המחשב: ביטול תוקף מטמון ומתן שמות לדברים."

הוא לא התבדח. ביטול תוקף מטמון הוא קשה באמת בגלל בעיה אפיסטמולוגית יסודית: איך יודעים מתי משהו שלא מסתכלים עליו השתנה?

תפוגה מבוססת זמן היא התשובה הפשוטה ביותר: הניחו שדברים נשארים תקפים למשך זמן קבוע. max-age=300 פירושו "סמוך על זה למשך 5 דקות, ואז בדוק." פשוט, צפוי, אבל גס. התוכן עשוי להשתנות אחרי 30 שניות או להישאר זהה במשך שבועות — תפוגה מבוססת זמן לא יודעת ולא אכפת לה.

משכי זמן קצרים שומרים על רענון התוכן אך מפחיתים את יעילות המטמון. משכי זמן ארוכים משפרים את שיעורי הפגיעה אך מגישים נתונים ישנים לאורך זמן רב יותר. אין תשובה נכונה אחת לכולם.

כתובות URL עם גרסאות עוקפות את הבעיה לחלוטין. במקום style.css, הגש style.a3f8c2.css — כש ה-hash מחושב מתכולת הקובץ. כש משנים את ה-CSS, ה-hash משתנה, כתובת ה-URL משתנה, ודפדפנים מורידים את הגרסה החדשה כי מעולם לא ראו את אותה כתובת URL. הגרסה הישנה לא בוטלה; היא פשוט הפסיקה להיות מוזכרת.

זה עובד נפלא עבור נכסים סטטיים. כלי בנייה מייצרים hash של תוכן באופן אוטומטי. אפשר להגדיר max-age=31536000 (שנה אחת) כי כתובת ה-URL עצמה מבטיחה רעננות.

ניקוי ידני מסיר תוכן במפורש מהמטמונים. כש מעדכנים פוסט בבלוג, קוראים ל-API הניקוי של ה-CDN עבור אותה כתובת URL. שליטה מדויקת, אך דורשת אינטגרציה בין ה-CMS לשכבת המטמון.

תגיות מטמון מאפשרות לנקות תוכן קשור בבת אחת. תייג את כל התגובות הקשורות למוצר עם product:123. כש המוצר הזה משתנה, נקה הכל עם אותה תגית. קל יותר לתחזוקה מאשר מעקב אחר כתובות URL בודדות, ונתמך ברוב ה-CDNים.

Stale-while-revalidate מגיש תוכן מהמטמון מיידית תוך בדיקת עדכונים ברקע. המשתמשים מקבלים תגובות מהירות; עדכונים מגיעים בבקשה הבאה. פשרה חכמה בין רעננות למהירות.

אסטרטגיות לפי סוג תוכן

תוכן שונה דורש גישות שונות.

נכסים סטטיים — CSS, JavaScript, תמונות, גופנים — משתנים רק כש מפתחים פורסים. השתמש בכתובות URL עם גרסאות ואחסן במטמון למשך שנה. כל בקשה אחרי הראשונה היא פגיעת מטמון.

דפי HTML הם מסובכים יותר. אתרים סטטיים לחלוטין יכולים לאחסן באגרסיביות. אתרים דינמיים צריכים משכי זמן קצרים יותר או no-cache עם ETags, בודקים רעננות בכל טעינה תוך שימוש בתגובות 304.

תגובות API משתנות מאוד. נתוני ייחוס (קודי מדינות, קטגוריות מוצרים) יכולים להיות במטמון שעות. נתונים ספציפיים למשתמש לא צריכים לחיות במטמונים משותפים, אך עשויים להיאחסן בדפדפן. נתונים בזמן אמת — מחירי מניות, תוצאות שידור חי — לא ניתנים לאחסון במטמון כלל.

תוכן מותאם אישית הוא המקרה הקשה ביותר. כל משתמש רואה נתונים שונים, כך שמטמונים משותפים לא יכולים לעזור. פתרונות: אחסון במטמון בדפדפן בלבד (private), הפרדת מעטפות סטטיות מתוכן דינמי, או הרכבת דפים מותאמים אישית מקטעים מאוחסנים.

דפוסי מטמון

Cache-aside (טעינה עצלה) הוא הדפוס הנפוץ ביותר. בודקים את המטמון תחילה. בפגיעה — מחזירים נתונים מאוחסנים. בהחמצה — שולפים ממסד הנתונים, שומרים במטמון, מחזירים. פשוט, אך בקשות ראשונות תמיד איטיות.

Write-through כותב למטמון ולמסד הנתונים בו-זמנית. עדכון פרופיל משתמש? שני המאגרים מקבלים את הנתונים החדשים באותה פעולה. המטמון נשאר מסונכרן, אבל מאחסנים נתונים שאולי לא יקראו לעולם.

Write-behind כותב למטמון מיידית, למסד הנתונים באופן אסינכרוני. כתיבות מהירות, פעולות מסד נתונים מקובצות — אבל מסוכן. כשל מטמון לפני שהכתיבה הגיעה למסד הנתונים פירושו אובדן נתונים.

Refresh-ahead מרענן באופן יזום פריטים פופולריים לפני שפוקעים, ומבטיח שנתונים חמים לא יחוו החמצת מטמון. עובד היטב לדפוסי גישה צפויים; מבזבז משאבים על נתונים שלא מתבקשים.

מטמון מבוזר

כש האפליקציה פועלת על שרתים מרובים, מטמון מקומי קורס. כל שרת שומר את המטמון שלו. בקשות משתמשים פוגעות בשרתים שונים. המטמונים מתפצלים. אי-עקביות בלתי נמנעת.

Redis ו-Memcached פותרים זאת עם מטמון משותף הנגיש לכל שרתי האפליקציה. כל שרת רואה את אותם נתונים. שיעורי הפגיעה משתפרים כי מילוי מטמון בשרת אחד מיטיב עם כולם.

Redis מציע התמדה, מבני נתונים עשירים (רשימות, קבוצות, קבוצות ממוינות), pub/sub ופעולות אטומיות. Memcached פשוט יותר — אחסון מפתח-ערך טהור — עם זמן המתנה מעט נמוך יותר.

הפשרה: הלוך-וחזור ברשת. חיפוש בזיכרון מקומי לוקח ננו-שניות; חיפוש ב-Redis לוקח אלפיות שנייה. עדיין הרבה יותר מהיר משאילתות מסד נתונים, אבל לא חינמי.

כשל בשרת המטמון חייב להיות מטופל כהלכה. אפליקציות צריכות לפנות לשאילתות מסד הנתונים, לא לקרוס. יש להתייחס למטמון כאל אופטימיזציה, לא כדרישה.

מדיניות פינוי

למטמונים יש זיכרון מוגבל. כש הוא מתמלא, משהו חייב ללכת.

LRU (Least Recently Used) מפנה את מה שלא ניגשו אליו הכי הרבה זמן. עובד היטב כש גישה אחרונה מנבאת גישה עתידית — נכון לרוב עומסי העבודה.

LFU (Least Frequently Used) מפנה פריטים עם ספירת הגישות הנמוכה ביותר. מעדיף נתונים שפופולריים באופן עקבי על פני גישות חד-פעמיות אחרונות.

TTL (Time To Live) מפוגג נתונים לאחר משך זמן קבוע, ללא קשר לדפוסי גישה. לעתים קרובות משולב עם LRU — פריטים שפג תוקפם מפונים תחילה, ואז הפחות-נגישים-לאחרונה.

LRU הוא ברירת המחדל מסיבה טובה. הוא פשוט, יעיל, ומתאים לאופן שבו רוב האפליקציות ניגשות לנתונים בפועל.

עדר הרעם

החמצת מטמון מפעילה שאילתת מסד נתונים. מה קורה כש אלף בקשות נתקלות בו-זמנית באותה החמצה?

אלף שאילתות מסד נתונים. בבת אחת. עבור נתונים זהים.

זהו עדר הרעם: רגע של בורות קולקטיבית שגורם לדהרה למסד הנתונים. זה קורה כש פריטים פופולריים פוקעים מהמטמון, או כש המטמונים מאותחלים ריקים.

פתרונות: קיבוץ בקשות גורם לבקשות מקבילות עבור אותו מפתח לחכות לשאילתת מסד נתונים יחידה. נעילות מטמון מאפשרות לבקשה הראשונה לרכוש נעילה בעוד האחרות ממתינות. Stale-while-revalidate ממשיך להגיש את הערך הישן בעוד בקשה אחת מרעננת אותו.

מדידת מה שחשוב

שיעור פגיעות מטמון: איזה אחוז מהבקשות מוגש מהמטמון? 80% פירושו שהצד השרת מטפל רק ב-20% מהתנועה. כדאי לעקוב אחר זה בכל שכבת מטמון.

זמן המתנה להחמצות: כמה זמן לוקחות החמצות מטמון? זמן המתנה גבוה מזהה שאילתות מסד נתונים איטיות או APIs חיצוניים — מועמדים ראשיים לאחסון במטמון.

ניצול זיכרון: פגיעה עקבית במגבלות קיבולת אומרת שצריך יותר זיכרון או מדיניות פינוי טובה יותר.

ישנות: כמה פעמים משתמשים רואים נתונים מיושנים? זה עומד בסתירה לשיעור הפגיעה — משכי מטמון ארוכים יותר משפרים פגיעות אבל מגבירים ישנות.

טעויות נפוצות

אחסון יתר במטמון: אחסון כל דבר מבזבז זיכרון על נתונים שנגישים לעתים רחוקות ומגיש תוכן ישן יותר מדי. אחסן מה שנגישים אליו לעתים קרובות ויקר לייצור.

אחסון חסר במטמון: פספוס הזדמנויות ברורות. אם אותה שאילתת מסד נתונים פועלת אלף פעמים בדקה, היא צריכה להיות במטמון.

התנגשויות מפתח מטמון: נתונים שונים חולקים את אותו מפתח. יש לכלול את כל הפרמטרים הרלוונטיים — מזהה משתמש, לוקאל, דגלי תכונות — ביצירת המפתח.

התעלמות ממטמון בפיתוח: פריסת שינויים שלא נכנסים לתוקף כי למשתמשים יש עדיין גרסאות ישנות במטמון. השתמש בכתובות URL עם גרסאות עבור נכסים; הגדר זמני מטמון קצרים בסביבות פיתוח.

התייחסות למטמון כמקור אמת: מטמון יכול להיעלם — פונה, פג תוקפו, השרת הופעל מחדש. האפליקציה חייבת לתפקד (לאט) גם בלעדיו.

מטמון הוא פשוט באופן מפתה ברמת הרעיון — שמור עותקים קרוב למקום שבו הם נחוצים — ומורכב באמת בפועל. רווחי הביצועים אמיתיים ומשמעותיים. וכך גם הבאגים כש ביטול התוקף משתבש.

הכישרון הוא לא לדעת איך לאחסן במטמון. הוא לדעת מתי העותק כבר לא טוב מספיק.

¿Fue útil esta página?

😔
🤨
😃