رفتن به محتوا
LoopX

منابع سیستم: دیسک، حافظه، CPU

توی این درس یاد می‌گیری هر سرور سه منبع اصلی دارد: دیسک (جای دائمی)، حافظه (RAM و swap) و CPU (توان پردازش). با df -h فضای خالی هر دیسک را، با du -sh * حجم پوشه‌ها را، با free -h وضعیت حافظه را، با uptime بار سیستم (load average) را، و با lsblk و mount دیسک‌ها و محل وصل‌شدنشان را می‌بینی. و مهم‌تر: وقتی «سرور پر شده» می‌دانی چطور پیدا کنی چه چیزی منبع را خورده. تمرین: بزرگ‌ترین پوشه‌های سیستم را پیدا می‌کنی.

مسئله: سرور کند یا از کار افتاده، چرا؟

Section titled “مسئله: سرور کند یا از کار افتاده، چرا؟”

بیشتر «سرور خراب شد» ها یکی از سه علت دارند: دیسک پر شد، حافظه تمام شد یا CPU اشباع شد. قبل از هر عیب‌یابی پیچیده، باید بتوانی در یک دقیقه این سه را بخوانی.

تشبیه: انبار، میز کار و کارگرها

Section titled “تشبیه: انبار، میز کار و کارگرها”

دیسک مثل انبار است: بزرگ و دائمی، اما رفتن تا آن کند است. RAM میز کار است: کوچک‌تر و بسیار سریع، و با خاموش‌شدن همه‌چیزش پاک می‌شود. swap قفسه‌ای در انبار است که وقتی میز پر شد، چیزهای کم‌مصرف را موقتاً آنجا می‌گذاری (جا باز می‌شود ولی هر بار رفتن سراغش کند است). CPU کارگرهاست، و load average یعنی «به‌طور متوسط چند کار منتظر نوبت یک کارگرند».

حافظه‌ی یک سیستم لایه‌لایه است: هرچه پایین‌تر، بزرگ‌تر و دائمی‌تر ولی کندتر. وقتی RAM پر شود، هسته بخشی از آن را روی swap (که خودش بخشی از دیسک است) می‌نویسد.

df (disk free) برای هر فایل‌سیستم (هر دیسک یا پارتیشنِ وصل‌شده) می‌گوید چقدر جا دارد. -h یعنی خوانا (human-readable: G و M به‌جای بایت):

Terminal window
df -h
خروجی
Filesystem Size Used Avail Use% Mounted on
overlay 453G 22G 408G 6% /
tmpfs 64M 0 64M 0% /dev
shm 64M 0 64M 0% /dev/shm
overlay 392M 356K 392M 1% /usr/sbin/docker-init
/dev/vda1 453G 22G 408G 6% /etc/hosts
tmpfs 4.0K 0 4.0K 0% /proc/scsi

ستون‌ها: Filesystem (دستگاه)، Size (اندازه‌ی کل)، Used (استفاده‌شده)، Avail (قابل‌استفاده)، Use% (درصد پر بودن) و Mounted on (محل وصل‌شدن در درخت پوشه‌ها). چون این آزمایشگاه یک کانتینر است، فایل‌سیستم ریشه (/) از نوع overlay است و چند خط مخصوص کانتینر هم هست؛ روی سرور واقعی معمولاً یک /dev/sda1 یا /dev/vda1 روی / می‌بینی. دو گزینه‌ی مفید:

Terminal window
echo "--- نوع فایل‌سیستم (-T) فقط برای /:"
df -hT /
echo "--- inode ها (-i):"
df -i /
خروجی
--- نوع فایل‌سیستم (-T) فقط برای /:
Filesystem Type Size Used Avail Use% Mounted on
overlay overlay 453G 22G 408G 6% /
--- inode ها (-i):
Filesystem Inodes IUsed IFree IUse% Mounted on
overlay 30179328 344223 29835105 2% /

هر فایل یک inode (درس لینک‌ها) مصرف می‌کند. اگر تعداد inode ها تمام شود، حتی با فضای خالی زیاد هم نمی‌توانی فایل جدید بسازی (مثال ۷). پس هشدار Use% را هم برای فضا و هم برای inode نگاه کن.

مثال ۲: حجم پوشه‌ها، du -sh *

Section titled “مثال ۲: حجم پوشه‌ها، du -sh *”

df می‌گوید دیسک چقدر پر است؛ du (disk usage) می‌گوید هر پوشه چقدر برداشته. -s یعنی فقط جمع هر مورد (summary)، -h خوانا. یک درخت نمونه با حجم‌های مشخص می‌سازم (از head -c فقط برای ساختن فایل‌های بی‌محتوای ۵ مگابایتی استفاده می‌کنم):

