Supervisord: מדוע תהליכים נופלים ולא עולים מחדש
התמונה הנפוצה ביותר: מטפל התור הופעל בסשן טרמינל, בלילה הסשן נקטע, התהליך מקבל SIGHUP ומת. איש לא שם לב — עד הבוקר מצטברות בתור אלפי בקשות שלא טופלו, והתורן מרים את השירות ידנית ומנקה את הזנב.
הסיבה היא ששירות שנפל אינו קם מעצמו: הליבה רק מסיימת את התהליך ומעבירה את קוד היציאה להורה. אם ההורה היה מעטפת או סקריפט זמני, אין מי שיאסוף את קוד היציאה — התהליך נשאר יתום, ואף אחד לא יוזם הפעלה מחדש.
אותו מנגנון יוצר תהליכי זומבי: ההורה לא אוסף את הסטטוס, הרשומה נשארת בטבלת התהליכים ומצטברת, עד שלא ניתן ליצור צאצאים חדשים.
Supervisord סוגר את זה ברמת מערכת ההפעלה: הדמון עולה כשירות מערכת, משמש בעצמו כהורה לכל תוכנית ולכן אוסף את קוד היציאה — זומבים לא מצטברים.
הפעלה אוטומטית של תהליכים בשרת מתוארת באופן הצהרתי: בקונפיגורציה של התוכנית מוגדרים פקודה, ספריית עבודה, משתמש, סימן הפעלה אוטומטית, הפעלה מחדש אוטומטית, השהיה בין ניסיונות ומספרם המרבי.
יומני הפעולה של התהליכים אינם הולכים לאיבוד: זרם הפלט והשגיאות נכתב לקבצים נפרדים עם רוטציה לפי גודל ומספר עותקים, ולכן לניתוח תקלה לילית אין צורך לחפש עקבות בכל המכונה. המצב נראה בפקודה אחת, והפעלה מחדש ידנית של האפליקציה מבוצעת ממוקדת, בלי לפגוע בשירותים שכנים. להלן נפרט כיצד זה נסגר בפועל.
מה משתנה לאחר הטמעת בקרת תהליכים
לפני הטמעת בקרת תהליכים, חלק הארי של זמן ההשבתה נבע מנפילת תהליך שאיש לא שם לב אליה: השירות מת בלילה, והדבר התברר רק מהפניות בבוקר. זמן השחזור של השירות הורכב מזמן הגילוי בתוספת הפעלה ידנית — עשרות דקות והשתתפות חובה של התורן.
Supervisord מעביר זאת למצב מנוהל. התהליכים מתוארים באופן הצהרתי: הפעלה מחדש אוטומטית מופעלת לפי קוד יציאה חריג, startretries ו-startsecs חוסמים שירותים "מהבהבים", exitcodes מגדיר רשימת סיומים תקינים — עצירה מתוכננת אינה מתחזה לתקלה ואינה יוצרת לופ הפעלות מחדש.
יכולת הנראות של מצב השירותים נשענת על הפלט של supervisorctl status ועל מטפל האירועים: מעבר למצב חריג נשלח כהתראה לניטור יחד עם זנב הלוג של התהליך. משמרת התורן רואה לא "השרת לא זמין", אלא שירות מסוים, את הסיבה ואת מספר הניסיונות — האבחון מתחיל מהעובדה, לא מחיפוש.
התוצאה מדידה: השחזור מתבצע בשניות ואינו דורש אדם, שיעור ההשבתות עקב נפילות שלא זוהו יורד לאחוזים בודדים, ומספר ההתערבויות הידניות מצטמצם פי כמה. העומס על משמרת התורן מפסיק לגדול יחד עם מספר השירותים.
Supervisord וחלופות: מה לבחור עבור שירות
הבחירה בדרך ההפעלה לעתים רחוקות נתקלת בפונקציונליות: כמעט כל מנהל תהליכים יודע להפעיל מחדש שירות שנפל ולכתוב לוג. ההבדל מתגלה בפרטים — מי עוקב אחרי התהליך, כיצד מתוארות תלויות ההפעלה, מה קורה לאחר אתחול הצומת וכיצד לשנות קונפיגורציה ללא השבתה.
להלן אפשרויות שביניהן באמת בוחרים בפרויקטים. ניתן לשלב ביניהן: בתוך קונטיינר לעתים קרובות נשאר סופרוויזר משלו למספר תהליכי אפליקציה.
| אפשרות | מתי מתאימה | מגבלות |
|---|---|---|
| Supervisord כמנהל תהליכים | מספר שירותים על מכונה אחת: קבוצות, סדרי עדיפויות בהפעלה, סטטוס אחיד | אינו PID 1 — נדרשת הפעלה אוטומטית חיצונית, אינו מנהל שירותים ברמת מערכת ההפעלה |
| מנהל שירותים מערכתי | שירות אחד-שניים, הפעלה אוטומטית בעת האתחול, מגבלות משאבים ויומן | תלויות רק דרך יעדים, אין קבוצות תהליכים גמישות |
| אפליקציה כ-PID 1 בקונטיינר | מיקרו-שירות עם תהליך אחד וקונפיגורציה הצהרתית | אינו מפעיל מחדש תהליכי בן; עבור כמה נדרש סופרוויזר |
| אורקסטרטור | רפליקות רבות, שחזור עצמי, עדכונים מדורגים ללא השבתה | מיותר עבור מכונה אחת, דורש מניפסטים ותשתית נפרדת |
כלל מעשי: תהליך אחד בקונטיינר — מינימום ניהול חיצוני; מספר תהליכים על צומת — Supervisord עם סדרי עדיפויות וקבוצות; שירותי מערכת — למנהל השירותים המערכתי הייעודי. תלויות ההפעלה מגדירים במפורש: אחרת לאחר אתחול השירות עולה לפני שהמסד והמטמון שלו מוכנים, ונופל בלופ של הפעלות מחדש.
שלבי הטמעה: מביקורת ועד מסירה לתפעול
סקר מלאי — מחצית העבודה. לפני כתיבת הקונפיגורציה, המהנדסים שלנו אוספים את כל מה שבפועל מורץ בשרתים: שירותים שהועלו ידנית בסשן זר, משימות מתזמן, סקריפטים שנותרו מקבלנים קודמים, פתרונות "זמניים" שחיים שנים. Supervisord לוקח אותם לניהולו — אבל רק אם ידוע במדויק מה הוא צריך להחזיק ובאיזה סדר.
סדר העבודות
- ביקורת הפעלת שירותים. מתעדים מה פועל כעת, מי בעל התהליך, לאן נכתבים הלוגים, מה מופעל מחדש בעת תקלה ומה מת בשקט.
- מפת תלויות תהליכים. מגדירים מי ממתין למי: האפליקציה לא עולה לפני המסד, משימות רקע — לפני התור. במפה רואים את סדר העלייה ואת סדר העצירה.
- הגדרת ניהול. מעבירים את השירותים תחת Supervisord: הפעלה אוטומטית, כללי הפעלה מחדש, מגבלות, רוטציית לוגים, משתמשי מערכת נפרדים.
- בדיקת תרחישי כשל. הורגים תהליכים, מפילים תלויות, מאתחלים את המכונה — בודקים אם הכול עולה בסדר הנדרש ואם לא נשארים מצבים "חצי-חיים".
- בדיקות קבלה. מריצים רשימת בדיקות מוסכמת בסביבת בדיקה ובסביבת ייצור יחד עם הצוות שלכם; פערים מתקנים לפני המסירה.
- מסירה לתפעול. מוסרים קונפיגורציות, תרשים, הנחיות לפעולות שגרתיות ותקנון פעולה בעת תקלה.
סדר זה מסיר את הסיכון העיקרי — מערכת שעובדת "כל עוד איש לא נגע בה". לאחר המסירה הצוות שלכם מנהל את השירותים בפקודות רגילות, ולא בחיפוש אחרי מי שזוכר איך זה הופעל.
קונפיגורציות, מדיניות הפעלה מחדש ותקנונים
ערכת התיעוד נמסרת לא "לצורך סימון וי": לפיה מהנדס תורן, שלא השתתף בהטמעה, יוכל להרים שירות שנפל ולהבין מדוע הוא נעצר. להלן מה שפיזית נשאר אצל הלקוח במאגר הקונפיגורציות ובבסיס הידע הפנימי.
-
קבצי קונפיגורציה של תהליכים — תיאור אחד לכל שירות בספרייה נפרדת, עם נתיבים, משתני סביבה, מגבלות ניסיונות וסדר הפעלה; הקונפיגורציות מנוהלות בגרסאות, והשינויים עוברים בדיקה.
-
מדיניות הפעלה מחדש — אילו קודי סיום נחשבים לתקינים, כמה ניסיונות ניתן לשחזור, מה לעשות בנפילה חוזרת: להשאיר עצור, להעלות בהשהיה או להסלים.
-
הרשאות גישה לתהליכים — מאיזה משתמש פועל כל שירות, מי רשאי לעצור ולהפעיל מחדש דרך ממשק הניהול, כיצד מוגבלת הגישה ללוגים ולסוקט.
-
מפת קבוצות ותלויות — מה עולה ראשון, איזה תהליך ממתין לשכן, ואיזה אסור לעצור לבדו בלי סיכון לשאר.
-
תקנון משמרת תורן — טבלת "תסמין → פעולה", הסף שבו התורן קורא למהנדס, תבנית הסלמה וסדר תיעוד האירוע.
-
הוראות תחזוקה — כיצד להוסיף תהליך חדש, כיצד להוציא שירות מהרוטציה בעדינות, היכן לראות לוגים וכיצד להחזיר קונפיגורציה לגרסה קודמת.
-
איסוף מדדים והתראות — מצב התהליכים, גידול בצריכת הזיכרון והפעלות מחדש תכופות נראים לפני שהשירות נופל סופית, ולא לפי שיחת בוקר.
כל סעיף עובר בדיקת קבלה בסביבת בדיקה: אנחנו מפילים תהליכים בכוונה ובודקים אם המדיניות פועלת כפי שכתוב בתקנון.
מקרה בוחן: השירות הפסיק ליפול בלי שהצוות שם לב
לפני ההטמעה
השירות נשען על חמישה תהליכים — עובדי תור, מתזמן משימות, מטפל אירועים חיצוניים — והופעל ידנית מהקונסולה. כשעובד נפל, התור המשיך לגדול, והצוות נודע על כך מתלונת לקוח: מהכשל ועד האות הראשון עברו כשלוש שעות, ועוד כשלוש שעות — לניתוח והפעלה מחדש ידנית. במשך חודש תועדו 11 עצירות כאלה, מתוכן 8 התגלו בידי משתמשים ולא בידי הניטור.
מה שינו ומה נהיה
כל תהליך תואר באופן הצהרתי: פקודת הפעלה, תלויות, ספריית עבודה, התנהגות בעת עצירה ומגבלות הפעלה מחדש. Supervisor לקח על עצמו בקרת מצב, הפעלה אוטומטית לאחר אתחול הצומת ושחזור אוטומטי של תהליכים שנפלו — עם השהיה ותקרת ניסיונות, כדי שלופ הנפילות לא יתחזה לעבודה יציבה. זרמי הפלט אוחדו ללוג אחד עם רוטציה, ועל אירועי שחזור וחריגה מהמגבלה נתלו התראות לתורן.
שיעור העצירות שנסגרות ללא אדם עלה מאפס ל-92% — השחזור אורך שניות במקום שעות. זמן התגובה לתקלה אמיתית הצטמצם משלוש שעות לכמה דקות: האות מגיע כעת מהמערכת, לא מהלקוח. התערבויות ידניות נותרו 1-2 בחודש במקום 11, והן קשורות לפגמים בקוד, לא לתשתית.
דוח התוצאות כלל מפת תהליכים, קונפיגורציה, תרשים התראות ותקנון תורן — מצב השירות מובן בלי לקרוא את קוד המקור.
במה Supervisord שונה ממנהל השירותים הרגיל
מנהל השירותים הרגיל (ברוב ההפצות — systemd) מיועד לרמת המארח: יחידה אחת — שירות אחד, תלויות בין יחידות, הפעלה אוטומטית בעת האתחול, מגבלות דרך cgroups ויומן בינארי משותף. עבור דמוני מערכת זה בדיוק מה שצריך — הוא עולה לפני קוד היישום ושורד אתחול יחד עם המארח.
Supervisord סוגר שכבה אחרת — קבוצת תהליכי יישום בתוך סביבה אחת וללא הרשאות סופר-משתמש.
הקונפיגורציה שטוחה: מקטעי INI [program:שם] עם מספר מופעים, תבנית שם תהליך, משתני סביבה, מדיניות ניסיונות חוזרים, קוד יציאה לעצירה תקינה וסדר עדיפויות שקובע את סדר העלייה; [group:...] מאגד עשרה תהליכים ליחידה מנוהלת אחת.
הגמישות בהגדרת ההפעלה היא ההבדל המרכזי. המנהל הרגיל מצפה שהיישום לא יעשה fork ושמתנהג כראוי עם הסוקט; Supervisord עובד גם עם אלה שמסתעפים לדמון, ממתין לשכן לפי פורט או נופל בזמן החימום — מגדירים השהיה לפני ניסיון חוזר, תקרת ניסיונות, אות עצירה.
ניהול הקבוצה נעשה דרך supervisorctl: הפעלה מחדש של כל התהליכים בפקודה אחת, סטטוס לכל מופע ויומן אירועים אחיד — קובץ נפרד לכל תהליך או זרם משותף דרך מטפל האירועים.
היכן שהרגיל אמין יותר: הפעלה אוטומטית לאחר אתחול, בידוד ומגבלות, תגובה לנפילה לפי cgroup ולא לפי קובץ pid מיושן.
לכן הגישות לא מתחרות אלא משתלבות: Supervisord חי תחת שירות מערכתי ובפנים מחזיק קבוצת יישומים — המארח מקבל עלייה צפויה, והיישום — כללי ניסיונות חוזרים גמישים וסדר הפעלה.
ספקות טכניים וטעויות נפוצות בהגדרה
לאחר אתחול השרת אינו חוזר ל"אותו מצב", אלא למה שמתואר בקונפיגורציה: הפעלה אוטומטית מופעלת בדגל autostart, את הסדר קובע priority — מסד הנתונים עולה לפני האפליקציה שמתחברת אליו.
אם תהליך Supervisord הופעל ידנית מסשן, לאחר אתחול הוא לא יהיה: נדרש unit ב-systemd או סקריפט init, אחרת הקונפיגים במקומם, אבל התהליכים אינם.
תוכנית חדשה מוסיפים תוך כדי תנועה: reread קורא מחדש את הקבצים, update מעלה רק קבוצות חדשות וששונו, שאר התהליכים לא מופעלים מחדש. את הקונפיג במקרה זה מחזיקים בקובץ נפרד בספרייה מקושרת — אז עריכה של שירות אחד לא נוגעת בשכנים.
מה יקרה לאחר אתחול השרת?
יעלו רק תוכניות עם autostart=true, והדמון עצמו — דרך unit systemd עם הפעלה אוטומטית. הפעלה ידנית מהטרמינל לא נשמרת.
אפשר לחבר שירות בלי השבתה של האחרים?
כן, reread ו-update נוגעים רק בקבוצות ששונו. אם יש שגיאת תחביר בקובץ, הדמון יסרב לחלוטין וישאיר את הגרסה הקודמת לפעול.
כיצד המערכת מתנהגת כשחסר זיכרון?
את הקורבן בוחר OOM-killer לפי הערך oom_score_adj. הדמון מעלה שוב את התהליך שנפל, ובלי הגבלת startretries נוצר לופ הפעלות מחדש שהורג את השכנים.
מה לעשות אם האפליקציה מולידה תהליכי בן?
אות אחד לתהליך הראשי אינו מספיק: נדרשים stopasgroup ו-killasgroup, אחרת עובדים נשארים תלויים ומחזיקים פורט או נעילה במסד.
אילו טעויות נפוצות ביותר?
startsecs גבוה מדי מסתיר נפילות בהפעלה, היעדר environment נותן שירות בלי המשתנים הנדרשים, ולוגים בלי רוטציה ממלאים את הדיסק. סעיף נפרד — הפעלה כ-root: הדמון מאפשר זאת, עד שנדרש בידוד הרשאות.
נדון במשימה שלכם: מה לשלוח לצורך הערכה
כדי לחזור עם תרשים פתרון ותוכנית עבודה, ולא עם ניסוחים כלליים, נדרש חתך של הקונפיגורציה הנוכחית. ככל שהנתונים מדויקים יותר, כך פחות סבבי הבהרה: ההערכה נשענת על תהליכים אמיתיים, לא על הנחות לגביהם.
שלחו את מה שיש — זה מספיק לגרסה ראשונה של התוכנית:
- רשימת שירותים: שמות תוכניות, פקודות הפעלה, ספריות עבודה, משתני סביבה;
- סדר הפעלה ותלויות: מה עולה ראשון, מה ממתין למוכנות המסד, אילו תהליכים צריכים לפעול במופע יחיד;
- קונפיגורציות נוכחיות, כולל פירוט לקבצים ולספריות נפרדים;
- כיצד מטפלים כעת בהפעלה מחדש לאחר נפילה ואחרי אתחול הצומת: unit של systemd, סקריפט או הפעלה ידנית;
- לאן נכתבים הלוגים וכמה נשמרים: פלט Supervisord או קבצים של האפליקציות עצמן;
- סביבת היעד: צומת אחד או כמה, קונטיינרים או מכונות, הרשאות משתמש השירות;
- מה כואב כעת: תהליכים שלא עולים, לופי הפעלה מחדש, משימות אבודות, גידול בלוגים.
מזה אנו מרכיבים מפת תהליכים, מציעים תרשים ניהולם ומוסרים תוכנית עבודה עם שלבים וסדר פריסה. תארו את המשימה — נחזור עם הערכה ותוכנית.







