הגדרת swap ב-Linux: מדוע השירות קורס בעת שיא בזיכרון
הפעלה מחדש חירומית של השירות מתרחשת בשיא העומס על השרת, בעוד שהניטור באותו רגע מראה זיכרון פנוי. זו אינה שגיאה בגרפים: מחסור בזיכרון פעולה מתבטא לא בנפח הכולל, אלא בזמינות דפים באזור הנדרש וביכולת של הליבה להקצות מקטע רציף. בלוגים של Linux זה נראה כך: oom killer סיים את התהליך, והמפקח הקים אותו מחדש.
את הקורבן בוחרת הליבה לפי oom_score עם התאמת oom_score_adj, ולרוב זה יהיה תהליך העבודה הראשי, ולא זה שצבר את הדליפה: לשירות ארוך-טווח יש צריכה גבוהה יותר — וכך גם סיכוי גבוה יותר להיכלל תחת סיום.
הפעלה מחדש מחזירה חיבורים, אך מאבדת טרנזקציות שלא נכתבו במלואן, וכעבור מספר דקות התמונה חוזרת על עצמה, אם הסיבה לא טופלה.
הגדרת swap ב-Linux במערך הזה אינה "להוסיף זיכרון איטי", אלא להעניק לליבה חוצץ זמן: לפרוק דפים קרים במקום סיום מיידי של התהליך כבר בשיא הראשון. vm.swappiness קובעת באיזו מידה נדחקים דפים אנונימיים, ומגבלות cgroup ומצב vm.overcommit_memory — למי וכמה בכלל מותר לתפוס.
נפרק כיצד זה נסגר: לפי אילו מדדים ניתן לראות התקרבות לכשל לפני ה-OOM עצמו, כיצד מחשבים מגבלות לפי קבוצות תהליכים ומה לעשות אם מערך העבודה של השירות כבר לא נכנס לזיכרון.
האפקט של החלפה מנוהלת: תגובתיות ויציבות
את האפקט של החלפה מנוהלת רואים לא לפי גרף הזיכרון הפנוי, אלא לפי מספר האירועים. לאחר ש-swap והמדיניות לתגובה למחסור בזיכרון הוגדרו בהתאם לפרופיל העומס, השירות בשיאים נכנס לדעיכה צפויה: חלק מהפעולות מאטות, אך התהליכים אינם גוועים ואינם גוררים איתם תהליכים שכנים. להלן — הבדיקות שלפיהן אנו מקבלים את העבודה.
- הפעלות מחדש חירומיות. מספר קריסות התהליכים עקב מחסור בזיכרון יורד בסדר גודל: במקום עשרות אירועים נותרים בודדים, וכל אחד מהם מנותח כאנומליה ולא כרקע.
- דעיכה צפויה. תחת השיא זמן התגובה גדל, אך התורים אינם נקרעים: דפים קרים עוברים להחלפה, מערך העבודה החם נשאר בזיכרון, ואין כשל של השירות.
- תגובתיות חלקה בהתפרצויות. סף הדפים הפנויים ואגרסיביות הדחיקה מכוונים בהתאם לעומס, ולכן bursts קצרים עוברים ללא נפילות — השירות מאט בהדרגה, ולא נקטע.
- בידוד ההשלכות. מגבלות הזיכרון לקבוצות תהליכים והורג מוקדם לפי לחץ על הזיכרון מטפלים רק בשירות הבעייתי; השכנים באותו מכונה אינם מאבדים זמינות.
- מחיקת סוג האירועים. התרומות הליליות והתראות התורנים בגלל קריסות עקב זיכרון יוצאות מהמחזור — נותרות משימות להרחבה מתוכננת, ולא לכיבוי שריפות.
- חזרה מהירה. לאחר השיא השירות נכנס למצב עבודה בתוך עשרות שניות, ללא חימום מחדש של המטמון וללא התערבות ידנית.
כל סעיף נבדק על מתקן בדיקה עם פרופיל עומס משוחזר: מסירים מדדים לפני ואחרי, משווים את תדירות ההפעלות מחדש ואת ההתנהגות בגבול. כך האפקט של ההחלפה נעשה מדיד, ולא הצהרתי.
דרכי ארגון ההחלפה: השוואה ומגבלות
בחירת מדיום ההחלפה קובעת לא רק את הנפח הזמין, אלא גם את זמן התגובה ברגע מיצוי הזיכרון. הליבה סוקרת את אזורי ההחלפה הפעילים לפי סדר עדיפות יורד, ולכן swap-קובץ על אמצעי אחסון מקומי מהיר ומחיצה רחבת נפח על מערך איטי מתקיימים בשלווה יחד: דפים חמים עוברים למהיר, קרים — לנפחי. השגיאה מתחילה במקום שבו מקצים להחלפה מדיום שאינו מיועד לכתיבה מתמדת.
| אפשרות | מתי מתאימה | מגבלות |
|---|---|---|
| Swap-קובץ על אמצעי אחסון מקומי | לפרוס מהר, לשנות גודל, להוסיף אזור נוסף | דורש מקום פנוי במערכת הקבצים, בעת שינוי גודל מתפצל |
| מחיצת החלפה נפרדת | השהיה צפויה, שרתים ללא hibernation, מסדי נתונים | הגודל נקבע בעת החלוקה, משתנה רק בחלוקה מחדש |
| החלפה דחוסה בזיכרון הפעולה | מכונות וירטואליות עם מעט זיכרון, צמתים ללא דיסק מקומי | מבזבזת מחזורי מעבד, אינה מועילה במחסור אמיתי בזיכרון, אינה שורדת אתחול |
| כרך על מנהל כרכים לוגיים | יש צורך לשנות גודל תוך כדי תנועה ללא עצירת שירותים | שכבת הפשטה נוספת, snapshots אוכלים מקום באופן בלתי מורגש |
| אזור על התקן בלוקים מרוחק | אשכולות ללא דיסקים מקומיים, רזרבה חירומית | השהיית רשת הופכת אותו לחסר תועלת תחת עומס |
עדיפות אזורי ההחלפה נקבעת במפורש — ברישומת מערכת הקבצים או במפתח בעת החיבור — אחרת סדר המילוי יהיה אקראי. כיוונון swappiness מבוצע לפי פרופיל העומס: עבור שירותים עם מטמון קבצים גדול הערך מוקטן, עבור מכונות וירטואליות ולקוחות דקים — מוגדל.
ההחלטה מתקבלת לא לפי טעם, אלא לפי מוני החמצות של כשלי דפים ונתונים על לחץ הזיכרון — ואז ההחלפה סוגרת שיאים, ולא מסווה מחסור בזיכרון.
סדר העבודות: מביקורת זיכרון ועד מסירת נהלים
אנחנו מתחילים לא מתיקון הקונפיגורציה, אלא מעובדות: ללא פרופיל צריכה, כל הגדרה של פרמטרי זיכרון הופכת לניחוש. סדר כזה שולל את התרחיש הטיפוסי שבו מפעילים החלפה "ליתר ביטחון" ומקבלים דעיכה בתגובתיות או הפעלה מחדש פתאומית של השירות בשעת שיא.
- ביקורת צריכת זיכרון. מסירים מדדים לפי תהליכים וקבוצות: צריכה שיאית וממוצעת, שיעור דפים אנונימיים, התנהגות בשעות עומס. בנפרד בוחנים מי מחזיק בזיכרון לאחר ההתפרצות.
- תכנית פריסת ההחלפה. קובעים האם דרוש קובץ החלפה או מחיצה נפרדת, על איזה מדיום ובאיזה גודל. מתעדים אילו נתונים מותר לדחות, ואילו חייבים להישאר בזיכרון הפעולה.
- הגדרת ספים וסיום חירומי. מגדירים את עוצמת הדחיקה, מגבלות לקבוצות תהליכים ועדיפויות שלפיהן הליבה בוחרת קורבן בעת מחסור בזיכרון. עדיפויות מפורשות אמינות יותר מבחירה אוטומטית.
- בדיקה תחת עומס. מריצים תרחישים עם מחסור מלאכותי בזיכרון ובוחנים את התוצאה: האם זמן התגובה גדל, האם מופעל הסיום החירומי ואילו תהליכים גוועים ראשונים.
- נצפות. מציבים התראות על התקרבות למגבלות, על גידול בהחלפה ועל עצם הסיום החירומי — האירוע נעשה גלוי לפני שהשירות נופל.
- מסירת נהלים. מוסרים את תכנית פריסת ההחלפה, ערכי הפרמטרים עם הנמקה, נוהל החזרה ורשימת פעולות בעת גידול חד בצריכה.
ערכת מסמכים וקונפיגורציות לאחר ההטמעה
לאחר ההטמעה נשארים לצוות לא רק ההגדרות העובדות, אלא גם מסמכים שלפיהם ניתן לשנותן ולהעבירן הלאה בלעדינו. להלן — רשימת הארטיפקטים שהלקוח מקבל יחד עם התוצאה. כל אחד מהם מיועד למהנדס תורן שיפתח אותו ברגע האירוע, ולא "מתישהו נקרא".
- קונפיגורציית החלפה — קובץ או מחיצה עם רישום ב-fstab, ערכי vm.swappiness, overcommit ו-cache_pressure, ולצידם הערה: מדוע נבחרה התנהגות כזו ומה ישתנה בחזרה לערכי ברירת המחדל.
- מדיניות לפי שירותים — מגבלות זיכרון ב-cgroup ועדיפויות oom_score_adj: מי מקבל סיכוי לשרוד תחת לחץ, את מי הליבה משחררת ראשון.
- תכנית הפריסה — על איזה צומת ומדיום נמצא אזור ההחלפה, כיצד הוא מתייחס לכרכי הנתונים ואיפה צווארי הבקבוק בפעולות דיסק.
- נוהל משמרת תורנית — פעולות שלב-אחר-שלב בעת גידול בצריכת זיכרון והפעלת OOM Killer: מה לבחון, מה להפעיל מחדש, מתי לקרוא למהנדס בכיר.
- תיעוד הזיכרון — פרופיל צריכה לפי שירותים, גבולות הנורמה, סיבות טיפוסיות לגידול ויומן שינויי הגדרות.
- בדיקות ותכנית החזרה — מדדים, התראות ופקודות אבחון בצורה מוכנה, וכן סדר החזרת הפרופיל הקודם, אם השינויים הרעו את התנהגות השירות.
בנפרד מתעדים בעלים: מי בצוות שלכם סוקר מחדש את המגבלות בעת גידול בעומס ולפי אילו סימנים מופעל הסוקר מחדש.
מקרה בוחן: ביטול הפעלות מחדש חירומיות בשיאים
השירות תחת עומס התנהג בצורה יציבה, אך בשעות שיא נתקל בזיכרון. הליבה, שלא מצאה דפים פנויים, סיימה באופן חירומי את התהליכים הכבדים ביותר — ואיתם הלך כל הצומת. התוצאה: שבעה אירועים בחודש, כל אחד עם ניתוח ידני; השחזור ארך עד 45 דקות, וחלק מהבקשות בחלון זה אבדו.
מה שינו
הפרדנו שני תרחישים שונים — התפרצות קצרה ומחסור מתמשך בזיכרון. להתפרצויות הוקצה אזור החלפה על כרך נפרד: הוא מעניק לליבה מרווח כדי להמתין לשחרור זיכרון, ולא לסיים תהליכים. עבור הקונטיינרים הוגדרו מגבלות קשיחות וסדר סיום — הראשון שעוזב הוא המטפל ברקע, שירות החזית נשאר בשורות.
אחרי הצריכה עקבנו דרך Prometheus: ההתראה על גידול מתמשך מכוונת כך שתופעל לפני המנגנון החירומי. זה איפשר ניתוח הסיבה לפני הכשל, ולא אחריו.
את השינויים עיגנו בשלושה חודשי תצפית. סיכום לפני ואחרי:
| מדד | לפני | אחרי |
|---|---|---|
| הפעלות מחדש חירומיות של השירות | 7 בחודש | 1 ברבעון |
| זמן שחזור השירות | עד 45 דקות ידנית | עד 3 דקות אוטומטית |
| שיאים שנספגו בהחלפה | לא נמדד | 9 מתוך 10 |
| קריאות לילה לתורן | 4–6 בחודש | 0 |
ההחלפה אינה מסווה את הדליפה: אם הצריכה גדלה באופן לינארי, מגיעה התראה, והסיבה מנותחת לפני שנגמר המלאי.
במה שונה swap-קובץ ממחיצה נפרדת?
מנקודת המבט של הליבה אין כמעט הבדל: גם הקובץ וגם המחיצה הופכים לאחר אתחול להתקן בלוקים שמתחבר בפקודה אחת. ההבדל מתבטא באופן שבו הנפח הזה נוצר, משתנה ושורד בנייה מחדש של הדיסק.
מחיצה ייעודית היא חתיכה שנחתכה מראש מהחלוקה. הליבה פונה אליה ישירות, ללא שכבת ביניים של מערכת קבצים, ולכן תקורת הקלט-פלט נמוכה יותר, וההתנהגות תחת עומס צפויה יותר. המחיר לכך הוא קשיחות: הגודל נקבע ברגע החלוקה, וכדי לשנותו יש לגעת בטבלת המחיצות ולעיתים תכופות לאתחל.
אפשרות כזו נלקחת במקום שבו ההחלפה קשורה ל-hibernation: הליבה זקוקה למקטע דיסק רציף שמתואר בפרמטרי האתחול.
קובץ החלפה חי במערכת קבצים קיימת. יוצרים ומחברים אותו על הדרך, את הגודל משנים ללא עצירת שירותים, וכמה קבצים עם עדיפויות שונות מאפשרים לפרוס את העומס על דיסקים שונים.
המגבלות נורשות ממערכת הקבצים: בחלק מאמצעי האחסון ברשת ובאמצעי אחסון משכפלים קובץ כזה אינו עובד, ובמצב hibernation דורש חישוב ידני של ההיסט.
הדבר משפיע ישירות על החלוקה: מחיצה אוכלת מקום מראש ומכריחה לתכנן את התכנית בעת ההתקנה, הקובץ משאיר את החלוקה שטוחה ומאפשר להתאים את נפח ההחלפה לעומס האמיתי.
מכאן גם הבחירה: שרתים פיזיים עם hibernation — מחיצה; מכונות וירטואליות, מארחי קונטיינרים וענן — קובץ, כי שינוי החלוקה שם יקר יותר מהסרה או הוספה של קובץ.
שאלות נפוצות על התנהגות המערכת בעת מחסור בזיכרון
לפני תחילת העבודות עולים אותם הספקות: האם השירות לא יתחיל לקרוס בתכיפות גבוהה יותר, האם התגובתיות לא תיפגע, מה ישתנה בקונטיינרים והאם אפשר להסתדר בלי אתחול של הצומת.
חלק מהשאלות נפתרות באבחון — לפי מוני הריגות תהליכים, סטטיסטיקת vmstat ומגבלות cgroup רואים מה קורה כעת ומה צפוי תחת עומס.
כיצד להבין שהשירות נפל בדיוק בגלל זיכרון?
רישום ביומן הליבה מציין את התהליך-קורבן ואת הסיבה — מיצוי זיכרון הצומת או מגבלת הקבוצה. אם אין שורה על הריגה, והתהליך בכל זאת הסתיים, את הסיבה מחפשים ביישום: דליפה, מגביל עצמי, שגיאה בעיבוד השיא. ההבדל עקרוני: במקרה אחד מגדירים את הליבה, בשני מתקנים קוד.
האם נדרשת החלפה אם יש מספיק זיכרון פעולה?
ההחלפה אינה מאיצה את העבודה, אך שומרת מרווח בשיא: דפים בשימוש נדיר עוברים לדיסק במקום הפעלת הריגת תהליך. כדאי לבטל אותה רק במקום שבו השהיה צפויה חשובה — ואז המגבלות מוגדרות קשיחות יותר, עם רזרבה מפורשת לעומס השיא.
האם השירות לא יתחיל לעבוד לאט יותר?
כל עוד הדפים הפעילים נשארים בזיכרון, התגובתיות אינה משתנה. הדעיכה מתחילה בעת דחיקה אקטיבית: רואים אותה בשדות הקלט-פלט ב-vmstat ובגידול בזמן התגובה. לכן ערך swappiness נבחר לפי פרופיל העומס, ולא נשאר בירושה.
כיצד זה עובד בקונטיינרים והאם מיושם ללא אתחול?
בתוך הקונטיינר פועלות מגבלות הקבוצה, ולא זיכרון הצומת: את הקורבן בוחרת ליבת המארח, אך לפי עדיפויות בתוך הקבוצה, ולכן הפרמטרים מסונכרנים בשתי רמות. רוב הערכים משתנים תוך כדי תנועה, והשאר מתועדים בקונפיגורציה — אין צורך לאתחל את הצומת, די להפעיל מחדש את הקונטיינר.
נדון במשימה ונחזור עם תכנית הטמעה
ההתחלה תמיד זהה: קודם ניתוח המצב, אחר כך הערכה ותכנית הטמעה, ורק לאחר מכן שינויים בשרתים חיים. אנחנו לא נוגעים בפרמטרי זיכרון "לפי תחושה" — קודם צריך לראות כיצד swap ומנגנון הסיום החירומי של תהליכים מתנהגים תחת העומס האמיתי שלכם. לשם כך די בתיאור המשימה ובגישה לתצפיות על המערכת, ולא בגישה מלאה לייצור בשלב הראשון.
- ניתוח המצב. מתעדים אילו שירותים חיים על המארח, מה השיאים שלהם בצריכת זיכרון ומה כבר קרה: האם היו הפעלות מחדש, "קיפאונות" תחת עומס, קריסות פתאומיות של תהליכים.
- איסוף נתוני מקור. בוחנים את פרמטרי ההחלפה הנוכחיים, מגבלות הזיכרון לקונטיינרים ולשירותים, היסטוריית הפעלות הסיום החירומי של תהליכים. זה עונה על השאלה היכן בדיוק הולך לאיבוד הזיכרון.
- הערכת העבודות. קובעים את היקף השינויים, סדר השלבים, חלונות לתיקונים ונקודות החזרה. אתם מקבלים הערכה ותכנית לפני שמשהו משתנה בשרתים.
- תכנית הטמעה. מתאמים אילו ספים ועדיפויות מציבים, אילו תהליכים מגנים מפני סיום, כיצד מגדירים את השחרור החירומי של הזיכרון כך שיפגע במטרה הנכונה.
- הטמעה ובדיקה. משנים את הקונפיגורציה, מריצים פרופיל עומס ומוודאים שתחת שיא המערכת אינה נכנסת להפעלה מחדש. התוצאה — התנהגות צפויה במקום נפילות פתאומיות.
- מסירה. מוסרים קונפיגורציות, תכנית ההחלטות שהתקבלו ומדדים שלפיהם השינויים נראים בגרפים.
כדי להתחיל, תָארו את המשימה: אילו שירותים, אילו סימפטומים מטרידים ומה כבר ניסיתם. נחזור עם הערכה ותכנית הטמעה — ללא התחייבות להתחיל בעבודות מיד.