Terminal window
mkdir -p demo/logs demo/cache demo/src demo/.hidden
head -c 5M /dev/zero > demo/logs/app.log
head -c 2M /dev/zero > demo/logs/old.log
head -c 1M /dev/zero > demo/cache/c.bin
echo 'print(1)' > demo/src/main.py
head -c 8M /dev/zero > demo/.hidden/big.bin
cd demo
echo "--- du -sh * (حجم هر مورد):"
du -sh *
echo "--- از بزرگ به کوچک (sort -rh):"
du -sh * | sort -rh
echo "--- فایل‌های یک پوشه، بزرگ‌ترین بالا (ls -S):"
ls -lhS logs
خروجی
--- du -sh * (حجم هر مورد):
1.1M cache
7.1M logs
8.0K src
--- از بزرگ به کوچک (sort -rh):
7.1M logs
1.1M cache
8.0K src
--- فایل‌های یک پوشه، بزرگ‌ترین بالا (ls -S):
total 7.0M
-rw-r--r-- 1 ali ali 5.0M Oct 3 21:20 app.log
-rw-r--r-- 1 ali ali 2.0M Oct 3 21:20 old.log

sort -rh مرتب‌سازی را برای اعداد خوانا (5.0M در برابر 1.1M) انجام می‌دهد (-h) و از بزرگ به کوچک (-r). یک نکته‌ی تله: du -sh * فقط چیزهایی را می‌بیند که * جایگزین می‌کند، و * فایل‌های مخفی (با نقطه) را نمی‌گیرد؛ پوشه‌ی .hidden هشت مگابایتی در خروجی نیامد! (اشتباهات رایج.)

مثال ۳: پیدا کردن اینکه چه چیزی دیسک را پر کرده

Section titled “مثال ۳: پیدا کردن اینکه چه چیزی دیسک را پر کرده”

روش استاندارد: از ریشه شروع کن، فقط یک سطح پایین برو (--max-depth=1)، بزرگ‌ترین را انتخاب کن و همان را دوباره باز کن. -x از رفتن به فایل‌سیستم‌های دیگر (مثل /proc) جلوگیری می‌کند و 2>/dev/null خطاهای «دسترسی نداری» را دور می‌ریزد:

Terminal window
echo "--- بزرگ‌ترین پوشه‌های ریشه:"
sudo du -xh --max-depth=1 / 2>/dev/null | sort -rh | head -6
echo "--- بزرگ‌ترین زیرپوشه‌های /usr:"
sudo du -xh --max-depth=1 /usr 2>/dev/null | sort -rh | head -5
خروجی
--- بزرگ‌ترین پوشه‌های ریشه:
732M /
642M /usr
71M /var
17M /home
2.8M /etc
236K /tmp
--- بزرگ‌ترین زیرپوشه‌های /usr:
642M /usr
268M /usr/lib
143M /usr/share
121M /usr/bin
96M /usr/libexec

(خط اول هر فهرست، جمع خود آن پوشه است.) هر بار بزرگ‌ترین را انتخاب می‌کنی و یک سطح پایین‌تر می‌روی تا به مقصر برسی (معمولاً /var/log، /var/lib/docker، یا /home). برای فایل‌های منفرد بزرگ هم find (درس پیدا کردن فایل‌ها):

Terminal window
echo "--- فایل‌های بزرگ‌تر از ۴ مگابایت در demo:"
find demo -type f -size +4M -exec ls -lh {} +
خروجی
--- فایل‌های بزرگ‌تر از ۴ مگابایت در demo:
-rw-r--r-- 1 ali ali 8.0M Oct 3 21:20 demo/.hidden/big.bin
-rw-r--r-- 1 ali ali 5.0M Oct 3 21:20 demo/logs/app.log
Terminal window
free -h
خروجی
total used free shared buff/cache available
Mem: 3.8Gi 2.2Gi 1.0Gi 5.6Mi 795Mi 1.6Gi
Swap: 1.0Gi 306Mi 717Mi

سطر Mem حافظه‌ی RAM و سطر Swap فضای swap است. معنی ستون‌ها:

ستون معنی
total کل RAM
used مصرف‌شده توسط برنامه‌ها
free کاملاً بی‌استفاده
shared حافظه‌ی اشتراکی (مثل tmpfs)
buff/cache کش دیسک: هسته از RAM آزاد برای تندتر کردن خواندن فایل‌ها استفاده می‌کند
available چقدر برای برنامه‌ی جدید در دسترس است (free + کش قابل‌آزادسازی)

