השאלה כמעט תמיד נשמעת אותו הדבר: בלילה האתר ענה תוך עשרים שניות, ועד הבוקר הכול הסתדר מעצמו. אין עוד במה להביט — top עונה על השנייה הנוכחית, ואילו השאלה נוגעת לשלוש לפנות בוקר. להלן מה באמת אומרים מספרי העומס, אילו מהם יש לקרוא בזוגות, ומדוע מדידה חד-פעמית מטעה לעיתים קרובות יותר מכפי שהיא עוזרת.
Load average: שלושה מספרים וטעות נפוצה אחת
uptime
cat /proc/loadavg
nproc
שלושת המספרים הם ממוצעים לדקה, לחמש דקות ולחמש עשרה דקות. אין להשוות אותם לאפס אלא למספר הליבות ש-nproc מדווח. ערך 8 במכונה עם שמונה ליבות הוא עומס מלא אך בריא: יש בדיוק כמות העבודה שהשרת מסוגל לבצע. ערך 2 ב-VPS עם ליבה אחת הוא תור ארוך פי שניים מהיכולת, וכל בקשה ממתינה לתורה.
היחס בין שלושת המספרים מראה את הכיוון. ערך הדקה גבוה בבירור מערך חמש עשרה הדקות פירושו שהעומס עולה בדיוק עכשיו. ההפך פירושו שהשיא כבר חלף ומה שנראה הוא הזנב שלו.
וכעת הטעות שמקלקלת את קריאת המספרים האלה יותר מכול. ב-Linux, load average אינו «ניצול המעבד». בשונה ממערכות Unix אחרות, Linux סופר בו לא רק תהליכים שרצים או מוכנים לרוץ, אלא גם כאלה שנמצאים במצב D — שינה בלתי ניתנת להפרעה. כלומר המתנה לדיסק או למערכת קבצים ברשת. מכאן השרת עם עומס 12 ומעבד כמעט בטל: העבודה אינה מתקדמת, כולם עומדים בתור.
מעבד או דיסק
הפרדת שני המקרים היא הדבר הראשון שכדאי לעשות:
vmstat 1 5
iostat -x 1 3
בפלט של vmstat חשובות שלוש עמודות. r היא כמה תהליכים ממתינים בתור למעבד, b כמה חסומים בהמתנה לקלט ופלט, ו-wa חלק הזמן שבו המעבד עמד בטל והמתין לדיסק. wa שנשאר מעל 10–15 % בעוד us ו-sy נמוכים פירושו שהשרת נבלם על ידי הדיסק: הוספת ליבות לא תעזור, הקיימות פנויות ממילא.
אילו תהליכים ממתינים אפשר לפרט בשמות:
ps -eo state,pid,comm,wchan:30 | awk '$1 ~ /^D/'
דוגמה מהניסיון שלנו. בתצורת ברירת המחדל Suricata כותבת כשלושים סוגי אירועים ואינה מגדירה עבורם שום סבב קבצים — בשרת עובד זה הניב 15 ג׳יגה-בייט של יומנים בתוך יומיים. העומס לא התבטא במעבד עסוק אלא דווקא ב-I/O wait: המערכת כתבה ללא הפסקה וכל השאר עמד בתור מאחוריה. התרופה אינה חבילה גדולה יותר, אלא רשימת אירועים קצרה יותר וסבב מוגדר.
המקרה ההפוך, מעבדי בלבד ופחות מובן מאליו. דף אינטרנט קרא ל-apt בשם המשתמש שתחתיו רץ PHP-FPM. משתמש העל מחזיק מטמון בינארי ב-/var/cache/apt/pkgcache.bin — במארח עם עשרות מאגרים מדובר ב-70 מגה-בייט — וממפה אותו לזיכרון ללא עלות. משתמש רגיל אינו רשאי לכתוב לספרייה הזאת ובונה את המטמון מחדש בכל קריאה. נמדד על אותה מכונה עצמה: 0.01 שניות זמן מעבד כמשתמש על מול 4.2 שניות כמשתמש ללא הרשאות. אותה פקודה, פער של פי ארבע מאות, כפול כל פתיחה של הדף.
המסקנה משני המקרים זהה: עומס מודדים, לא מנחשים. תזמון נפרד של כל פקודה חשודה אורך חצי שעה ומצביע בדרך כלל למקום אחר מזה שממנו יצא החשד.
זיכרון: free אינו מראה את מה שנדמה
free -h
העמודה used כשלעצמה אומרת מעט מאוד, והעמודה free מטעה ממש: Linux מוסר זיכרון שאינו בשימוש למטמון הדפים ומחזיר אותו ליישומים בבקשה הראשונה. העמודה שיש לקרוא היא available — כמה אפשר לתפוס בלי לרדת ל-swap. buff/cache גדול אינו בעיה אלא סימן למערכת שעובדת כשורה.
ב-swap חשוב לא הערך הנוכחי אלא הצורה. עלה וחזר לאפס: היה שיא קצר. עלה פעם אחת ונשאר: השיא כבר היה, דפים הודחו ואיש אינו מחזיר אותם — השרת נראה רגוע אף שברגע מסוים לא הספיק לו הזיכרון. אם ההחלפה מתרחשת כרגע יראו העמודות si ו-so ב-vmstat; ערכים שונים מאפס שם הם צורת ההאטה שהמשתמשים חשים בה יותר מכול.
אם במהלך הצניחה הלילית תהליך פשוט נעלם, ההסבר נמצא בדרך כלל כאן:
journalctl -k --since yesterday | grep -i "out of memory"
dmesg -T | grep -i "killed process"
שורה מסוג Out of memory: Killed process 1234 (mysqld) סוגרת את העניין טוב מכל גרף: מסד הנתונים לא «נפל מעצמו», הליבה עצרה אותו כי הזיכרון אזל.
מי גורם לזה
ps aux --sort=-%cpu | head -10
ps aux --sort=-%mem | head -10
הסתייגות אחת: %CPU ב-ps הוא ממוצע לאורך כל חיי התהליך, ולכן התפרצות קצרה אובדת ברשימה הזאת. עבורה נדרשים top או pidstat 1 5, שמודדים על פני מרווח.
מתי העומס הופך לשאלת אבטחה
100 % מעבד באופן אחיד בלילה, עם תהליך בעל שם חסר משמעות וספריית עבודה ב-/tmp או ב-/dev/shm, היא התמונה הקלאסית של כורה ולא של אתר שגדל. קפיצה בתעבורה הנכנסת יחד עם גידול בכתיבה ליומנים היא מתקפת סיסמאות מתמשכת. נפח יומנים שמזנק בפתאומיות הוא בדרך כלל סערה של התרעות שווא של מסנן כלשהו.
כלי ההגנה עצמם הם קטגוריה נפרדת. באחד השרתים שלנו העומס נשאר סביב שלוש בלי אף מבקר, ובראש ps לפי זמן מעבד מצטבר עמדו לא האתר ולא מסד הנתונים אלא CrowdSec, fail2ban, Falco ו-Suricata. אין זו תקלה ואין זו סיבה לכבות אותם, אבל כדאי להכיר את מחיר ההגנה במספרים: ב-VPS קטן הוא מורגש.
לשם מה התצפית
כל האמור לעיל עונה על השאלה «מה קורה עכשיו». את שאלת הבוקר — מה קרה בשלוש לפנות בוקר — הפקודות האלה אינן מכסות: על הלילה שחלף אין נתונים אם איש לא רשם אותם. והקמת Prometheus עם Grafana עבור VPS יחיד מוטלת בספק, שכן מערך התצפית יוצא כבד מהשרת הנצפה.
די בשורה במסד נתונים כל חמש דקות ובדף אחד שמצייר ממנה את עשרים וארבע השעות האחרונות: load average, ניצול המעבד ובנפרד I/O wait, זיכרון ו-swap, קריאה וכתיבה לדיסק, מידת התפוסה של המחיצה, inodes, מתארי קבצים, חיבורים. על ציר זמן אחד הזוגות נקראים בעין: wa גבוה עם מעבד רגוע, swap שלא חזר לאפס, מתארים שמתקרבים למגבלה — שגיאת too many open files העתידית נראית שעות לפני שהיא מתרחשת. איך זה נראה כשהכול מקובץ יחד מציג דף ההדגמה שלהלן.