למה הגדרת XFS כברירת מחדל מפילה כתיבה בעומסי שיא
שרת פרודקשן עם XFS "מהקופסה" מחזיק בדיוק עד לפרץ הכתיבה הרציני הראשון: גיבוי לילי, אינדוקס מחדש של מסד נתונים, חילוץ ארכיונים.
ברגע הזה זמן התגובה לכתיבה עולה בסדר גודל, האפליקציה מקבלת שגיאות timeout של I/O, ולפי המדדים הדיסק לא מנוצל במלואו — העומס עובר להמתנה במקום לעבודה מועילה.
הסיבה היא באופן שבו מערכת הקבצים מחלקת מקום. XFS מחלקת את הכרך לקבוצות הקצאה ומחלקת בלוקים במקביל, אבל כברירות מחדל המקום הפנוי מתפצל במהירות לחתיכות קטנות לא רציפות.
לקובץ חדש מגיעים בלוקים מקבוצות שונות, המטא-דאטה מתעדכנת לעתים קרובות יותר, וזרמי הכתיבה מתייצבים בתור על נעילות של קבוצות אלה — במקום זרם ליניארי מתקבל מקוטע.
היומן מוסיף משלו: גודל המאגרים, סדר השטיפה, המיקום על המדיום. כשדרך נקודת שטיפה אחת עוברות גם פעולות סינכרוניות קטנות וגם פעולות רציפות גדולות, הגדולות ממתינות לקטנות.
זו בדיוק הירידה בביצועי I/O שנראית בגרפים כ"דיסק איטי", למרות שלמעשה איטית תור הפעולות של הכתיבה, ולא המדיום.
ext4 מתנהגת אחרת ועד נקודה מסוימת סולחת על רשלנות, אבל נתקלת בתקרה שלה בכתיבה מרובת תהליכים בכרכים גדולים. לכן הבחירה בין השתיים אינה עניין של טעם, אלא של פרופיל עומס.
בהמשך — פרמטרי mount לפרופיל מסוים, גודל ויישור של קבוצות הקצאה, מדיניות הקצאה לקבצים מסוגים שונים, הוצאת היומן ומעקב אחר פיצול מקום פנוי. נפרט איך זה נסגר.
מה נותנים חלוקה נכונה ופרמטרי mount
חלוקת הכרך ואפשרויות ה-mount קובעות שלושה דברים מדידים: פיזור זמן התגובה לכתיבה בעומס שיא, היקף הפעולות שאובדות בהפסקת חשמל פתאומית, ומשך החזרה של השרת לפעילות לאחר תקלה.
בגרסאות עדכניות של Red Hat XFS נבחרת כברירת מחדל, אבל ברירות המחדל מיועדות לעומס "ממוצע" — למשימה מסוימת מדייקים אותן. בהמשך — מה שאנחנו בודקים בכל צומת פרודקשן לפני העלאה לפעולה.
- יישור תחילת הכרך והמחיצות לגבולות שהמדיום מבין: נעלם מצב "קריאה-שינוי-כתיבה" לכל בלוק, הכתיבה מפסיקה להיות איטית פי כמה מהקריאה, והתגובה אינה תלויה במיקום הנתונים.
- רזרבה למטא-דאטה וגודל inode בעת יצירת הכרך: המקום עבורם לא נגמר הרבה לפני מיצוי הכרך עצמו — אין צורך לעצור את השירות ולהעביר נתונים.
- יומן מערכת הקבצים: לאחר הפסקת חשמל העקביות של המטא-דאטה משוחזרת, והשחזור מצטמצם להרצה חוזרת של הטרנזקציות האחרונות — שניות במקום בדיקה מלאה של הכרך שנמשכת עשרות דקות.
- נפח ומספר המאגרים של היומן: פרצי כתיבה בשעות שיא לא מתייצבים בתור — פיזור זמן התגובה מצטמצם, ולא גדל במדרגות.
noatimeאוrelatimeבפרמטרי mount: מסיר עשרות אלפי עדכוני מטא-דאטה מיותרים ביום, והמדיום לא כותב את מה שאף אחד לא קורא.- תור I/O לפי פרופיל העומס: בזרימה משולבת ההמתנה לכתיבה מתקצרת, וגיבוי כבד מפסיק לעכב טרנזקציות.
fstrimקבוע ובקרת מילוי: בלוקים פנויים מוחזרים למדיום, והידרדרות הכתיבה לא מגיעה בפתאומיות.- קונפיגורציית החלוקה וה-mount במאגר: השחזור לאחר תקלת שרת הוא משוחזר, ולא "לפי הזיכרון של המהנדס".
השוואת גישות: אפשרות, התאמה, מגבלות
אף מערכת קבצים לא מנצחת "באופן כללי" — להשוואה יש משמעות רק יחד עם האופן שבו הנתונים מפוזרים בין הכרכים. XFS מחזיקה טוב יותר כתיבה מקבילה וקבצים גדולים, ext4 צפויה יותר בפעולות קטנות ופשוטה יותר לתחזוקה. בהמשך — ארבע תוכניות חלוקה שביניהן באמת בוחרים, עם מגבלות כנות של כל אחת.
| תוכנית | מתי מתאימה | היכן נשברת |
|---|---|---|
| קבוצות הקצאה נפרדות: נתונים, יומנים ואינדקסים על כרכים משלהם | כתיבה מקבילה גבוהה, קבצים גדולים, גדילה בלי חלוקה מחדש | אי אפשר להקטין כרך במקום; snapshots — רק באמצעי האחסון |
| תוכנית קלאסית עם יומן (ext4, כרך יחיד) | עומס אחיד, שירותים עם פעולות קטנות, rollback פשוט | היומן הופך לצוואר בקבוק בזרם כתיבה; בדיקת שלמות בכרך גדול נמשכת זמן רב |
| גישת snapshot: תמונת כרך לפני שינוי | עדכונים תכופים, צריך rollback תוך דקות | snapshots צורכים מקום פנוי; כשהמאגר מתמלא, כל נקודות ה-rollback אובדות |
| הקצאה דקה של כרך | נפח הנתונים אינו ידוע מראש, צריך רזרבה לגדילה | פיצול וירידת ביצועי כתיבה כשנגמרים הבלוקים, חובה לבקר מילוי |
בפועל משלבים תוכניות: את השורש ומחיצות המערכת מחזיקים על מערכת קבצים עם יומן, נתונים ויומנים מוציאים לכרכים נפרדים, ו-rollback לפני עדכון עושים ב-snapshot. הסדר נבחר לפני הפריסה — חלוקה מחדש על שרת חי עולה בזמן השבתה, ולכן מחליטים מראש ובודקים בהרצת עומס.
סדר העבודות: מהערכה ועד מסירה לתפעול
העבודות מתקדמות במסלול אחד: קודם — עובדות על האחסון, אחר כך קונפיגורציה ורק לאחר בדיקות מאושרות — פרודקשן. אף פרמטר לא נלקח "כמו אצל כולם": הוא או מאושר לפי פרופיל העומס, או לא מיושם.
- ביקורת אחסון. אוספים תפוסת כרכים, פיזור גדלי קבצים, חלק הכתיבה הרציפה והאקראית, חלונות שיא. בפלט — פרופיל עומס במקום מילים כלליות על "הרבה קבצים קטנים".
- פריסת נתונים. מפזרים את הנתונים בין כרכים ונקודות mount: בנפרד יומנים ומטא-דאטה, בנפרד כתיבה חמה, בנפרד ארכיונים. הפריסה מיד מראה איזה מחיצה תידרדר ראשונה.
- חישוב פרמטרים של מערכת הקבצים. לפי הפריסה הזו קובעים גודל בלוק, מצב יומן, מגבלות inode ואפשרויות mount. כל סעיף מוסבר: מה הוא נותן ומה אנחנו משלמים עבורו.
- בדיקות עומס לדיסק. מריצים סינתטיקה וחזרה על פרופיל אמיתי: בודקים השהיות ותפוקה על פרק זמן ארוך, ולא על פרץ של דקה.
- בדיקת עמידות לתקלות. מדמים כשל דיסק, ניתוק, התמלאות כרך ואובדן חשמל, ואז — שחזור ובדיקת שלמות. מתעדים זמן השבתה ונפח נתונים שעולים מהגיבוי.
- העברה לפרודקשן. מיישמים בשלבים, עם חלון תחזוקה ותוכנית חזרה: אם המדדים יוצאים מהגבולות, חוזרים לקונפיגורציה הקודמת בלי אובדן נתונים.
- מסירה לתפעול. מוסרים תיעוד, מפת פריסה, ספי ניטור ונוהל לתקלות אופייניות; נשארים בקשר עד שהצוות שלכם יבצע את הפעולה המתוכננת הראשונה בעצמו.
ערכת תיעוד, קונפיגורציות ונהלים
אנחנו מוסרים לא אוסף פקודות מפוזרות, אלא ערכה שלפיה אפשר לתחזק את התשתית בלעדינו: המהנדס פותח את הקובץ המתאים ורואה לא רק מה הוגדר, אלא גם למה נבחר דווקא המצב הזה. בהמשך — מה שנשאר אצל הצוות שלכם לאחר העבודות.
- קונפיגורציית mount — קבצי עבודה לכל שרת עם הסבר שורה־שורה לאפשרויות: למה הופעל
noatime, במה מוצדקdiscardבמדיות, ואיפה הושאר במכוון מצב יומן ברירת מחדל. - תרשים מחיצות וכרכים — מפת דיסקים, מחיצות ונקודות mount עם יישור לגבולות בלוקים ומקום שמור לגדילה.
- מדיניות גישה לנתונים — בעלים והרשאות על תיקיות אפליקציות ויומנים, חשבונות שירות נפרדים במקום עבודה מ-superuser.
- הוראות הרחבת כרך — סדר צעד־אחר־צעד: להוסיף קיבולת, להגדיל כרך לוגי, ואז להרחיב את מערכת הקבצים בזמן אמת (
xfs_growfsאוresize2fs) בלי לעצור את השירות. - נוהל תחזוקת שרת — תדירות בקרת מילוי, ספי התראות, חלונות בדיקות שלמות מתוכננות וסדר פעולות בעת הפסקת חשמל.
- סדר שחזור — מה לעשות במקרה של פגיעה במטא-דאטה, איך פורשים מגיבוי ואיך לוודא שהנתונים שלמים לאחר מכן.
- יומן שינויים — כל שינוי בקונפיגורציה עם סיבה ודרך rollback.
מקרה בוחן: טיפול בהידרדרות כתיבה בשרת קבצים
שרת איסוף לוגים קיבל זרם מכמה עשרות שירותים, ובשיא העומס הפסיק להדביק אותו. תור פעולות הכתיבה גדל, זמן התגובה חצה timeout, ואחרי אתחול שחזור הכרך נמשך שעות. האבדות היו סמויות: חלק מהאירועים נזרקו בצד המקורות, והלוגים לא הגיעו לדיסק בדיוק כשהתבצעה חקירת תקלה.
מדדים נאספו ב-Prometheus — עומק תור I/O, זמן המתנה לכתיבה וזמן שחזור. התמונה התבררה כטיפוסית: יומן מערכת הקבצים ישב על אותו התקן כמו הנתונים, יישור למערך לא היה, והאפליקציה סינכרנה כל אירוע, והפכה זרם כתיבות לזרם המתנות.
מה שינו
פיצלנו את הנתונים ויומן מערכת הקבצים להתקנים שונים, עברנו ל-XFS עם בלוק שמתאים לפרופיל הכתיבה בפועל ויישור ל-stripe של המערך. הוספנו מכסות ומדיניות ניקוי סגמנטים ישנים, הפחתנו את תדירות הסנכרונים הכפויים ברמת האפליקציה, והשארנו את הבטחת המסירה ברמת מערכת הקבצים.
מדדים לפני ואחרי
תור הפעולות בשיא הצטמצם מאלפי כתיבות לא גמורות למאות, והפסיק לגדול עם הזמן. זמן התגובה באחוזון ה-99 קטן בערך פי עשרים, וחלון השחזור לאחר תקלה — משעות לדקות. אין יותר פספוס אירועים בשיא, ורזרבת העומס מאפשרת לחבר מקורות חדשים בלי להחליף חומרה.
הגדרת XFS או ext4: מה לבחור לעומס הנוכחי?
אין מנצח חד־משמעי: שתי המערכות מנהלות יומן מטא-דאטה, אבל מפזרות נתונים אחרת ומחזיקות כתיבה מקבילה אחרת. בחירת מערכת קבצים נעשית לא לפי "חדש או ישן", אלא לפי פרופיל I/O: גודל קובץ ממוצע, חלק הגישה האקראית מול הרציפה, ומספר הכותבים בו־זמנית.
ext4 מספיקה במקום שבו העומס משולב והקבצים קטנים — קונפיגורציות, סשנים, תיקיות עם מיליוני אובייקטים, לוגים של אפליקציות. הקצאת בלוקים נדחית אוספת כתיבות קטנות לפעולה אחת, ויומן המטא-דאטה נותן שחזור צפוי לאחר תקלה.
תוכנית קלאסית עם יומן מכסה היטב אתרי אינטרנט ושירותי עזר, ואת הכרך אפשר להקטין בעת הצורך בלי ליצור מחדש.
XFS מתגלה בקבצים גדולים ובכתיבה מקבילה: קבוצות הקצאה נפרדות מאפשרות לזרמים לכתוב לאזורים שונים בכרך בלי להיתקל במנעול משותף. זה נראה במשימות זרימה — לוגים, גיבויים, מדיה, מסדי נתונים עם בלוקים גדולים. הצד השני: מחיקה המונית של קבצים קטנים איטית יותר, ואי אפשר להקטין כרך.
קריטריונים לעומס אנחנו אוספים מהשירות עצמו: משחזרים את הפרופיל שלו על עותק נתונים ומשווים זמני פעולות אמיתיות, לא מספרים סינתטיים. אחר כך בוחרים אפשרויות mount וגודל בלוק לפי הכתיבה הממוצעת, בודקים את התנהגות הכרך בזמן התמלאות וכיבוי חירום. ההחלטה נשענת על מדידות של עומס מסוים, לא על ויכוח כללי.
ספקות טכניים: תאימות, סיכונים ו-rollback
הצוות ההנדסי של הלקוח ממעט לשאול במה מערכת קבצים אחת טובה מרעותה. השאלה נשמעת מעשית יותר: מה יקרה לשרת שכבר עובד אם מחליפים אותה. בהמשך — מה שאנחנו מפרקים לפני תחילת העבודות: העברת נתונים במערכת חיה, השפעה על גיבוי, סדר rollback ובדיקת שלמות.
החלפת מערכת קבצים אינה פירמוט מחדש של הדיסק, אלא העברת עץ לכרך מוכן עם מיתוג קצר של השירות; הכרך הישן נשאר ללא שינוי עד סוף תקופת התצפית, ולכן תמיד יש דרך חזרה.
האם אפשר לעבור בלי עצירה ארוכה של השירות?
כן. הכרך החדש עולה לצד הישן, הנתונים מועברים בהעתקה ברקע תוך שמירה על הרשאות, בעלים, קישורים קשיחים ומאפיינים מורחבים, ואז מתבצעת השלמת השינויים. המיתוג לנקודת mount חדשה נמשך דקות — עצירה נדרשת רק לצעד הזה, ולא לכל ההעברה.
איך מבצעים rollback לשינויים אם משהו משתבש?
Rollback — החזרת נקודת ה-mount בקונפיגורציה והפעלה מחדש של השירות, בלי העתקה חזרה של נתונים. הכרך הישן אינו משתנה ואינו משוחרר עד לסיום תקופת התצפית המוסכמת על החדש. אם אחרי המעבר מתגלה בעיה, החזרה נמשכת אותו זמן כמו המעבר קדימה.
מה משתנה בגיבוי?
בדרך כלל כלום: snapshots נעשים ברמת הכרך, ולא בתוך מערכת הקבצים, ותסריט ההעתקה נשאר כמו שהיה. לפני העבודות בודקים שסוכן הגיבוי קורא נכון הרשאות ומאפיינים מורחבים בכרך החדש, ומשחזרים עותק בקרה במלואו.
איך בודקים שלמות נתונים אחרי העברה?
משווים את העץ לפי רשימת קבצים עם checksums לפני ואחרי, בודקים הרשאות, בעלים וקישורים קשיחים, ואז קוראים באופן סלקטיבי קבצים גדולים ותמונות. אי־התאמות מתקנים לפני מיתוג השירות, לא אחריו. בנפרד בודקים מילוי מטא-דאטה — הוא מראה את הרזרבה לגידול העומס.
איך להתחיל: מה לדייק ובאיזה סדר להתקדם
הערכת עבודות אחסון מתחילה לא במספרים, אלא בנתוני פתיחה: בלעדיהם תוכנית היישום יוצאת כללית ולא מביאה בחשבון לא את פרופיל העומס ולא את דרישות שימור הנתונים. בהמשך — מה אנחנו מדייקים בשיחה הראשונה, כדי לחזור עם רצף שלבים מסוים ולוחות זמנים.
- פרופיל עומס: מה כותב לדיסק לעתים קרובות יותר — מסד נתונים, לוגים של אפליקציות, תורי הודעות, שכבת קונטיינרים; מה היחס בין קריאה לכתיבה והאם יש פרצים בשעות דיווח.
- שכבת חומרה: דיסקים מקומיים או אחסון רשתי, מערך ורמת עמידות התקלות שלו, רזרבת דיסקים לגידול עתידי.
- מצב נוכחי: איזו מערכת קבצים פרוסה, עם אילו פרמטרי mount ויצירה, אילו שינויים נעשו ידנית אחרי ההתקנה ועל ידי מי.
- דרישות לנתונים: האם צריך snapshots, באיזו תדירות נלקח גיבוי ואיזה זמן שחזור נחשב סביר לשירות.
- חלון עבודה: האם מותר להעביר את השרת למצב תחזוקה, האם אפשר מיגרציה בלי לעצור את השירות ומי מאשר את החלון.
- תחזית נפח: באיזו מהירות מתווספים נתונים והאם מתוכננת הרחבת מחיצה בעתיד הנראה לעין — מזה תלויה הרזרבה בחלוקה.
סדר השלבים לאחר מכן פשוט: מתעדים את נתוני הפתיחה, מכינים תוכנית עבודה עם חלוקה להכנה, העברה ובדיקה, מריצים את הקונפיגורציה על סטנד בדיקה עם עותק נתונים, ורק אחר כך נוגעים בפרודקשן. תארו את המשימה — נחזור עם הערכה לאחסון, תוכנית יישום ולוחות זמנים, ולא עם מילים כלליות.