مهم‌ترین ستون available است، نه free. لینوکس عمداً RAM بی‌استفاده را به کش می‌دهد (free کوچک و عادی است)؛ هر وقت برنامه‌ای حافظه بخواهد، کش را رها می‌کند. هشدار وقتی است که available کم شود و swap used رشد کند. (عددها اینجا مال ماشین مجازی داکر است که میزبان این کانتینر است.) ببین یک برنامه‌ی ۳۰۰ مگابایتی چه اثری دارد:

Terminal window
echo "--- قبل:"
free -m | head -2
python3 -c 'import time; b = bytearray(300 * 1024 * 1024); b[::4096] = b"x" * len(b[::4096]); time.sleep(6)' &
sleep 2
echo "--- وقتی پروسه‌ای ۳۰۰ مگابایت نگه داشته:"
free -m | head -2
wait
echo "--- swap:"
swapon --show
خروجی
--- قبل:
total used free shared buff/cache available
Mem: 3916 2279 1030 5 795 1637
--- وقتی پروسه‌ای ۳۰۰ مگابایت نگه داشته:
total used free shared buff/cache available
Mem: 3916 2587 721 5 795 1328
--- swap:
NAME TYPE SIZE USED PRIO
/var/lib/swap file 1024M 306.5M -1

ستون used حدود ۳۰۰ مگابایت بالا رفت و available همان‌قدر پایین آمد. swapon --show فایل یا پارتیشن swap را نشان می‌دهد: یک فایل (/var/lib/swap) که ۱ گیگابایت از دیسک را برای swap گذاشته. اگر RAM و swap هر دو تمام شوند، هسته «OOM killer» را اجرا می‌کند و برای نجات سیستم یک پروسه را می‌کشد (درس لاگ‌ها).

Terminal window
uptime
echo "--- همان عددها از /proc، و تعداد هسته‌های CPU:"
cat /proc/loadavg
nproc
خروجی
21:20:15 up 1 day, 2:19, 0 user, load average: 0.45, 0.54, 1.59
--- همان عددها از /proc، و تعداد هسته‌های CPU:
0.45 0.54 1.59 1/480 829
8

uptime سه چیز می‌گوید: ساعت، مدتی که سیستم بالاست، و load average سه عدد: میانگین بار در ۱، ۵ و ۱۵ دقیقه‌ی اخیر. load یعنی میانگین تعداد پروسه‌هایی که آماده‌ی اجرا (R) یا منتظر دیسک (D) هستند. قاعده‌ی سرانگشتی: load را با تعداد هسته‌ها (nproc) مقایسه کن: load برابر با تعداد هسته‌ها یعنی CPU کاملاً مشغول؛ بیشتر از آن یعنی صف. الگوی سه عدد هم مهم است: اگر عدد ۱ دقیقه از عدد ۱۵ دقیقه کوچک‌تر باشد، بار در حال کم‌شدن است، و اگر بزرگ‌تر باشد، در حال زیادشدن. (چون این کانتینر کل ماشین مجازی را می‌بیند، load شامل بقیه‌ی کانتینرهای آن هم هست.) برای دیدن اثر یک بار شدید، چهار پروسه‌ی شلوغ راه می‌اندازم و با vmstat (آماری که هر ثانیه تکرار می‌شود) نگاه می‌کنم:

Terminal window
for i in 1 2 3 4; do yes > /dev/null & done
sleep 1
vmstat 1 4
pkill yes
خروجی
procs -----------memory---------- ---swap-- -----io---- -system-- -------cpu-------
r b swpd free buff cache si so bi bo in cs us sy id wa st gu
5 0 313904 1046920 37816 776576 3 12 153 358 3385 3 29 1 70 0 0 0
4 0 313904 1046920 37816 776576 0 0 0 224 5408 2071 14 38 49 0 0 0
12 0 313904 1052672 37816 776576 0 0 0 0 5758 2667 14 38 48 0 0 0
4 0 313904 1052420 37816 776576 0 0 0 0 5604 2559 13 39 48 0 0 0

(سطر اول vmstat میانگین از زمان بوت است؛ از سطر دوم به بعد را بخوان.) ستون r (run queue) تعداد پروسه‌های آماده‌ی اجراست و برابر ۴ شد (همان ۴ پروسه‌ی yes)؛ ستون‌های us (user) و sy (system) سهم CPU شلوغ را نشان می‌دهند و id (idle) سهم بیکار: چون ماشین ۸ هسته دارد و ۴ تایشان مشغول‌اند، حدود نصف CPU بیکار ماند. ستون wa (wait) اگر بالا باشد یعنی CPU منتظر دیسک است، نشانه‌ی دیسک کند، نه CPU ضعیف.

