Skip to content

דיסק שרת מלא ב-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 בבריטניה) או עיין במדריך הגלובלי שלנו של מספרי חירום.

תעשה את זה עכשיו

  1. לא למחוק pg_wal/, pg_xlog/, pg_multixact/, ib_logfile*, undo_*, או -wal / -shm קבצים כדי לפנות מקום: מחיקת יומן Write-Ahead או קובצי רישום/ביטול של InnoDB בזמן שמסד נתונים קרס או לא מסומן, הורסת את הרשומה היחידה של דפים לא מחויבים ודפים בטיסה. מסד נתונים עם דיסק מלא ניתן לשחזור ב-100 אחוז ברגע שמתפנה מקום; מסד נתונים שקובצי ה-WAL שלו נמחקו ידנית rm יסבול משחיתות בלתי הפיכה של עץ B וערימה.
  2. ** אבחן תוך 5 שניות אם נגמרו לך בלוקים של דיסקים (df -h), מחוץ לאינודים של מערכת הקבצים (df -i), או החזקת קבצים פתוחים לא מקושרים (lsof +L1)**:
  3. רוץ df -h כדי לבדוק קיבולת בלוק ו df -i לבדיקת קיבולת האינודה. שרת עם 50 גיגה-בייט (53.6 מיליארד בתים) של שטח דיסק פנוי עדיין יזרוק No space left on device (ENOSPC) אם df -i מופעים IUse% = 100% (בדרך כלל נגרמת ממיליוני קבצי הפעלה זעירים, מטמון או קבצי סליל דואר).
  4. אם df -h מופעים 100% בשימוש (0 Avail) גם אחרי שרצתם rm על קבצי יומן ענקיים, הפעל sudo lsof +L1. כל קובץ שנמחק עם rm תוך כדי nginx, rsyslog, docker, postgres, או mysqld עדיין מחזיק מתאר קובץ פתוח ממשיך לצרוך 100 אחוז מחסימות הדיסק שלו עד שהתהליך יתחיל מחדש או שתקטוע את המתאר ישירות.
  5. פנה ג'יגה-בייט של שטח בשנייה אחת ללא הפעלה מחדש של דמונים על-ידי חיתוך קבצים פתוחים במקום (: > /path/to/logfile או : > /proc/<pid>/fd/<n>):
  6. במקום rm /var/log/syslog (מה שמשאיר בלוקים נעולים על ידי היומן הפועל), אפס את הקובץ במקום באמצעות הפניית ה-null של ה- shell: sudo sh -c ': > /var/log/syslog' או sudo truncate -s 0 /var/log/syslog.
  7. אם כבר רצתם rm על קובץ יומן עצום ו df -h לא ירד, מצא את מזהה התהליך שלו (PID) ומתאר קובץ (FD) ב sudo lsof +L1 ולחתוך אותו ישר דרך ממשק הקרנל procfs: sudo sh -c ': > /proc/<PID>/fd/<FD>'. החלל יחזור ל df -h באופן מיידי.
  8. פתח את הנעילה של חדר נשימה חירום מיידי 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 /).
  9. ** ואקום 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.
  10. לאחר ששטח של לפחות 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 משותף:

export TMPDIR=/dev/shm
- 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 במקום זאת:
sudo find /var/lib/php/sessions -type f -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 אוטומטי כבר מחקת קבצים גדולים אך שטח דיסק לא הוחזר, בדוק את טבלת הקבצים הפתוחים הלא מקושרים של הקרנל:

sudo lsof +L1
תסתכל על 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) ישירות בזיכרון הליבה:
sudo sh -c ': > /proc/612/fd/7'
רוץ df -h מיד: כל 18.2 גיגה-בייט משוחררים במקום מבלי להפעיל מחדש אף שירות.

שלב 2: תביעה מחדש ext4 בלוקים שמורים באינטרנט עם tune2fs

על כל ext4 או ext3 מערכת הקבצים, בדוק את ספירת החסימות השמורות הנוכחית:

df -h /
sudo tune2fs -l /dev/nvme0n1p1 | grep -i "reserved block"
בגלל PostgreSQL (postgres), MySQL (mysql), Redis (redis), ואפליקציות אינטרנט של SQLite (www-data, node) פועלים כמשתמשי שורש ללא הרשאות, ליבת לינוקס חוסמת אותם מלהשתמש ב-5 האחוזים האחרונים של הדיסק. הורדת יחס החסימה השמור מ 5% ל 1% (או 0% בזמן חירום פעיל) נכנס לתוקף באופן מיידי על מערכת קבצים מותקנת חיה:
sudo tune2fs -m 1 /dev/nvme0n1p1
בנפח מסד נתונים של 1 טרה-בייט (1,000 גיגה-בייט), פקודה יחידה זו מעבירה מיד 40 גיגה-בייט (42.9 מיליארד בתים) של שטח בר כתיבה למנוע מסד הנתונים שלך כדי שיוכל לסיים את נקודת ה-WAL שלו. לאחר שהמשבר ייפתר והנתונים הישנים יטוקו, החזר את הרזרבה 2% או 5% (sudo tune2fs -m 2 /dev/nvme0n1p1).

