דיסק שרת מלא ב-100% (0 בתים חינם): שחזור מסד נתונים קרס מתי rm ו apt נכשל בגלל חוסר אינודות/מרחב¶
מספרי חירום שונים לפי מדינה. דף זה משתמש ב-911, המספר של ארצות הברית וקנדה. מדינות רבות אחרות משתמשות ב-112, 999 או מספר אחר. מצא את המספר עבור המדינה שלך.
מגלה ששרת לינוקס לייצור פגע 100% שימוש בדיסק (0 bytes free) או 100% ניצול אינוד (df -i) בזמן הפעלת מסד נתונים PostgreSQL, MySQL/InnoDB, MariaDB או SQLite פעיל הוא אחד ממצבי הכשל המסוכנים ביותר בניהול מערכות. באפס בתים או אפס אינודים פנויים, המשבר מתגלגל במהירות: ליבת מערכת ההפעלה לא יכולה עוד ליצור שקעי תחום יוניקס ב /tmp או /var/run, bash לא מצליח להשלים את הכרטיסיות כי הוא לא יכול לכתוב צינורות מעטפת זמניים, apt או dnf לא יכול לרוץ לנקות חבילות מכיוון שמנהלי חבילות דורשים קבצי נעילה זמניים, ומנוע מסד הנתונים שלך קורס באמצע יומן Write-Ahead (WAL) מחסום או מסרב להיסגר בצורה נקייה מכיוון שהוא אינו יכול להקצות בלוק בודד של 4 קילובייט (0.004 מגה-בייט) עבורו .pid או לנעול קובץ. גרוע מכך, מנהלים מבוהלים פועלים לעתים קרובות rm -rf /var/log/*.log על קבצי יומן ריבוי ג'יגה-בייט וצפו באימה כמו df -h עדיין מדווח 100% Use% (0 Avail), או שהם מוחקים אנושות pg_wal (pg_xlog) או ib_logfile0 כדי לפנות מקום, משחית לצמיתות את מסד הנתונים מעבר לשחזור העסקאות. אם מחקת בטעות קבצי מסד נתונים קריטיים במהלך ניסיון ניקוי, עצור מיד ועבור אל בשוגג rm -rf או Shift-Delete לקריאה בלבד מחדש וגילוף אינודה; אם חומרת האחסון הבסיסית שלך זורקת שגיאות קלט/פלט או ננעלה מפני כתיבה, התייעץ מצב SSD ו-NVMe פתאומי לקריאה בלבד ו-TRIM משבית הצלה או שחזור קבצי Word, Excel, PDF ומסד נתונים פגומים. אם הפסקה זו משפיעה על מערכות בטיחות חיים בבית החולים, שיגור חירום או שירותים ציבוריים קריטיים, התקשר למספר החירום המקומי שלך (911 בארצות הברית ובקנדה, 112 ברחבי האיחוד האירופי, 999 בבריטניה) או עיין במדריך הגלובלי שלנו של מספרי חירום.
תעשה את זה עכשיו¶
- לא למחוק
pg_wal/,pg_xlog/,pg_multixact/,ib_logfile*,undo_*, או-wal/-shmקבצים כדי לפנות מקום: מחיקת יומן Write-Ahead או קובצי רישום/ביטול של InnoDB בזמן שמסד נתונים קרס או לא מסומן, הורסת את הרשומה היחידה של דפים לא מחויבים ודפים בטיסה. מסד נתונים עם דיסק מלא ניתן לשחזור ב-100 אחוז ברגע שמתפנה מקום; מסד נתונים שקובצי ה-WAL שלו נמחקו ידניתrmיסבול משחיתות בלתי הפיכה של עץ B וערימה. - ** אבחן תוך 5 שניות אם נגמרו לך בלוקים של דיסקים (
df -h), מחוץ לאינודים של מערכת הקבצים (df -i), או החזקת קבצים פתוחים לא מקושרים (lsof +L1)**: - רוץ
df -hכדי לבדוק קיבולת בלוק וdf -iלבדיקת קיבולת האינודה. שרת עם 50 גיגה-בייט (53.6 מיליארד בתים) של שטח דיסק פנוי עדיין יזרוקNo space left on device (ENOSPC)אםdf -iמופעיםIUse% = 100%(בדרך כלל נגרמת ממיליוני קבצי הפעלה זעירים, מטמון או קבצי סליל דואר). - אם
df -hמופעים100%בשימוש (0 Avail) גם אחרי שרצתםrmעל קבצי יומן ענקיים, הפעלsudo lsof +L1. כל קובץ שנמחק עםrmתוך כדיnginx,rsyslog,docker,postgres, אוmysqldעדיין מחזיק מתאר קובץ פתוח ממשיך לצרוך 100 אחוז מחסימות הדיסק שלו עד שהתהליך יתחיל מחדש או שתקטוע את המתאר ישירות. - פנה ג'יגה-בייט של שטח בשנייה אחת ללא הפעלה מחדש של דמונים על-ידי חיתוך קבצים פתוחים במקום (
: > /path/to/logfileאו: > /proc/<pid>/fd/<n>): - במקום
rm /var/log/syslog(מה שמשאיר בלוקים נעולים על ידי היומן הפועל), אפס את הקובץ במקום באמצעות הפניית ה-null של ה- shell:sudo sh -c ': > /var/log/syslog'אוsudo truncate -s 0 /var/log/syslog. - אם כבר רצתם
rmעל קובץ יומן עצום וdf -hלא ירד, מצא את מזהה התהליך שלו (PID) ומתאר קובץ (FD) בsudo lsof +L1ולחתוך אותו ישר דרך ממשק הקרנל procfs:sudo sh -c ': > /proc/<PID>/fd/<FD>'. החלל יחזור לdf -hבאופן מיידי. - פתח את הנעילה של חדר נשימה חירום מיידי
ext4/ext3על ידי הורדת אחוז חסימת השורש השמור (tune2fs -m 1): כברירת מחדל,ext4שומרת 5 אחוזים מכל המחיצה (25 gigabytesעל א500 gigabyteדיסק) אך ורק עבורUID 0(root), כלומר שירותים שאינם שורש כמוpostgres(UID 109),mysql, וwww-dataלהכותNo space left on deviceב-95 אחוזי ניצול. קבל בחזרה 80 אחוז מהעתודה הזו באינטרנט תוך שנייה אחת עם אפס זמן השבתה על ידי ריצהsudo tune2fs -m 1 /dev/sda1(או מכשיר חסימת השורש שלך מfindmnt /). - ** ואקום
systemd-journaldיומנים בינאריים ומטמוני חבילות ישנים בבטחה**: הפעלsudo journalctl --vacuum-size=50M(שמסובב בבטחה ומנקה בינארי/var/log/journalארכיון עד 50 מגה-בייט) וsudo apt-get clean(אוsudo dnf clean all), אשר מוחק הורדת.deb/.rpmארכיון ב/var/cache/apt/archives/ללא צורך לכתוב למסד הנתונים של dpkg. - לאחר ששטח של לפחות 1 ג'יגה-בייט עד 5 ג'יגה-בייט (1.07 מיליארד עד 5.36 מיליארד בתים) פנוי, העלה את מסד הנתונים במצב משתמש יחיד או שחזור כדי להשלים את נקודת ה-WAL שלו לפני שתאפשר תעבורת לקוח: אפשר ל-PostgreSQL, MySQL/InnoDB או SQLite להפעיל מחדש את יומן הכתיבה שלו (
WAL), שטפו דפים מלוכלכים לקבצי הנתונים הראשיים, ומחזרו בצורה נקייה את מקטעי ה-WAL הנפוחים שלו לפני פתיחת חומת האש של האפליקציה או שרת האינטרנט מחדש.
Danger
לעולם אל תברח pg_resetwal (או pg_resetxlog) ב-PostgreSQL או innodb_force_recovery = 6 ב-MySQL פשוט בגלל שהדיסק התמלא: פועל pg_resetwal מוחק את מצביעי יומן העסקאות ומאלץ את PostgreSQL להתחיל עם דפי נתונים כתובים למחצה, מה שמבטיח אובדן שורות שקט, מפתחות ראשיים כפולים ועצי B שבורים של מפתח זר. ב-99.9 אחוז מקריסות מסד הנתונים המלאות בדיסק, פשוט שחרור של 2 ג'יגה-בייט עד 10 ג'יגה-בייט (2.1 מיליארד עד 10.7 מיליארד בתים) של מקום במחיצה והפעלת דמון מסד הנתונים מאפשר בדרך כלל שחזור קריסה אוטומטי (REDO שלב) כדי לסיים בצורה נקייה עם אפס אובדן נתונים.
עץ החלטות: שרת עם רווח אפס וטריאג' מסד נתונים קרס¶
השתמש בעץ ההחלטות הזה כדי לזהות מדוע מערכת ההפעלה מדווחת ENOSPC (No space left on device) ובחר את נתיב ההתאוששות הלא הרסני המדויק:
flowchart TD
Start["זריקת שרת או מסד נתונים: לא נותר מקום במכשיר (ENOSPC)"] --> CheckDF["הפעלה: df -h ו-df -i"]
CheckDF --> DiagType{"מה מדווח df?"}
DiagType -->|"df -h מציג 100% שימוש (0 זמינות) ו-df -i < 95%"| BlockFull["Block Exhaustion: בדוק אם du -shx / מתאים ל-df -h"]
DiagType -->|"df -h מציג GBs בחינם אבל df -i מציג 100% IUse"| InodeFull["מיצוי Inode: מיליוני קבצים זעירים של 0 עד 4KB"]
DiagType -->|"גם df -h וגם df -i Show < 90% בשימוש"| RamOrQuota["מגבלה נסתרת: בדוק את מכסות הדיסק df -h /tmp (tmpfs RAM מלא), Docker Overlay2, או XFS/ext4"]
BlockFull --> GhostCheck{"האם כבר הפעלת rm על קבצים גדולים ללא נפילת df?"}
GhostCheck -->|"כן: du הוא הרבה יותר קטן מ-df"| UnlinkedFD["הפעל: sudo lsof +L1 -> חתוך קובץ רפאים דרך: > /proc/PID/fd/FD"]
GhostCheck -->|"לא: קבצים אמיתיים ממלאים את הדיסק"| EmergencySpace["צור חדר נשימה מיידי (1 GB עד 5 GB)"]
EmergencySpace --> Ext4Check{"האם מערכת הקבצים היא ext4 / ext3?"}
Ext4Check -->|"כן"| Tune2fs["הפעלה: sudo tune2fs -m 1 /dev/root_dev (משחרר באופן מיידי 4% מהדיסק עבור משתמש שאינו Root DB)"]
Ext4Check -->|"לא (XFS / Btrfs / ZFS)"| TruncLogs["חתוך יומנים במקום (: > /var/log/syslog) והפעל journalctl --vacuum-size=50M"]
InodeFull --> InodeClean["מצא ספרייה עם מיליוני קבצים באמצעות find / -xdev -printf '%h\n' | מיון | uniq -c | מיון -k 1 -ר | head -20 -> מחק עם find -delete"]
UnlinkedFD --> DBRecover["המשך אל Database Engine WAL ו-B-Tree Recovery"]
Tune2fs --> DBRecover
TruncLogs --> DBRecover
InodeClean --> DBRecover
RamOrQuota --> DBRecover
DBRecover --> WhichDB{"איזה מנוע מסד נתונים קרס?"}
WhichDB -->|"PostgreSQL"| PGFlow["שמור את pg_wal שלם -> התחל את Postgres כדי להפעיל מחדש את WAL -> הפעל CHECKPOINT; -> זרוק חריצי שכפול מעופש"]
WhichDB -->|"MySQL / MariaDB (InnoDB)"| MyFlow["שמור את ib_logfile* שלם -> התחל את mysqld -> ניקוי יומנים בינאריים באמצעות PURGE BINARY LOGS -> בצע אופטימיזציה של טבלאות"]
WhichDB -->|"SQLite3"| SqFlow["גיבוי .db + .db-wal + .db-shm -> הפעל את PRAGMA wal_checkpoint(TRUNCATE) או sqlite3 broken.db '.recover'"]
שלב 1: מדוע פקודות סטנדרטיות (rm, apt, tab-completion) נכשל ב-0 בתים בחינם¶
כאשר מחיצת לינוקס פוגעת ב-100 אחוז בלוק או מיצוי האינוד, פקודות תיקון סטנדרטיות נכשלות בדרכים בלתי צפויות:
- לוחצים Tab ב bash זורק cannot create temp file for here-document: No space left on device: מודרני bash-completion סקריפטים יוצרים קבצים זמניים ב /tmp. אם /tmp שוכן על השורש / מחיצה במקום א tmpfs תושבת RAM, השלמת מעטפת ו heredocs (<<EOF) נכשלים. תקן זאת מיד על ידי הצבעה TMPDIR לזיכרון RAM משותף:
apt-get autoremove או dpkg --configure -a נכשל עם No space left on device: מתי /boot או / מלא ב-100 אחוז, apt לא יכול להסיר גרעינים ישנים כי dpkg תחילה עליך לכתוב עדכוני סטטוס לתוך /var/lib/dpkg/updates/. במקום זאת, רוץ sudo apt-get clean (מה שמבטל קישורים לקובץ שמור .deb ארכיון ב /var/cache/apt/archives/ ישירות), או לקטוע תמונת גרעין אחת שאינה בשימוש /boot (sudo sh -c ': > /boot/initrd.img-<old-unused-version>') לתת dpkg 50 מגה-בייט (52.4 מיליון בייט) שהוא צריך כדי לפעול sudo dpkg --purge linux-image-<old-unused-version>.
- rm /path/to/dir/* נכשל עם Argument list too long: מתי df -i הוא ב-100 אחוז בגלל ספרייה כמו /var/lib/php/sessions מכיל מיליוני קבצים זעירים, עם תווים כלליים (*) מציף את הקרנל ARG_MAX חיץ (2 megabytes) לפני rm מתחיל. השתמש find עם -delete במקום זאת:
5 הסיבות הנבדלות של No space left on device (ENOSPC)¶
לפני נגיעה בקבצי מסד נתונים כלשהם, השווה את חמשת התרחישים האלה כדי לאשר איזה משאב מיצה בפועל:
| פקודת אבחון | סימפטום נצפה | סיבה שורשית | תיקון מיידי של 10 שניות |
|---|---|---|---|
df -h לעומת sudo du -shx / |
df -h מופעים 100% בשימוש (0 Avail), אבל du -shx / מסתכם רק 60% מגודל הדיסק. |
פתח קבצים לא מקושרים ("קבצי רפאים"): מישהו רץ rm על יומן ענק או קובץ זמני תוך כדי תהליך (nginx, java, postgres, docker) עדיין היה פתוח. |
רוץ sudo lsof +L1, אתר את PID ו FD של (deleted) קובץ, והפעל sudo sh -c ': > /proc/<PID>/fd/<FD>'. |
df -hמופעים 95% בשימוש, 0 Avail |
Used + Avail אינו שווה Size; root יכול לכתוב קבצים, אבל postgres או mysql מקבל ENOSPC. |
ext4 חסימות שורש שמורות (5% ברירת מחדל): ext4 מעכב 5 אחוז מהחסימות ממשתמשים שאינם שורשיים (UID > 0) כדי למנוע נעילות שורש וקיטוע. |
רוץ sudo tune2fs -m 1 /dev/<partition> להוריד את העתודה מ-5 אחוז ל-1 אחוז באופן מיידי באינטרנט. |
df -i |
df -h מציג ג'יגה-בייט של מקום פנוי, אבל df -i מופעים IUse% = 100% (IFree = 0). |
תשישות אינודה: ext4 יש מספר קבוע של אינודים שנוצרו ב mkfs זמן; מיליוני קבצים זעירים צרכו כל חריץ אינודה. |
מצא את תיקיית האשם (sudo find / -xdev -printf '%h\n' \ | מיון \ | uniq -c \ | מיון -k 1 -r \ | ראש -10) and run sudo find /culprit/dir -סוג f -delete. |
סודו mount \ | grep /path |
du -sh /var/log הוא זעיר, עדיין / יש 40 גיגה-בייט של שטח חסר. |
קבצים נסתרים מתחת לנקודת הר: תהליך נכתב ב-40 גיגה-בייט /mnt/backup בזמן שהכונן החיצוני לא הותקן, ומאוחר יותר מישהו הרכיב דיסק מעל /mnt/backup, מסתיר את הקבצים הבסיסיים du. |
התקן Bind את מערכת הקבצים הבסיסית לתצוגה זמנית (sudo mkdir /dev/shm/rootview && sudo mount --bind / /dev/shm/rootview), לבדוק du -sh /dev/shm/rootview/mnt/*, ומחק את הקבצים המוסתרים. |
btrfs filesystem df / |
df -h מציג 20 גיגה-בייט בחינם ב-a Btrfs נפח, ובכל זאת כותבים נכשלים עם ENOSPC. |
Btrfs מיצוי נתח מטא נתונים: Btrfs מקצה מקום לנתחי נתונים ומטא נתונים נפרדים; אם כל השטח הגולמי שלא מוקצה ננעל בנתחי נתונים דלילים, נתחי Metadata יגיעו ל-100 אחוז. |
הוסף באופן זמני התקן לולאת קבצי RAM של 2 גיגה-בייט (dd if=/dev/zero of=/dev/shm/btrfs_ram bs=1M count=2048 && sudo btrfs device add -f /dev/shm/btrfs_ram /), לרוץ sudo btrfs balance start -dusage=10 /, אז sudo btrfs device remove /dev/shm/btrfs_ram /. |
שלב 2: החזרת שטח דיסק בבטחה תוך פחות מ-60 שניות¶
בצע את השלבים המדויקים הבאים כדי להחזיר מקום בנפח של בין 500 מגה-בייט ל-50 ג'יגה-בייט (0.53 מיליארד עד 53.6 מיליארד בייטים) מבלי לפגוע בתהליכים פעילים:
שלב 1: חתוך קבצים שנמחקו ("רוח רפאים") פתוחים באמצעות /proc/<pid>/fd/¶
אם אתה או סקריפט logrotate אוטומטי כבר מחקת קבצים גדולים אך שטח דיסק לא הוחזר, בדוק את טבלת הקבצים הפתוחים הלא מקושרים של הקרנל:
תסתכל עלSIZE/OFF עמודה (נמדדת בבתים). אם אתה רואה ערך כמו:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NLINK NODE NAME
mysqld 1942 mysql 6u REG 259,1 34896609280 0 918273 /tmp/ibXz91aB (deleted)
rsyslogd 612 syslog 7w REG 259,1 18253611008 0 131092 /var/log/syslog.1 (deleted)
rsyslogd (PID 612, מתאר קובץ 7w -> 7) מחזיק קובץ יומן שנמחק בגודל 18.2 גיגה-בייט פתוח. אל תעשה kill -9 תהליכי מסד נתונים (mysqld או postgres) לשחרר /tmp קבצים אם אתה יכול לפנות מקום במקום אחר קודם. במקום זאת, אפס את מתאר קובץ היומן (PID 612, FD 7) ישירות בזיכרון הליבה:
רוץ df -h מיד: כל 18.2 גיגה-בייט משוחררים במקום מבלי להפעיל מחדש אף שירות.
שלב 2: תביעה מחדש ext4 בלוקים שמורים באינטרנט עם tune2fs¶
על כל ext4 או ext3 מערכת הקבצים, בדוק את ספירת החסימות השמורות הנוכחית:
postgres), MySQL (mysql), Redis (redis), ואפליקציות אינטרנט של SQLite (www-data, node) פועלים כמשתמשי שורש ללא הרשאות, ליבת לינוקס חוסמת אותם מלהשתמש ב-5 האחוזים האחרונים של הדיסק. הורדת יחס החסימה השמור מ 5% ל 1% (או 0% בזמן חירום פעיל) נכנס לתוקף באופן מיידי על מערכת קבצים מותקנת חיה:
בנפח מסד נתונים של 1 טרה-בייט (1,000 גיגה-בייט), פקודה יחידה זו מעבירה מיד 40 גיגה-בייט (42.9 מיליארד בתים) של שטח בר כתיבה למנוע מסד הנתונים שלך כדי שיוכל לסיים את נקודת ה-WAL שלו. לאחר שהמשבר ייפתר והנתונים הישנים יטוקו, החזר את הרזרבה 2% או 5% (sudo tune2fs -m 2 /dev/nvme0n1p1).
שלב 3: חתוך יומני טקסט פעילים במקום ושואב journald¶
מצא את הקבצים הגדולים ביותר במערכת הקבצים הבסיסית (הישאר באותה מערכת קבצים עם -xdev כך שלא תבזבז זמן בסריקה /proc או תושבות חיצוניות):
/var/log/nginx/access.log, /var/log/syslog, /var/log/postgresql/*.log, דוקר *-json.log):
לעולם אל תברח rm על קובץ יומן פעיל. חתכו אותו לאפס בתים במקום כך שמתאר הקובץ של הדמון יישאר חוקי ומצביעי היסט מאופסים בצורה נקייה:
sudo truncate -s 0 /var/log/nginx/error.log
sudo truncate -s 0 /var/lib/docker/containers/*/*-json.log
systemd-journald יומנים בינאריים (/var/log/journal/):
שלב 3: שחזור PostgreSQL לאחר קריסה של 100% בדיסק מלא (pg_wal נפיחות)¶
כאשר שרת PostgreSQL נגמר בשטח הדיסק, הוא נרשם ביומן PANIC: could not write to file "pg_wal/xlogtemp.1234": No space left on device, מבטל מיד את תהליכי ילד הדואר, ומסרב להתחיל.
למה pg_wal (pg_xlog ב-PostgreSQL 9.6 ומעלה) ממלא את כל הדיסק¶
בפעולה רגילה, PostgreSQL כותב כל שינוי לקבצי מקטע של 16 מגה-בייט (16.7 מיליון בתים) בפנים $PGDATA/pg_wal/ וממחזר אותם אחרי כל אחד CHECKPOINT ברגע החורג max_wal_size. עם זאת, PostgreSQL אסור למחוק או למחזר ישנים pg_wal קבצים בשלושה תנאים:
1. חריץ שכפול פיזי/לוגי יתום או בפיגור: שרת העתק (standby), מחבר Debezium/Kafka, או pg_receivewal הלקוח התנתק לפני ימים, אבל חריץ השכפול שלו (pg_replication_slots) עדיין active = false בראשי, מורה ל-PostgreSQL לשמור כל קטע WAL בודד שנוצר מאז הניתוק.
2. כישלון archive_command: archive_mode = on מופעל ב postgresql.conf, ותסריט הגיבוי (pgBackRest, WAL-G, Barman, או aws s3 cp) מחזירה קוד יציאה שאינו מאפס (לדוגמה, מפתח S3 שפג תוקפו או מארח גיבוי בלתי ניתן להשגה). PostgreSQL שומר כל קטע WAL שלא הועבר בארכיון pg_wal/ עד archive_command מחזיר 0.
3. מבוי סתום מלא בדיסק: pg_wal גדל עד 0 bytes נשאר על /var/lib/postgresql, ועכשיו PostgreSQL אפילו לא יכול להתחיל להוריד את חריץ השכפול או להשלים נקודת ביקורת מכיוון שחזור ההפעלה עצמו זקוק למספר מגה-בייט של שטח דיסק פנוי כדי לכתוב קבצי מצב זמניים.
שלב אחר שלב חילוץ PostgreSQL אפס שטח (אפס אובדן נתונים)¶
- צור 1 גיגה-בייט עד 5 גיגה-בייט (1.07 מיליארד עד 5.36 מיליארד בתים) של שטח זמני בחוץ
pg_wal/: - שימוש ראשון
sudo tune2fs -m 0 /dev/<partition>וקיצוץ יומני טקסט של מערכת/PostgreSQL (sudo truncate -s 0 /var/lib/postgresql/*/main/log/*.logאו/var/log/postgresql/*.log). - ** מה אם למסד הנתונים יש מחיצה ייעודית משלו עם אפס יומני טקסט ו-XFS (כך
tune2fsאינו זמין)?** העבר 10 ל-20 מה-העתיקים ביותר.readyאו קבצים לא פעילים מתוך ספרייה שאינה WAL, או העבר אתpg_walספרייה זמנית למחיצה אחרת עם מקום פנוי באמצעות קישור סמלי:# ONLY while PostgreSQL is completely stopped (verify with: ps aux | grep postgres) sudo mkdir -p /mnt/extra_space/pg_wal_rescue sudo chown -R postgres:postgres /mnt/extra_space/pg_wal_rescue sudo mv /var/lib/postgresql/16/main/pg_wal/* /mnt/extra_space/pg_wal_rescue/ sudo rmdir /var/lib/postgresql/16/main/pg_wal sudo ln -s /mnt/extra_space/pg_wal_rescue /var/lib/postgresql/16/main/pg_wal sudo chown -h postgres:postgres /var/lib/postgresql/16/main/pg_wal - אם
archive_commandנכשל וחוסם את מיחזור WAL, עוקף אותו באופן זמני פנימהpostgresql.conf: אם יעד ה-S3/גיבוי שלך מושבת וpg_wal/archive_status/מכיל אלפי.readyקבצים, ערוךpostgresql.conf(archive_command = '/bin/true') רק כאמצעי חירום אחרון כדי למנוע מהדיסק למות, בידיעה שעליך לקחת טריpg_basebackupמיד לאחר ההתאוששות כי בשרשרת הארכיון של WAL יהיה פער. - הפעל את PostgreSQL ובדוק מיד את חריצי השכפול:
התחל את PostgreSQL (
sudo systemctl start postgresql) והתחבר באמצעותsudo -u postgres psql: - שחרר כל חריץ שכפול מת/לא פעיל שאוגר ג'יגה-בייט של WAL:
אם אתה רואה משבצת לא פעילה (
active = f) המחזיק 80 גיגה-בייט שלretained_wal: - כפה מיד
CHECKPOINTלמחזר את הנפוחpg_walקטעים: הרגעCHECKPOINT;מסתיים לאחר שחרור המשבצת המתה, PostgreSQL יבטל אוטומטית את הקישור או ימחזר ג'יגה-בייט של קבצי פלח ישנים של 16 מגה-בייט בpg_wal/, מחזיר את השימוש בדיסק שלך לרגיל. - מנע מוות של דיסק חריץ שכפול עתידי: הגדר
max_slot_wal_keep_sizeבpostgresql.conf(זמין ב-PostgreSQL 13+) למכסה בטוח (כגוןmax_slot_wal_keep_size = 20GB) כך ש-PostgreSQL מבטל את התוקף של משבצת עותק מת במקום לקרוס את מסד הנתונים הראשי ב-0 בתים פנויים.
שלב 4: שחזור MySQL / MariaDB (InnoDB) ב-0 בתים בחינם¶
כאשר MySQL או MariaDB פוגעים 100% שימוש בדיסק (/var/lib/mysql), InnoDB תוקע את כל הכתיבה או קריסות איתם [ERROR] [MY-012640] [InnoDB] Error number 28 means 'No space left on device'.
זיהוי מה מילא /var/lib/mysql¶
רוץ sudo du -sh /var/lib/mysql/* | sort -hr | head -n 15 כדי לראות מי מארבעת האשמים האלה צרך את הדיסק:
1. יומנים בינאריים ללא גבולות (binlog.000001, mysql-bin.000042): כברירת מחדל ב-MySQL 8.0+, רישום בינארי מופעל עם שמירה של 30 יום (binlog_expire_logs_seconds = 2592000), שיכול ליצור בקלות מאות גיגה-בייט של אירועי שורה במהלך ייבוא בכמות גדולה.
2. שאילתה בורחת כותבת טבלאות זמניות ענקיות (#sql* או ibtmp1): מסיבית GROUP BY או ORDER BY השאילתה מולאה ibtmp1 או /tmp/#sql_* עד שהדיסק פגע ב-0 בתים.
3. מונוליטי ibdata1 נפח שולחן המערכת: אם innodb_file_per_table הושבתה או שעסקאות ארוכות טווח מנעו את רשימת ההיסטוריה של InnoDB (בטל יומנים בפנים ibdata1 או undo_001) מטיהור.
4. יומן שאילתות איטי של MySQL או יומן שגיאות (/var/log/mysql/mysql-slow.log).
שלב אחר שלב חילוץ MySQL / MariaDB אפס שטח¶
- לעולם אל תמחק
ibdata1,ib_logfile0,ib_logfile1,#innodb_redo/*, אוundo_001עםrm: מחיקת כל אחד מהקבצים האלה הופכת כל.ibdקובץ הטבלה במסד הנתונים שלך אינו קריא. - שטח הפעלה ראשוני חינם (500 מגה-בייט עד 2 גיגה-בייט):
- קטוע
/var/log/mysql/error.logוmysql-slow.logדרךsudo truncate -s 0 /var/log/mysql/*.log. - פועל
ext4, לרוץsudo tune2fs -m 1 /dev/<partition>. - אם
mysqldמופסק כרגע ו/var/lib/mysql/ibtmp1(מרחב השולחן הזמני הלא דחוס) הוא עצום,ibtmp1נוצר מחדש אוטומטית בעת האתחול, או שאתה יכול להעביר את שניים או שלושה היומנים הבינאריים העתיקים ביותר (binlog.000001,binlog.000002- לעולם אל הבינלוג הפעיל בעל המספר הגבוה ביותר) ל/dev/shmבאופן זמני כךmysqldיכול לאתחל. - התחל MySQL וטהר יומנים בינאריים בבטחה באמצעות SQL (
PURGE BINARY LOGS): מדוע עליך להשתמש ב-SQL במקוםrm /var/lib/mysql/binlog.*? מכיוון ש-MySQL עוקב אחר כל שם קובץ יומן בינאריbinlog.index. אם אתה מוחק יומנים בינאריים עםrmללא עדכוןbinlog.index, MySQL יסרב להתחיל או שהשכפול יישבר. פעם אחתmysqldמתחיל, התחבר (sudo mysql) והריצו: (או נקה הכל עד לקובץ היומן הפעיל הנוכחי שמוצג בתחתיתSHOW BINARY LOGS;באמצעותPURGE BINARY LOGS TO 'binlog.000085';) - הגדר גודל יומן בינארי קבוע ומכסה שמירה
/etc/mysql/mysql.conf.d/mysqld.cnf:מכסה[mysqld] binlog_expire_logs_seconds = 259200 # Keep only 3 days (259,200 seconds) max_binlog_size = 256M innodb_temp_data_file_path = ibtmp1:12M:autoextend:max:5Gibtmp1בmax:5Gמבטיח כי נוכל unindexedJOINאוORDER BYהשאילתה נכשלת עם אtable is fullשגיאה במקום להרחיבibtmp1עד שכל שרת הלינוקס ימות ב-0 בתים פנויים.
שלב 5: שחזור מסד נתונים SQLite3 פגום (database or disk is full / SQLITE_FULL / malformed)¶
יישומים משובצים, מכולות Docker (Nextcloud, Vaultwarden, Home Assistant, Plex, Grafana, Gitea), ושירותי נייד/שולחן עבודה מסתמכים על SQLite3. כאשר דיסק מגיע ל-0 בתים פנויים בזמן ש-SQLite נמצא באמצע החזרת יומן או יומן Write-Ahead (-wal) מחסום, תיתקלו באחד משני מצבי חירום:
1. מאסיבי .db-wal נפיחות קבצים (ה .db-wal הקובץ גדל ל-10 גיגה-בייט בזמן שה- .db הקובץ הוא 200 מגה-בייט בלבד, מכיוון שקוראים ארוכי טווח מנעו מחסום WAL פסיבי, וכעת הדיסק מלא ב-100 אחוז).
2. RuntimeError: database disk image is malformed (SQLITE_CORRUPT) נגרמת על ידי חומרה שבורה fsync(), מיכל נהרג באמצע ההחזרה ב-0 בתים פנויים, או מישהו שמוחק את -wal או -journal תיק ביד.
Warning
לעולם אל תזיז, תשנה שם או תעתיק א .db קובץ בפני עצמו תוך יציאה שלו .db-wal (יומן כתיבה קדימה) או .db-journal (Rollback Journal) קובץ מאחורי: אם app.db-wal או app.db-journal קיים לצד app.db, קובץ נלווה זה מכיל עסקאות מחויבות ודפי B-tree מקוריים הנדרשים לביצוע app.db עקבי מבחינה מבנית. העתק תמיד את כל שלושת הקבצים (app.db, app.db-wal, app.db-shm) ביחד לפני הפעלת פקודה כלשהי.
שלב 1: כיווץ נפוח .db-wal קובץ ושאיבת אבק של SQLite כאשר שטח הדיסק קרוב לאפס¶
- עצור את מיכל היישומים או השירות שמחזיק את מסד הנתונים של SQLite פתוח (
sudo systemctl stop appאוdocker stop container_name). - העתק
app.db,app.db-wal, וapp.db-shmלמחיצה או לכונן חיצוני עם הרבה מקום פנוי (או פנוי פי 2 בגודל שלapp.dbבדיסק המקומי תחילה). - פתח את מסד הנתונים עם ה
sqlite3CLI וכוח מחסום WAL קטוע, אשר מקפל את כל הפריימים המחויבים ממנוapp.db-walלתוךapp.dbומתכווץapp.db-walעד 0 בתים: - אמת את תקינות המבנה של עץ B והרשימה החופשית:
אם זה מודפס
ok, מסד הנתונים שלך בריא ב-100 אחוז. - איך
VACUUMמסד נתונים ענק של SQLite כאשר בדיסק המקומי אין מספיק מקום פנוי: סטנדרטיVACUUM;דורש עד פי שניים מגודל מסד הנתונים בשטח דיסק פנוי באותה מחיצה ו/var/tmp. במקום זאת, השתמשVACUUM INTO(הוצג ב-SQLite 3.27.0) כדי לכתוב עותק שדחוס ומאוחח לאחרונה ישירות לדיסק מותקן נפרד או לשיתוף רשת:
שלב 2: הצלת עץ B פגום (database disk image is malformed) עם .recover¶
אם PRAGMA integrity_check; דוחות row 412 missing from index, btreeInitPage() returns error code 11, או database disk image is malformed:
- קודם נסה לבנות מחדש אינדקסים משניים שבורים (
REINDEX): לעתים קרובות נתוני הטבלה בפועל (table B-trees) הוא 100 אחוז שלם ורק עץ אינדקס משני נפגם כשהדיסק התמלא. הרץ:אםsqlite3 /mnt/external_usb/copy_of_app.db "REINDEX;" sqlite3 /mnt/external_usb/copy_of_app.db "PRAGMA integrity_check;"PRAGMA integrity_check;כעת חוזרok, שחזרת 100 אחוז ממסד הנתונים שלך עם אפס שורות שאבדו. - אם
REINDEXנכשל, הפעל את סורק B-tree forensic (.recover): בניגוד למבוגרים יותר.dumpפקודה (המפסיקה לייצא טבלה ברגע שהיא פוגעת במצביע B-tree פגום),.recover(מובנה בsqlite3גרסה 3.29.0+) עוקפת לחלוטין את מצביעי עץ ה-B הפנימיים הפגומים, סורקת כל דף גולמי של 4 קילובייט של הקובץ ברצף מבייט 0 ל-EOF, משחזרת כל שורה קריא, וממקמת כל רשומה מיותמת בקובץlost_and_foundטבלה: - אמת את מסד הנתונים החדש ששוחזר:
בדוק אם א
lost_and_foundנוצרה טבלה (sqlite3 /mnt/external_usb/repaired_app.db ".tables") כדי לבדוק כל שורות יתומות ששוחזרו מדפי עלים לא מקושרים. עבור מסדי נתונים מוצפנים של SQLCipher (כגון גיבויים של Signal או WhatsApp), עיין במדריך הייעודי שלנו בנושא שחיתות גיבוי בצ'אט SQLite, Signal ו-WhatsApp מוצפן וחילוץ מפתח מקומי.
שלב 6: חירום "קובץ נטל טריפ-wire" ורשימת בדיקה למניעת ניטור¶
ברגע שהשרת ומסד הנתונים שלך חוזרים לרשת, יישם את ארבעת אמצעי ההגנה האלה באופן מיידי, כך שלעולם לא תיתפס שוב ב-0 בתים פנויים:
- צור 1 גיגה-בייט (
1,073,741,824byte) קובץ נטל חירום בכל מחיצת מסד נתונים: הפעלsudo fallocate -l 1G /var/lib/EMERGENCY_DELETE_ME.ballast. אם השרת יפגע אי פעם100%הדיסק מלא, פועלsudo rm /var/lib/EMERGENCY_DELETE_ME.ballastמשחרר 1 גיגה-בייט של בלוקים רציפים תוך אלפית שנייה. - כובע
systemd-journaldיומני מיכל של Docker לצמיתות: הגדרSystemMaxUse=200Mב/etc/systemd/journald.confולהגדיר/etc/docker/daemon.jsonעם"log-opts": {"max-size": "20m", "max-file": "3"}. - לבודד
/var/log,/tmp, ו/var/lib/postgresqlעל נפחי LVM נפרדים: שמירה/var/logו/tmpנפרד מנפחי מסד נתונים מבטיח שיומן אינטרנט בורח לעולם לא יקרוס את מסד הנתונים או נועל כניסות SSH. - התראה על שניהם
df -h(> 80%) וdf -i(> 80%) פלוסpg_replication_slotsפיגור: הגדר ניטור (node_filesystem_avail_bytesוnode_filesystem_files_free) להתריע לפני שהניצול חוצה 85 אחוז.
מספרי חירום אזוריים ופרוטוקולי סוכנות¶
בעוד שדיסק שרת מלא הוא בדרך כלל מצב חירום תפעולי IT פנימי, הפסקה משפיעה על רישום בריאות אלקטרוני (EHR) מסדי נתונים, שיגור חירום (CAD), טלמטריית מים/חשמל עירונית, או זמינות נתונים אישיים סטטוטוריים עשויים לדרוש הסלמה רשמית לשעת חירום:
- ארצות הברית וקנדה: חייגו
911אם קריסת שרת משביתה ניטור קליני או שיגור, ומפעילה נהלי זמן השבתה. דווח על מיצוי משאבי תשתית קריטית או התקפות של תוכנות כופר ל-CISA (1-844-Say-CISA/cisa.gov/report) או המרכז הקנדי לאבטחת סייבר (1-833-CYBER-88). - בריטניה: חייגו
999עבור איומי חיים או מערכות NHS קריטיות. לפי תקנות GDPR ו-NIS של בריטניה, העריכו אם אובדן זמינות קבוע של מסד נתונים מחייב הודעה ל-ICO (0303 123 1113) תוך 72 שעות. - האיחוד האירופי: חייגו
112בכל המדינות החברות באיחוד האירופי. ישויות חיוניות לפי הדירקטיבה NIS2 חייבות להודיע ל-CSIRT הלאומי שלהם בתוך 24 שעות על הפסקה משמעותית, ואובדן נתונים אישיים לצמיתות ללא שחזור גיבוי מפעיל דיווח על סעיף 33 של GDPR תוך 72 שעות. - אוסטרליה וניו זילנד: חייגו
000באוסטרליה או111בניו זילנד; צור קשר עם ACSC (1300 CYBER1) לאירועי תשתית. - הודו ואסיה-פסיפיק: חייגו
112לתגובת חירום; דווח על הפסקות סייבר ל-CERT-In (incident@cert-in.org.in) בתוך חלון החובה של 6 שעות.
שאלות נפוצות¶
למה עשה df -h להישאר ב-100% (0 Avail) גם לאחר שמחקתי קובץ יומן 50 GB עם rm?¶
במערכות קבצים לינוקס, rm רק שיחות unlink(), הסרת שם הקובץ מהספרייה בזמן שהקרנל שומר את בלוקי הדיסק מוקצים עד שכל תהליך שמחזיק את הקובץ הזה פתוח סוגר את מתאר הקובץ שלו (i_count == 0). רוץ sudo lsof +L1 כדי למצוא את מזהה התהליך (PID) ומתאר קובץ (FD) של ה (נמחק) קובץ ואז הפעל sudo sh -c ': > /proc/PID/fd/FD' לאפס את הבלוקים במקום באופן מיידי מבלי להפעיל מחדש את השירות.
מה אם אני לא יכול אפילו SSH להיכנס לשרת בגלל /tmp או /var/run הוא 100% מלא ו sshd מסרב להקצות מושב?¶
תחילה נסה לבצע פקודה ישירה שאינה PTY על SSH מבלי להקצות פסאודו-טרמינל אינטראקטיבי: ssh -T root@server "sh -c ': > /var/log/syslog'". אם שורש הכניסה מושבתת, השתמש בקונסולה הטורית מחוץ לפס של ספק הענן שלך (AWS EC2 Serial Console, DigitalOcean Console, Linode Lish או Proxmox/VMware VNC) כדי להתחבר ישירות ב- ttyS0 או אתחול למצב שחזור של משתמש יחיד.
מישהו כבר מחק קבצים בתוך PostgreSQL pg_wal ספרייה לפני קריאת המדריך הזה, ועכשיו PostgreSQL מסרב להתחיל עם PANIC: could not locate a valid checkpoint record. האם כל הנתונים אבדו?¶
לא, רוב שורות הטבלה עדיין בפנים $PGDATA/base/, למרות שעסקאות בטיסה בתוך קבצי ה-WAL שנמחקו אבדו וייתכן שחלק מהדפים ייקרעו. ראשית צור עותק שלם של כולו $PGDATA ספרייה (cp -a /var/lib/postgresql/16/main /mnt/backup/pgdata_raw). ואז לרוץ sudo -u postgres /usr/lib/postgresql/16/bin/pg_resetwal -f /var/lib/postgresql/16/main, הפעל את PostgreSQL במצב של משתמש יחיד, והפעל מיד pg_dumpall לתוך אתחול טרי (initdb) אשכול; לעולם אל תמשיך להפעיל תעבורת ייצור על אשכול לאחר מכן pg_resetwal.
כיצד אוכל למחוק מיליוני קבצים קטנים מתי rm -rf נתקע או נכשל על אינוד מותש (df -i 100%) שרת?¶
כאשר ספרייה מכילה מיליוני קבצי הפעלה או מטמון זעירים, אינדקס הספרייה שלה (htree) גדל עצום, גורם ls ו rm -rf כדי לעכב מיון שמות קבצים ב-RAM. במקום זאת, רוץ sudo find /path/to/million_files -mindepth 1 -מחיקה, או צור ספריית RAM ריקה (mkdir /dev/shm/empty) ולרוץ sudo rsync -a --מחק /dev/shm/empty/ /path/to/million_files/ כדי לבטל קישור אינודים במהירות.
מדוע Docker מילא את כל הדיסק של השרת שלי כאשר הקונטיינרים שלי עצמם זעירים, ואיך אני מנקה /var/lib/docker בבטחה?¶
Docker צובר שטח דיסק ביומני JSON stdout לא מסובבים (/var/lib/docer/containers/*/*-json.log), משתלשל שכבת על2 שכבות תמונה, ומטמון buildkit. לעולם לא ידנית rm -rf תיקיות בפנים /var/lib/docer/overlay2/. ראשית חתוך את יומני ה-JSON (sudo truncate -s 0 /var/lib/docer/containers/*/*-json.log) אז לדמון יש מקום לנשימה, ואז רוץ sudo docker system prune -a -f (השמטה --כרכים כך שנפחי מסד הנתונים נשארים ללא נגיעה).
האם אני יכול להרחיב נפח EBS בענן / נפח דיסק קבוע בזמן שהשרת נמצא ב-100% ניצול דיסק?¶
כן, הרחבת נפח מקוון עובדת ללא אתחול מחדש, עם תפס אחד: סקריפט העזר growpart /dev/nvme0n1 1 מנסה ליצור קובץ זמני ב /tmp באמצעות mktemp ונכשל ב-0 בתים בחינם. עוקף את הכשל הזה על ידי ריצה sudo TMPDIR=/dev/shm growpart /dev/nvme0n1 1 (באמצעות זיכרון RAM מגובה /dev/shm הר) ואחריו sudo resize2fs /dev/nvme0n1p1 (ext4) או sudo xfs_growfs / (XFS).
מדריכים קשורים¶
- 'rm -rf' או 'Shift+Delete' בטעות ב-Linux, macOS או Windows: הפעלה מחדש מיידית לקריאה בלבד
- שחיתות גיבוי בצ'אט SQLite, Signal ו-WhatsApp מוצפן וחילוץ מפתח מקומי
- Word, Excel, PDF ומסד נתונים פגומים ושחזור מסמכים שלא נשמרו
- מצב קריאה פתאומי של SSD ו-NVMe, 0% חסימות חילוף ו-TRIM השבתת הצלה
- משבר אירוח אתרים, הגירה ושחזור גיבוי
- מספרי חירום לפי מדינה
מקורות והדרכה רשמית¶
- קבוצת הפיתוח העולמית של PostgreSQL: תיעוד רשמי של PostgreSQL 16 - פרק 30: מהימנות ויומן הכתיבה קדימה (תצורת WAL, חריצי שכפול ושחזור כשלי דיסק מלא).
- קונסורציום SQLite (
sqlite.org): כיצד להשחית קובץ מסד נתונים של SQLite (נעילת קבצים, קבצי יומן/WAL לא מקושרים, וה.recoverהרחבת CLI). - Oracle Corporation / MySQL Documentation & MariaDB Foundation: שחזור קריסה של InnoDB, הליכי טיהור יומן בינארי (
PURGE BINARY LOGS), ומרחב שולחנות זמני (ibtmp1) ניהול. - ארגון ליבת לינוקס (
kernel.org): ניהול מערכת קבצים Ext4 (tune2fsבלוקים שמורים, טבלאות אינודה ו/proc/<pid>/fd/חיתוך מתאר קובץ). - המכון הלאומי לתקנים וטכנולוגיה (
NIST) (ארצות הברית): פרסום מיוחד 800-123: מדריך לאבטחת שרתים וניהול זמינות כללית.