⚡ بررسی سریع

load average برابر ۴ روی سیستمی با ۴ هسته CPU یعنی…

مثال ۶: دیسک‌ها و mount، lsblk و mount

Section titled “مثال ۶: دیسک‌ها و mount، lsblk و mount”

دیسک‌ها (block device) تا جایی که به درخت پوشه‌ها وصل (mount) نشوند قابل‌استفاده نیستند. برای دیدن کل چرخه، یک دیسک واقعی نمی‌خواهم: یک فایل ۱۰۰ مگابایتی را مثل دیسک فرمت می‌کنم (ext4) و با mount -o loop به /mnt/data وصل می‌کنم. این کار root می‌خواهد و در ماشین systemd‌دار آزمایشی (که در آن root هستم) انجام می‌دهم:

Terminal window
truncate -s 100M /tmp/lx-disk.img
mkfs.ext4 -q /tmp/lx-disk.img
mkdir -p /mnt/data
mount -o loop /tmp/lx-disk.img /mnt/data
echo "--- lsblk: دیسک‌های بلوکی (ram و nbd های خیالیِ ماشین آزمایشی را حذف کردم: -e 1,43)"
lsblk -e 1,43
echo "--- df با نوع فایل‌سیستم:"
df -hT /mnt/data
echo "--- findmnt: این مسیر از کجا وصل شده؟"
findmnt /mnt/data
echo "--- mount (فهرست همه؛ فقط خط مربوط به ما):"
mount | grep lx-disk
خروجی
--- lsblk: دیسک‌های بلوکی (ram و nbd های خیالیِ ماشین آزمایشی را حذف کردم: -e 1,43)
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
loop0 7:0 0 100M 0 loop /mnt/data
vda 254:0 0 460.4G 0 disk
└─vda1 254:1 0 460.4G 0 part /etc/resolv.conf
/etc/hosts
/etc/hostname
vdb 254:16 0 646.1M 1 disk
--- df با نوع فایل‌سیستم:
Filesystem Type Size Used Avail Use% Mounted on
/dev/loop0 ext4 90M 24K 83M 1% /mnt/data
--- findmnt: این مسیر از کجا وصل شده؟
TARGET SOURCE FSTYPE OPTIONS
/mnt/data /dev/loop0 ext4 rw,relatime
--- mount (فهرست همه؛ فقط خط مربوط به ما):
/tmp/lx-disk.img on /mnt/data type ext4 (rw,relatime)
  • lsblk (list block devices) دیسک‌ها و پارتیشن‌ها را در یک درخت می‌نشاند: vda دیسک اصلی ماشین مجازی من است و loop0 همان فایل ۱۰۰ مگابایتی با MOUNTPOINTS برابر /mnt/data. (زیر vda1 چند مسیر /etc/... هم هست چون این ماشین یک کانتینر است.)
  • mount بدون آرگومان همه‌ی mount ها را با شکل «دستگاه on مسیر type نوع (گزینه‌ها)» چاپ می‌کند؛ findmnt همین را مرتب‌تر.
  • Size فایل‌سیستم (۹۰ مگابایت) از فایل ۱۰۰ مگابایتی کمتر است: بخشی صرف ساختار خود ext4 (journal، جدول inode ها) می‌شود، و ext4 به‌طور پیش‌فرض ۵٪ را هم برای root رزرو می‌کند (Avail کمتر از Size - Used).

حالا از دیسک استفاده کن و بردارش (umount، بدون «n» اول، یک غلط املایی تاریخی است):

Terminal window
echo "داده‌ی من" > /mnt/data/note.txt
ls -l /mnt/data
df -h /mnt/data | tail -1
umount /mnt/data
echo "--- بعد از umount:"
ls -A /mnt/data | wc -l
findmnt /mnt/data || echo "(دیگر mount نیست)"
خروجی
total 20
drwx------ 2 root root 16384 Oct 3 21:19 lost+found
-rw-r--r-- 1 root root 19 Oct 3 21:19 note.txt
/dev/loop0 90M 28K 83M 1% /mnt/data
--- بعد از umount:
0
(دیگر mount نیست)

بعد از umount، /mnt/data دوباره یک پوشه‌ی خالی معمولی روی دیسک اصلی است؛ داده‌ها داخل فایل lx-disk.img ماندند و هر وقت دوباره mount کنی برمی‌گردند.