שלב 3: חתוך יומני טקסט פעילים במקום ושואב journald

מצא את הקבצים הגדולים ביותר במערכת הקבצים הבסיסית (הישאר באותה מערכת קבצים עם -xdev כך שלא תבזבז זמן בסריקה /proc או תושבות חיצוניות):

sudo find / -xdev -type f -size +100M -exec ls -lh {} + 2>/dev/null | sort -k 5 -hr | head -n 25
- עבור קובצי יומן טקסט רגיל גדולים (/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/):
sudo journalctl --vacuum-size=50M


שלב 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. צור 1 גיגה-בייט עד 5 גיגה-בייט (1.07 מיליארד עד 5.36 מיליארד בתים) של שטח זמני בחוץ pg_wal/:
  2. שימוש ראשון sudo tune2fs -m 0 /dev/<partition> וקיצוץ יומני טקסט של מערכת/PostgreSQL (sudo truncate -s 0 /var/lib/postgresql/*/main/log/*.log או /var/log/postgresql/*.log).
  3. ** מה אם למסד הנתונים יש מחיצה ייעודית משלו עם אפס יומני טקסט ו-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
    
  4. אם archive_command נכשל וחוסם את מיחזור WAL, עוקף אותו באופן זמני פנימה postgresql.conf: אם יעד ה-S3/גיבוי שלך מושבת ו pg_wal/archive_status/ מכיל אלפי .ready קבצים, ערוך postgresql.conf (archive_command = '/bin/true') רק כאמצעי חירום אחרון כדי למנוע מהדיסק למות, בידיעה שעליך לקחת טרי pg_basebackup מיד לאחר ההתאוששות כי בשרשרת הארכיון של WAL יהיה פער.
  5. הפעל את PostgreSQL ובדוק מיד את חריצי השכפול: התחל את PostgreSQL (sudo systemctl start postgresql) והתחבר באמצעות sudo -u postgres psql:
    SELECT slot_name, plugin, slot_type, active,
           pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained_wal
    FROM pg_replication_slots;
    
  6. שחרר כל חריץ שכפול מת/לא פעיל שאוגר ג'יגה-בייט של WAL: אם אתה רואה משבצת לא פעילה (active = f) המחזיק 80 גיגה-בייט של retained_wal:
    SELECT pg_drop_replication_slot('name_of_dead_slot');
    
  7. כפה מיד CHECKPOINT למחזר את הנפוח pg_wal קטעים:
    CHECKPOINT;
    
    הרגע CHECKPOINT; מסתיים לאחר שחרור המשבצת המתה, PostgreSQL יבטל אוטומטית את הקישור או ימחזר ג'יגה-בייט של קבצי פלח ישנים של 16 מגה-בייט ב pg_wal/, מחזיר את השימוש בדיסק שלך לרגיל.
  8. מנע מוות של דיסק חריץ שכפול עתידי: הגדר 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 אפס שטח

  1. לעולם אל תמחק ibdata1, ib_logfile0, ib_logfile1, #innodb_redo/*, או undo_001 עם rm: מחיקת כל אחד מהקבצים האלה הופכת כל .ibd קובץ הטבלה במסד הנתונים שלך אינו קריא.
  2. שטח הפעלה ראשוני חינם (500 מגה-בייט עד 2 גיגה-בייט):
  3. קטוע /var/log/mysql/error.log ו mysql-slow.log דרך sudo truncate -s 0 /var/log/mysql/*.log.
  4. פועל ext4, לרוץ sudo tune2fs -m 1 /dev/<partition>.
  5. אם mysqld מופסק כרגע ו /var/lib/mysql/ibtmp1 (מרחב השולחן הזמני הלא דחוס) הוא עצום, ibtmp1 נוצר מחדש אוטומטית בעת האתחול, או שאתה יכול להעביר את שניים או שלושה היומנים הבינאריים העתיקים ביותר (binlog.000001, binlog.000002 - לעולם אל הבינלוג הפעיל בעל המספר הגבוה ביותר) ל /dev/shm באופן זמני כך mysqld יכול לאתחל.
  6. התחל 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 BEFORE NOW() - INTERVAL 1 DAY;
    
    (או נקה הכל עד לקובץ היומן הפעיל הנוכחי שמוצג בתחתית SHOW BINARY LOGS; באמצעות PURGE BINARY LOGS TO 'binlog.000085';)
  7. הגדר גודל יומן בינארי קבוע ומכסה שמירה /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:5G
    
    מכסה ibtmp1 ב max:5G מבטיח כי נוכל unindexed JOIN או 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 כאשר שטח הדיסק קרוב לאפס

  1. עצור את מיכל היישומים או השירות שמחזיק את מסד הנתונים של SQLite פתוח (sudo systemctl stop app או docker stop container_name).
  2. העתק app.db, app.db-wal, ו app.db-shm למחיצה או לכונן חיצוני עם הרבה מקום פנוי (או פנוי פי 2 בגודל של app.db בדיסק המקומי תחילה).
  3. פתח את מסד הנתונים עם ה sqlite3 CLI וכוח מחסום WAL קטוע, אשר מקפל את כל הפריימים המחויבים ממנו app.db-wal לתוך app.db ומתכווץ app.db-wal עד 0 בתים:
    sqlite3 /path/to/app.db "PRAGMA wal_checkpoint(TRUNCATE);"
    
  4. אמת את תקינות המבנה של עץ B והרשימה החופשית:
    sqlite3 /path/to/app.db "PRAGMA integrity_check;"
    
    אם זה מודפס ok, מסד הנתונים שלך בריא ב-100 אחוז.
  5. איך VACUUM מסד נתונים ענק של SQLite כאשר בדיסק המקומי אין מספיק מקום פנוי: סטנדרטי VACUUM; דורש עד פי שניים מגודל מסד הנתונים בשטח דיסק פנוי באותה מחיצה ו /var/tmp. במקום זאת, השתמש VACUUM INTO (הוצג ב-SQLite 3.27.0) כדי לכתוב עותק שדחוס ומאוחח לאחרונה ישירות לדיסק מותקן נפרד או לשיתוף רשת:
    sqlite3 /path/to/app.db "VACUUM INTO '/mnt/external_usb/app_compacted.db';"
    

שלב 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:

  1. קודם נסה לבנות מחדש אינדקסים משניים שבורים (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 אחוז ממסד הנתונים שלך עם אפס שורות שאבדו.
  2. אם REINDEX נכשל, הפעל את סורק B-tree forensic (.recover): בניגוד למבוגרים יותר .dump פקודה (המפסיקה לייצא טבלה ברגע שהיא פוגעת במצביע B-tree פגום), .recover (מובנה ב sqlite3 גרסה 3.29.0+) עוקפת לחלוטין את מצביעי עץ ה-B הפנימיים הפגומים, סורקת כל דף גולמי של 4 קילובייט של הקובץ ברצף מבייט 0 ל-EOF, משחזרת כל שורה קריא, וממקמת כל רשומה מיותמת בקובץ lost_and_found טבלה:
    sqlite3 /mnt/external_usb/copy_of_app.db ".recover" | sqlite3 /mnt/external_usb/repaired_app.db
    
  3. אמת את מסד הנתונים החדש ששוחזר:
    sqlite3 /mnt/external_usb/repaired_app.db "PRAGMA integrity_check;"
    
    בדוק אם א lost_and_found נוצרה טבלה (sqlite3 /mnt/external_usb/repaired_app.db ".tables") כדי לבדוק כל שורות יתומות ששוחזרו מדפי עלים לא מקושרים. עבור מסדי נתונים מוצפנים של SQLCipher (כגון גיבויים של Signal או WhatsApp), עיין במדריך הייעודי שלנו בנושא שחיתות גיבוי בצ'אט SQLite, Signal ו-WhatsApp מוצפן וחילוץ מפתח מקומי.

שלב 6: חירום "קובץ נטל טריפ-wire" ורשימת בדיקה למניעת ניטור

ברגע שהשרת ומסד הנתונים שלך חוזרים לרשת, יישם את ארבעת אמצעי ההגנה האלה באופן מיידי, כך שלעולם לא תיתפס שוב ב-0 בתים פנויים:

  • צור 1 גיגה-בייט (1,073,741,824 byte) קובץ נטל חירום בכל מחיצת מסד נתונים: הפעל 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).


מדריכים קשורים


מקורות והדרכה רשמית

  • קבוצת הפיתוח העולמית של 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: מדריך לאבטחת שרתים וניהול זמינות כללית.