כיוונון הקרנל ב-Linux: היכן נחנק שרת תחת עומס
המעבד טעון בחציו, הזיכרון עודנו פנוי, אך השירות מגיב בתדירות הולכת וגוברת באיחור ומנתק חלק מהבקשות בגלל חריגת זמן המתנה. המסקנה «אין מספיק כוח» אינה מתאמתת על ידי הרחבה: צוואר הבקבוק של השרת מתגלה לא בחומרה, אלא בפרמטרים של הקרנל שנשארו בברירת מחדל. כיוונון הקרנל ב-Linux מתחיל באיתור המקום שבו נשבר מסלול הבקשה, ולא בעריכת ההגדרות.
בזמן התפרצות תעבורה הקרנל מצטבר חיבורים נכנסים לתור של סוקט מאזין, שאורכו מוגבל. ברגע שהוא מלא, חיבורים חדשים נזרקים לפני שהאפליקציה הספיקה לקבל אותם — ומכאן המשתמשים ה"נעלמים" כשהשירות עדיין חי. לצידו פועלת מגבלה שקטה שנייה: מספר מתארי הקבצים הפתוחים לכל תהליך.
כל סוקט, לוג וחיבור למסד נתונים צורך מתאר, ופגיעה בתקרה נראית כמו כשל של השירות תחת עומס בלי אף שגיאה בלוגים.
השהיות קופצניות בשיאים — זה עניין של מתזמן המשימות ופיזור פסיקות הרשת בין הליבות. אם תור הפסיקות נסגר על ליבה אחת, היא עסוקה בפענוח מנות, האפליקציה ממתינה לזמן מעבד, והגדלת מספר תהליכי העבודה רק מחמירה את התמונה. בנפרד אנו בודקים את טבלת החיבורים: כשזו מתמלאת הקרנל מתחיל לאבד מנות של סשנים שכבר הוקמו.
את הסימפטומים קוראים דרך מדדים: אורך תור הקליטה, מונה החיבורים שנזרקו, שגיאות סוקטים, וחלק הזמן בפסיקות בכל ליבה. מכאן — תיקון ממוקד של פרמטרים והרצה תחת עומס, ולא העתקה של סטים "אוניברסליים" מהאינטרנט. נפרט כיצד זה נסגר.
מה נותן קרנל מכוונן תחת עומס שיא
קרנל Linux כברירת מחדל מיועד לעומס אוניברסלי: תורי חיבורים, מגבלות מתארים, התנהגות המתזמן ומערכת הזיכרון מותאמים לפרופיל ממוצע.
תחת שיא זה מתבטא לא כ"שרת איטי", אלא במקומות ספציפיים: חיבורים נזרקים בגלל תור מלא, האפליקציה נתקעת בתקרת המתארים הפתוחים, וקלט/פלט ממתין מאחורי תהליכים שאין להם שום קשר לדיסק.
השהיית תגובה. כאשר פרמטרי קליטת החיבורים ומאגרי הרשת מוביאים לפרופיל אמיתי, חלק מההמתנה בכניסה לאפליקציה נעלם — הבקשות אינן עומדות בתור מלא. זה נראה כהתכווצות של זנב ההתפלגות: הממוצע כמעט לא משתנה, אך התגובות האיטיות ביותר מואצות באופן ניכר, והמשתמשים מפסיקים לחוות נפילות בודדות.
תפוקה על אותה חומרה גדלה בלי החלפת שרתים — בזכות פריסת התהליכים בין הליבות, מתזמן קלט/פלט שמתאים לפרופיל הדיסק ומגבלות זיכרון הגיוניות. העתודה נוצרת בדיוק במקום שבו קודם נתקעו בתקרה: עיבוד פסיקות רשת, פעולות דיסק, הקצאות.
אפקט נפרד — היעלמות של סוג כשלים בגלל מיצוי משאבי מערכת. השירות אינו נופל כולו תחת שיא: הוא מחזיק תור, מחזיר שגיאות צפויות ומתאושש מעצמו, בלי התערבות ידנית. את היציבות הזו אי אפשר להשיג רק בתיקונים בקוד — חלק מהתקרות חיות ברמת הקרנל.
השוואת גישות לכיוונון הקרנל
הגישות נבדלות לא בעומק, אלא בסיכונים שצוות נוטל על עצמו. סט פרמטרים טיפוסי סוגר מגבלות בסיסיות — תורי חיבורים, מספר מתארים, אגרסיביות החלפה — וכמעט אינו דורש הכנה.
כיוונון ממוקד נשען על הפרופיל של שירות מסוים, וניתוח מלא מוסיף בדיקת עומס: ההחלטות מאומתות במדידות על סטנד, ולא בניסיון של פרויקטים קודמים.
| אפשרות | מתי מתאימה | מגבלות |
|---|---|---|
| סט פרמטרים טיפוסי | שירות טיפוסי בלי שיאים בולטים, נדרש אתחול צפוי | אינו מתחשב בפרופיל האפליקציה: חלק מהערכים אינם נותנים אפקט, חלק מסיטים את האיזון בין זיכרון לדיסק. השינויים אינם מוסברים היטב בעת ניתוח תקלה |
| כיוונון ממוקד לשירות | ידועים צווארי הבקבוק: תורי חיבורים, זמן תגובה, גידול במספר הקבצים הפתוחים | שבריריות: החלפת גרסת אפליקציה או שינוי בסכמת העבודה שוברים את ההנחות. נדרשת סקירה חוזרת בכל עדכון משמעותי |
| ניתוח מלא עם בדיקת עומס | מתאר קריטי, שבו טעות שווה השבתה; קיים סטנד ופרופיל עומס ניתן לשחזור | ארוך יותר בלוחות זמנים ויקר יותר בזמן צוות; המדידות אינן תקפות אם הסטנד אינו בר-השוואה לפרודקשן |
מה לקחת בחשבון בעת הבחירה
מורכבות התחזוקה גדלה יחד עם העומק: ככל שמשתנים יותר ערכים, כך חשוב יותר להחזיק אותם בקונפיגורציה, ולא בתיקונים ידניים על מכונה חיה. אחרת הסביבה לאחר בנייה מחדש סוטה מהפרודקשן, וניתוח תקלה מתחיל בשחזור מה ומדוע שונה.
סדר העבודות: מצילום מדדים ועד מסירת נוהל
אנחנו בונים את העבודה כמחזור אחד: קודם מדידות, אחר כך שינויים. כיוונון קרנל בלי קו בסיס מתועד הופך לניחוש, וחזרה לאחור בלי ערכים מקוריים שמורים — להשבתה במתאר הייצור. לכן כל שלב מסתיים בארטיפקט שנשאר אצל הצוות שלכם.
- אבחון השרת וצילום מדדים. אוספים קו בסיס תחת עומס אמיתי: עומס מעבדים, תורים לדיסק, פיזור זיכרון, פסיקות רשת, מספר חיבורים. את המדידות עושים בשיא, ולא בשעות שקט — אחרת צוואר הבקבוק לא יתגלה.
- איתור צוואר הבקבוק. משווים בין המדדים וקובעים היכן אובדת הביצועים: הזיכרון נדחק לדיסק, תור הקלט/פלט אינו מספיק, עיבוד הפסיקות נופל על ליבה אחת.
- תכנית השינויים. מתעדים אילו פרמטרים של הקרנל משנים, באילו גבולות ומה זה נותן לפי החישוב. לצידם — תכנית חזרה לאחור ורשימה של מה שאנחנו במודע לא נוגעים בו, כדי לא לשלם על השיפור בחוסר יציבות.
- הטמעה. את התיקונים מבצעים בחלקים ובאופן הפיך, שומרים את הקונפיגורציות המקוריות, ובמידת האפשר — בלי אתחול. אחרי כל צעד משווים למדדים ועוצרים אם האפקט אינו מתאמת.
- בדיקה תחת עומס. מריצים את אותו פרופיל תעבורה ומשווים לפני/אחרי: זמן תגובה, תפוקה, התנהגות בשיא ובמקרה של כשל של שירות שכן. מסתכלים לא רק על הממוצעים, אלא גם על זנב ההשהיות.
- מסירת הנוהל. מוסרים מסמך: מה שונה ומדוע, אילו ערכים הם המקוריים, כיצד לחזור לאחור, אילו מדדים וספים להחזיק בניטור. מכאן והלאה את השרת מפעיל הצוות שלכם.
קונפיגורציות, תכניות ונוהלים בתוצר הסופי
כיוונון קרנל בלי ארטיפקטים חי עד ההפעלה מחדש או העדכון הראשון של האימג' — ואז הערכים חוזרים לברירת המחדל, ואיש אינו זוכר מדוע הם היו שונים. לכן כל מה שאנחנו משנים מתועד כקבצים שמוחלים אוטומטית, ולא נערכים ביד על מכונה חיה. הערכה נשארת אצל הצוות שלכם ועובדת בלעדינו.
- קבצי קונפיגורציה — פרמטרי הקרנל, מגבלות התהליכים וכללי תורי הרשת מחולקים לפי ייעוד (sysctl.d, limits.d, הגדרות מתזמן הקלט/פלט), ולא נערמים לקובץ אחד משותף, שבו עריכת שירות אחד משנה את התנהגות האחרים.
- מפת שירותים — מהו התהליך, אילו פורטים וסוקטים הוא מחזיק, לאילו תורים של אירועים ומתארים הוא פונה, באיזו שירות הוא עולה ובמה הוא תלוי.
- תיאור המגבלות — טבלה «פרמטר — ערך נבחר — נימוק — גבול הדרדרות»: רואים מהיכן הגיע המספר ומה ישתנה בעת הזזה למעלה או למטה.
- הוראות חזרה לאחור — חזרה מודרכת לפרופיל הקודם: איזה קובץ לשחזר, איזו פקודה להריץ, לפי אילו סימנים לוודא שהסטנד חזר למצב תקין.
- נוהל תחזוקה — מה ובאיזו תדירות נבדק, אילו שינויים עוברים אישור, כיצד מנוהל היסטוריית התיקונים ומי אחראי על הצומת בתורנות.
- פרופילים לפי תפקידים — סטים נפרדים למאזן עומסים, למסד נתונים ולצומת אפליקציות, כדי שתיקונים לעומס אחד לא ישברו את האחר.
- סקריפטים להחלה ולהשוואה — פריסת הקונפיגורציה מהמאגר עם שמירת צילום של הערכים בפועל לפני ואחרי; הרצה חוזרת אינה משנה את התוצאה, וסטיות נראות מיד.
כל סעיף נבדק במתאר שלכם: אנחנו מריצים חזרה לאחור והחלה של הפרופיל על עותק של הצומת, כדי שההוראות יהיו מעשיות ולא תיאורטיות.
מקרה בוחן: הסרנו דרדרות תחת עומס שיא
השירות קיבל תעבורה דרך Nginx, אחריו פעל מאגר אפליקציות ומסד נתונים משותף. בפרופיל רגיל הכול החזיק מעמד, אך בהתפרצות חגיגית מספר הפניות בו-זמניות גדל פי שלושה — והכשלים החלו לפני שהמעבד או הדיסק הגיעו לקצה.
הדרדרות התרחשה בשכבת הרשת, ולא בלוגיקת האפליקציה.
חלק הלקוחות שלא זכו להשלמת החיבור גדל מ-0.2% ל-7%, זמן התגובה באחוזון ה-99 — פי ארבעה, וזנב השגיאות אחרי השיא נמשך כ-20 דקות נוספות: תור הקליטה לא הספיק להתפנות, תהליכי העבודה נתקעו במגבלת המתארים, וחלק מהסוקטים נתקעו בהמתנה לסגירה.
כיווננו את קליטת החיבורים לאורך התור בפועל: העלינו net.core.somaxconn ו-tcp_max_syn_backlog, הרחבנו את טווח הפורטים המקומיים והפעלנו שימוש חוזר בסוקטים בהמתנה לסגירה.
בהמשך — fs.file-max ומגבלות מתארים לתהליכי העבודה, דפים עצומים שקופים מושבתים, שחרור מתון של הזיכרון במקום swap אגרסיבי ופסיקות רשת שפוזרו בין הליבות במקום עיבוד על ליבה אחת.
כיצד אישרנו את התוצאה
הרצנו את אותו פרופיל תעבורה פעמיים, תוך השוואה של התפלגות זמן התגובה, ולא של הממוצע. כשלי החיבור ירדו לאפס, האחוזון ה-99 שב לרמת העומס הרגיל, הזנב אחרי השיא הצטמצם מ-20 דקות לדקה, והשיא עצמו המערכת מחזיקה עם עתודה של פי ארבעה בחיבורים.
סוג הכשלים שהוסר — כשל בהשלמת החיבור וכשל בגלל מיצוי מתארים: הלקוח אינו מקבל עוד שגיאה לפני שהבקשה הגיעה לאפליקציה.
במה נבדל כיוונון הקרנל ב-Linux מתבניות טיפוסיות?
ענף הקרנל העדכני אינו מספק סט פרמטרים אוניברסלי: תבניות טיפוסיות כמו «swappiness באחד, לכבות huge pages, להגדיל somaxconn» משכפלות את פרופיל העומס של אותו שירות שלמענו נאספו.
לאפליקציה עם חיבורים ארוכים ומטמון קר, סט כזה אינו מזיק, אך עבור מסד נתונים עם ערכת עבודה חמה בזיכרון הוא מאיץ קלט/פלט של דיסק ומנפח את השהיית הזנב.
לכן הצעד הראשון הוא פרופיל העומס, ולא עריכת פרמטרים של הקרנל: כמה חיבורים נפתחים ונסגרים בשנייה, איזה חלק מהזמן עובר בהמתנה לרשת, האם יש התפרצויות בזיכרון ובכתיבה לדיסק.
מכאן כבר רואים מה לגעת בו — תור החיבורים הנכנסים, שימוש חוזר בסוקטים במצב TIME_WAIT, ספי שחרור של דפים מזוהמים או גודל ה-huge pages.
הסיכון בהעתקה הוא שחלק מההגדרות מייעל תרחיש אחד על חשבון אחר. השבתת huge pages שקופים מסירה היתקעות אצל מסדי נתונים מסוימים ומוסיפה תקורת תרגום כתובות אצל אחרים; שחרור אגרסיבי של דפים מזוהמים מקצר התפרצויות כתיבה אך פוגע בזרמים סדרתיים. פרמטר שנעקר מהקשרו הופך בקלות למקור לכשלים תחת שיא.
ניתוח פרטני נראה כך: מצלמים מדדים תחת עומס אמיתי, משנים פרמטרים אחד-אחד, משווים את השהיית הזנב ואת צריכת הזיכרון לפני ואחרי, ומתעדים את התוצאה בקונפיגורציה עם הערה — למה הוא שם ואיך חוזרים ממנו לאחור. כך הישימות של ההגדרות נשארת מאומתת, ולא בירושה ממאמר.
ספקות טכניים לפני תחילת העבודה
תיקונים בקרנל של שרת פעיל מפחידים בצדק: חלק מהפרמטרים מתבטאים רק תחת עומס, כשכבר אין זמן לחזור לאחור. אנחנו משנים פרמטר אחד בכל פעם ואחרי כל אחד משווים מדדים — אורך התור, השהיות תגובה, חלק החיבורים שנזרקו.
עד כמה בטוח לשנות פרמטרים של הקרנל על שרת חי?
רוב ההגדרות מוחלות בזמן אמת. המסוכנים אינם התיקונים עצמם, אלא השינויים «לפי העין»: אנחנו מחזיקים רשימת פרמטרים עם ערכי יעד ומפעילים אותם במנות.
האם נדרשת השבתת השירות?
ככלל, לא: מאגרי רשת, מגבלות מתארים ומתזמן הקלט/פלט נקבעים בלי לנתק חיבורים. חלון זמן נדרש רק לפרמטרי העלייה של הקרנל.
כיצד חוזרים לאחור בהגדרות אם המצב החמיר?
את השינויים מבצעים דרך קובץ קונפיגורציה, ולא בפקודות חד-פעמיות, ולכן החזרה לאחור היא שחזור הגרסה הקודמת. את המצב הקודם שומרים עד שהמצב החדש ישרוד את שעות השיא.
האם ההגדרות נשמרות לאחר עדכון המערכת?
כן: הפרמטרים מעוגנים בקבצים הנקראים בזמן העלייה, ולא נקבעים ידנית בסשן הנוכחי. לאחר עדכון הקרנל אנחנו בודקים שהקונפיגורציה נקלטה באותו סדר.
כיצד להבין שצוואר הבקבוק הוא דווקא בקרנל?
מתחילים באבחון: השהיות בשכבת הרשת, תורים, פסיקות, פיזור בין הליבות. אם המגבלה היא במגבלות המערכת ולא בלוגיקת האפליקציה, הכיוונון ייתן אפקט.
נדון במשימה ונחזור עם אומדן ותכנית
כדי שהאומדן יהיה מדויק מהפעם הראשונה, אנחנו זקוקים לפרופיל עומס אמיתי: אותו צומת עבור מסד נתונים ועבור עיבוד בקשות דורש פשרות שונות במתזמן, במגבלות ובזיכרון. ככל שנתוני הקלט מלאים יותר, כך נדרשות פחות סבבי הבהרה והתכנית יוצאת קונקרטית יותר.
לפנייה די לצרף:
- פרופיל עומס: אילו שירותים פועלים על הצומת, עומס שיא וממוצע, קצב יומי ושבועי, האם יש התפרצויות חדות.
- מדדים לתקופה: עומס מעבדים, המתנה לקלט/פלט, צריכת זיכרון, תורים בממשקי רשת — בצורה שבה מערכת הניטור שלכם מצלמת אותם.
- תיאור הצומת: ענף הקרנל וההפצה, הרכב החומרה או פרמטרי המכונה הווירטואלית, סוג ומצב הדיסקים.
- תכנית הסביבה: תפקיד הצומת בקבוצת עמידות בכשלים, איזון עומסים, תלות בשירותים שכנים.
- היסטוריית תקלות: מה בדיוק דרדר ובאיזה עומס, אילו שינויים כבר ניסו ולמה הם הובילו.
- מגבלות: חלונות לשינויים ואתחולים, דרישות להרשאות גישה, כללי אבטחה וביקורת.
זה מספיק כדי לחזור עם הרכב העבודות, אומדן לוחות זמנים ותכנית בדיקות לכל שינוי. תארו את המשימה — נדון במה שיש טעם לגעת בו, ומה בטוח יותר להשאיר כמו שהוא.