برای دیدن این خطا بدون پر کردن دیسک واقعی، یک فایل‌سیستم ۱۰ مگابایتی در RAM (tmpfs) درست می‌کنم و پرش می‌کنم:

Terminal window
mkdir -p /mnt/small
mount -t tmpfs -o size=10M tmpfs /mnt/small
dd if=/dev/zero of=/mnt/small/big bs=1M count=20
df -h /mnt/small
echo "--- مقصر را با du/ls پیدا و پاک می‌کنیم:"
ls -lh /mnt/small
rm /mnt/small/big
df -h /mnt/small | tail -1
خروجی
dd: error writing '/mnt/small/big': No space left on device
11+0 records in
10+0 records out
10485760 bytes (10 MB, 10 MiB) copied, 0.008131 s, 1.3 GB/s
Filesystem Size Used Avail Use% Mounted on
tmpfs 10M 10M 0 100% /mnt/small
--- مقصر را با du/ls پیدا و پاک می‌کنیم:
total 10M
-rw-r--r-- 1 root root 10M Oct 3 21:19 big
tmpfs 10M 0 10M 0% /mnt/small

dd در ۱۰ مگابایت اول موفق بود و بعد No space left on device؛ و df همان لحظه 100% را نشان داد. بعد از پاک‌کردن فایل، فضا برگشت. نوع دوم همین خطا، با فضای خالیِ فراوان است: وقتی inode ها تمام شوند (مثلاً میلیون‌ها فایل کوچک). با یک فایل‌سیستم که فقط ۵۰ inode دارد شبیه‌سازی می‌کنم:

Terminal window
umount /mnt/small
mount -t tmpfs -o size=10M,nr_inodes=50 tmpfs /mnt/small
for i in $(seq 1 80); do touch /mnt/small/f$i 2>/tmp/lx-err || { echo "فایل شماره‌ی $i: $(cat /tmp/lx-err)"; break; }; done
echo "--- فضا:"
df -h /mnt/small | tail -1
echo "--- inode:"
df -i /mnt/small
umount /mnt/small
خروجی
فایل شماره‌ی 50: touch: cannot touch '/mnt/small/f50': No space left on device
--- فضا:
tmpfs 10M 0 10M 0% /mnt/small
--- inode:
Filesystem Inodes IUsed IFree IUse% Mounted on
tmpfs 50 50 0 100% /mnt/small

df -h می‌گوید ۰٪ پر (۱۰ مگابایت خالی!) ولی df -i می‌گوید ۱۰۰٪ inode ها مصرف شده. پس وقتی «No space left» دیدی و df -h خالی نشان داد، df -i را بزن.

مثال ۸: /etc/fstab، mount دائمی

Section titled “مثال ۸: /etc/fstab، mount دائمی”

mount ای که با دست زدی بعد از ریبوت می‌رود. برای دائمی‌شدن، آن را در /etc/fstab می‌نویسند که سیستم هنگام بوت می‌خواند. هر خط شش ستون دارد: دستگاه، محل mount، نوع فایل‌سیستم، گزینه‌ها، dump، fsck. برای همین دیسک نمونه (loop یعنی از یک فایل mount کن):

Terminal window
echo "--- fstab قبلی (بدون توضیح):"
grep -v '^#' /etc/fstab
echo "/tmp/lx-disk.img /mnt/data ext4 loop 0 0" >> /etc/fstab
echo "--- بعد از افزودن یک خط:"
grep -v '^#' /etc/fstab
echo "--- mount -a (همه‌ی خط‌های fstab را که mount نیستند mount کن، مثل هنگام بوت):"
mount -a
findmnt /mnt/data
echo "--- پاک‌سازی:"
umount /mnt/data
sed -i '/lx-disk/d' /etc/fstab
rm -rf /mnt/data /mnt/small /tmp/lx-disk.img
losetup -a
echo "(هیچ loop باقی نمانده)"
خروجی
--- fstab قبلی (بدون توضیح):
--- بعد از افزودن یک خط:
/tmp/lx-disk.img /mnt/data ext4 loop 0 0
--- mount -a (همه‌ی خط‌های fstab را که mount نیستند mount کن، مثل هنگام بوت):
TARGET SOURCE FSTYPE OPTIONS
/mnt/data /dev/loop0 ext4 rw,relatime
--- پاک‌سازی:
(هیچ loop باقی نمانده)

(fstab این ماشین فقط توضیح داشت، برای همین سطر اول چیزی چاپ نکرد.) mount -a بعد از ویرایش fstab بهترین آزمایش است: اگر خطی غلط باشد همان‌جا خطا می‌دهد، نه موقع بوت بعدی که سرور بالا نمی‌آید.

پشت پرده: df و du چرا گاهی با هم نمی‌خوانند؟

Section titled “پشت پرده: df و du چرا گاهی با هم نمی‌خوانند؟”

df از خود فایل‌سیستم می‌پرسد «چند بلوک استفاده شده؟»، و du فایل‌ها را یکی‌یکی پیمایش می‌کند و اندازه‌شان را جمع می‌زند. بیشتر وقت‌ها برابرند؛ ولی اگر فایلی پاک شده ولی هنوز باز باشد، du آن را نمی‌بیند (اسمی در پوشه نیست) ولی df هنوز جایش را می‌شمارد، چون فضا تا بسته‌شدن آخرین پروسه‌ی بازکننده آزاد نمی‌شود. این یکی از شاخص‌ترین معماهای واقعی است:

Terminal window
mkdir -p /mnt/small
mount -t tmpfs -o size=20M tmpfs /mnt/small
dd if=/dev/zero of=/mnt/small/log bs=1M count=15 2>/dev/null
sleep 300 < /mnt/small/log &
holder=$!
rm /mnt/small/log
echo "--- پوشه خالی است:"
ls -l /mnt/small
du -sh /mnt/small
echo "--- ولی df ۱۵ مگابایت می‌گوید:"
df -h /mnt/small | tail -1
echo "--- چه کسی آن را باز نگه داشته؟ lsof +L1 (فایل‌هایی با 0 لینک):"
lsof +L1 /mnt/small
kill $holder; wait $holder 2>/dev/null
echo "--- بعد از بستن آن پروسه:"
df -h /mnt/small | tail -1
umount /mnt/small
خروجی
--- پوشه خالی است:
total 0
0 /mnt/small
--- ولی df ۱۵ مگابایت می‌گوید:
tmpfs 20M 15M 5.0M 75% /mnt/small
--- چه کسی آن را باز نگه داشته؟ lsof +L1 (فایل‌هایی با 0 لینک):
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NLINK NODE NAME
sleep 474 root 0r REG 0,67 15728640 0 2 /mnt/small/log (deleted)
--- بعد از بستن آن پروسه:
tmpfs 20M 0 20M 0% /mnt/small

فایل با rm از پوشه حذف شد (لینکش صفر شد) ولی sleep هنوز آن را باز داشت، پس هسته فضایش را نگه داشت: lsof +L1 فهرست «پاک‌شده ولی باز» را نشان می‌دهد. وقتی آن پروسه تمام شد فضا برگشت. در سرور واقعی معمولاً مقصر یک سرویس است که لاگ را باز دارد و کسی لاگ را با rm پاک کرده؛ راه‌حل درست: فایل را خالی کن (: > فایل یا truncate -s 0 فایل) به‌جای پاک کردن، یا سرویس را restart کن.

دستور کار
df -h فضای هر فایل‌سیستم
df -hT /مسیر با نوع فایل‌سیستم، فقط برای یک مسیر
df -i مصرف inode ها
du -sh * حجم هر مورد (بدون فایل‌های مخفی)
du -sh .[!.]* * حجم همه‌ی موارد از جمله مخفی
du -xh --max-depth=1 / | sort -rh | head بزرگ‌ترین پوشه‌ها
ls -lhS فایل‌ها از بزرگ به کوچک
free -h حافظه و swap
swapon --show فایل‌ها یا پارتیشن‌های swap
uptime / cat /proc/loadavg مدت بالا بودن و load average
nproc تعداد هسته‌های CPU
vmstat 1 5 آمار حافظه و CPU (هر ثانیه، ۵ بار)
lsblk دیسک‌ها و پارتیشن‌ها
mount / findmnt فهرست mount ها
mount دستگاه مسیر / umount مسیر وصل کردن / جدا کردن
lsof +L1 فایل‌های پاک‌شده ولی هنوز باز
ستون free معنی
used حافظه‌ی مصرف‌شده‌ی برنامه‌ها
buff/cache کش دیسک؛ قابل‌آزادسازی
available آنچه برای برنامه‌ی جدید واقعاً هست (این را نگاه کن)

۱) du -sh * فایل‌های مخفی را نمی‌بیند

Section titled “۱) du -sh * فایل‌های مخفی را نمی‌بیند”
Terminal window
cd demo
echo "--- با * (بدون مخفی‌ها):"
du -sh *
echo "--- با .[!.]* هم:"
du -sh .[!.]* *
echo "--- راه مطمئن‌تر: خودِ du پیمایش کند و sort:"
du -h --max-depth=1 . | sort -rh
خروجی
--- با * (بدون مخفی‌ها):
1.1M cache
7.1M logs
8.0K src
--- با .[!.]* هم:
8.1M .hidden
1.1M cache
7.1M logs
8.0K src
--- راه مطمئن‌تر: خودِ du پیمایش کند و sort:
17M .
8.1M ./.hidden
7.1M ./logs
1.1M ./cache
8.0K ./src

شل * را به نام‌های بدون نقطه‌ی اول باز می‌کند؛ پوشه‌ی .hidden هشت مگابایتی (بزرگ‌ترین!) نیامد. راه‌حل: du -h --max-depth=1 . | sort -rh که خود du همه‌چیز (از جمله مخفی‌ها) را می‌شمارد و . جمع کل است.

۲) پاک‌کردن فایل و تغییر نکردن df

Section titled “۲) پاک‌کردن فایل و تغییر نکردن df”

مثال «پشت پرده»: فایل لاگ را با rm پاک کردی ولی df همان ۹۵٪ است. راه‌حل: lsof +L1 برای پیدا کردن نگه‌دارنده، و restart آن سرویس؛ در آینده با truncate -s 0 خالی کن، نه rm.

ستون free ممکن است نسبت به total کوچک باشد در حالی که available (همان مثال ۴) خیلی بزرگ‌تر است؛ سیستم سالم است. راه‌حل: همیشه ستون available و رشد swap used را نگاه کن، نه free.

۴) mount روی یک پوشه‌ی پر، فایل‌های قبلی را «پنهان» می‌کند

Section titled “۴) mount روی یک پوشه‌ی پر، فایل‌های قبلی را «پنهان» می‌کند”
Terminal window
mkdir -p /mnt/shadow
echo "فایل اصلی" > /mnt/shadow/data.txt
echo "--- قبل از mount:"; ls /mnt/shadow
mount -t tmpfs tmpfs /mnt/shadow
echo "--- بعد از mount (روی همان پوشه):"; ls -A /mnt/shadow | wc -l
umount /mnt/shadow
echo "--- بعد از umount:"; ls /mnt/shadow
rm -rf /mnt/shadow
خروجی
--- قبل از mount:
data.txt
--- بعد از mount (روی همان پوشه):
0
--- بعد از umount:
data.txt

فایل‌ها پاک نشدند: mount جدید روی پوشه می‌نشیند و فایل‌های زیرش تا umount دیده نمی‌شوند. اگر دیدی «فایل‌هایم ناپدید شدند»، با findmnt ببین روی آن پوشه چیزی mount شده یا نه. راه‌حل: نقطه‌ی mount را یک پوشه‌ی خالی انتخاب کن.

اگر در یک مسیر دیسک دیگری mount شده باشد و rm -rf بزنی، محتوای آن دیسک پاک می‌شود، نه فقط پوشه‌ی خالی. راه‌حل: پیش از حذف مسیرهای تحت /mnt و /media، با findmnt مطمئن شو چیزی mount نیست (یا اول umount).

✎ تمرینآسان

درصد پر بودن فایل‌سیستم ریشه (/) و درصد مصرف inode آن را پیدا کن.

دیدن جواب
Terminal window
df -h /
df -i /
echo "--- فقط درصد‌ها:"
df --output=pcent,ipcent /
خروجی
Filesystem Size Used Avail Use% Mounted on
overlay 453G 22G 408G 6% /
Filesystem Inodes IUsed IFree IUse% Mounted on
overlay 30179328 344233 29835095 2% /
--- فقط درصد‌ها:
Use% IUse%
6% 2%

--output ستون‌های دلخواه df را انتخاب می‌کند (pcent درصد فضا و ipcent درصد inode).

✎ تمرینمتوسط

تمرین اصلی: بزرگ‌ترین پوشه‌های سیستم را پیدا کن. با du بزرگ‌ترین پوشه‌ی داخل /var را پیدا کن و بعد بزرگ‌ترین زیرپوشه‌ی آن را؛ دو سطح پایین برو.

دیدن جواب
Terminal window
echo "--- سطح اول: بزرگ‌ترین پوشه‌های /var"
sudo du -xh --max-depth=1 /var 2>/dev/null | sort -rh | sed -n '2,4p'
echo "--- سطح دوم: داخل /var/lib (بزرگ‌ترین‌ها)"
sudo du -xh --max-depth=1 /var/lib 2>/dev/null | sort -rh | sed -n '2,4p'
خروجی
--- سطح اول: بزرگ‌ترین پوشه‌های /var
67M /var/lib
3.2M /var/cache
600K /var/log
--- سطح دوم: داخل /var/lib (بزرگ‌ترین‌ها)
55M /var/lib/apt
11M /var/lib/dpkg
760K /var/lib/plocate

sed -n '2,4p' خط ۲ تا ۴ را می‌دهد (خط اول جمع خود پوشه است).

✎ تمرینسخت

یک دیسک ۵۰ مگابایتی شبیه‌سازی کن: فایل، mkfs.ext4، mount در /mnt/vault، یک فایل بنویس، و در df -h و lsblk و findmnt نشانش بده؛ دائمی‌اش کن با یک خط fstab، با umount و mount -a آزمایش کن که برمی‌گردد، و همه‌چیز را پاک کن. (root لازم است؛ این بخش را روی ماشین آزمایشی انجام می‌دهم.)

دیدن جواب
Terminal window
truncate -s 50M /tmp/lx-vault.img
mkfs.ext4 -q /tmp/lx-vault.img
mkdir -p /mnt/vault
mount -o loop /tmp/lx-vault.img /mnt/vault
echo "رمز خزانه" > /mnt/vault/secret.txt
df -h /mnt/vault | tail -1
lsblk -e 1,43 | grep vault
findmnt /mnt/vault
echo "/tmp/lx-vault.img /mnt/vault ext4 loop 0 0" >> /etc/fstab
umount /mnt/vault
echo "--- بعد از umount: $(ls -A /mnt/vault | wc -l) فایل (خالی)"
mount -a
echo "--- بعد از mount -a:"
cat /mnt/vault/secret.txt
umount /mnt/vault
sed -i '/lx-vault/d' /etc/fstab
rm -rf /mnt/vault /tmp/lx-vault.img
خروجی
/dev/loop0 43M 28K 40M 1% /mnt/vault
loop0 7:0 0 50M 0 loop /mnt/vault
TARGET SOURCE FSTYPE OPTIONS
/mnt/vault /dev/loop0 ext4 rw,relatime
--- بعد از umount: 0 فایل (خالی)
--- بعد از mount -a:
رمز خزانه
؟ آزمونک
  1. تفاوت df و du چیست؟

  2. در خروجی free کدام ستون نشان می‌دهد برای برنامه‌ی جدید چقدر حافظه در دسترس است؟

  3. load average ۸ روی سیستمی با ۴ هسته یعنی…

  4. df -h می‌گوید ۴۰٪ خالی است ولی نمی‌توانی فایل بسازی و خطا No space left on device است. اول چه می‌زنی؟

  5. فایل لاگ بزرگی را rm کردی ولی df همان‌قدر پر مانده است. چرا؟

  6. اگر یک دیسک را روی پوشه‌ای mount کنی که از قبل فایل داشته، چه می‌شود؟

  • دیسک: df -h (فضا؛ -T نوع، -i inode)، du -sh * و du -h --max-depth=1 . | sort -rh برای پیدا کردن مقصر. * فایل‌های مخفی را نمی‌بیند.
  • حافظه: free -h؛ ستون available مهم است، نه free. swapon --show فضای swap را نشان می‌دهد؛ رشد swap و کم‌شدن available علامت خطر است.
  • CPU: uptime و load average (۱، ۵، ۱۵ دقیقه)؛ با nproc مقایسه کن. vmstat 1 برای دیدن r، us، sy، id و wa.
  • دیسک‌ها و mount: lsblk دستگاه‌ها، mount/findmnt وصل‌شده‌ها، mount دستگاه مسیر و umount؛ دائمی‌کردن با /etc/fstab و آزمایش با mount -a.
  • «No space left on device» دو علت دارد: فضا یا inode؛ و اگر rm فضا را آزاد نکرد، lsof +L1.
برگه‌ی تقلب این درس
دستورکاری که می‌کند
df -h / df -hT / / df -iفضا، نوع فایل‌سیستم، inode
du -sh *حجم هر مورد (بدون مخفی‌ها)
du -h --max-depth=1 . | sort -rh | headبزرگ‌ترین‌ها، با مخفی‌ها
sudo du -xh --max-depth=1 / 2>/dev/null | sort -rh | headبزرگ‌ترین پوشه‌های سیستم
ls -lhSفایل‌ها از بزرگ به کوچک
free -hحافظه و swap (ستون available)
swapon --showفضای swap
uptime / nprocload average و تعداد هسته‌ها
vmstat 1 5آمار CPU و حافظه
lsblkدیسک‌ها و پارتیشن‌ها
mount | grep نام / findmnt مسیربررسی mount ها
sudo mount دستگاه مسیر / sudo umount مسیروصل / جدا کردن
lsof +L1فایل‌های پاک‌شده ولی باز