فهرست مطالب
  1. چرا پر شدن دیسک این‌قدر بی‌صدا اتفاق می‌افتد
  2. چه چیزی را باید سنجید
  3. بررسی فضای دیسک ویندوز سرور با PowerShell
  4. آستانهٔ هشدار را چطور بگذاریم
  5. پیدا کردن اینکه چه چیزی جا گرفته
  6. آزاد کردن جا بدون شکستن چیزی
  7. تخمین ساده: چند روز تا پر شدن؟
  8. پیشگیری: سیاست نگه‌داری به‌جای پاک‌سازی دستی
  9. پایش فضای دیسک با ServerMug
  10. پرسش‌های پرتکرار
    1. چقدر فضای آزاد روی درایو C: کافی است؟
    2. آیا فعال کردن NTFS Compression راه خوبی برای آزاد کردن جاست؟
    3. Storage Sense روی ویندوز سرور کار می‌کند؟
  11. جمع‌بندی

پر شدن درایو یکی از کم‌هیجان‌ترین و در عین حال پرهزینه‌ترین خرابی‌های سرور است. هیچ هکری در کار نیست، هیچ باگ پیچیده‌ای هم نیست؛ فقط یک فایل لاگ IIS که سه سال پاک نشده، یا پوشهٔ بکاپی که کسی یادش رفته قدیمی‌هایش را حذف کند. نتیجه اما جدی است: SQL Server دیگر نمی‌تواند فایل را بزرگ کند، Windows Update نصب نمی‌شود، سرویس‌ها با خطاهای مبهم متوقف می‌شوند و گاهی خود ویندوز روی درایو C: دیگر جای page file هم ندارد. پایش فضای دیسک ویندوز سرور کار ساده‌ای به نظر می‌رسد، ولی بیشتر تیم‌ها آن را یا اصلاً ندارند یا با آستانه‌ای دارند که یا دیر خبر می‌دهد یا آن‌قدر زود و زیاد که کسی دیگر نگاهش نمی‌کند.

در این نوشته می‌بینیم چه چیزی را باید سنجید، آستانه را چطور منطقی بگذاریم، با PowerShell وضعیت درایوها و پوشه‌های پرحجم را پیدا کنیم و جا را بدون شکستن چیزی آزاد کنیم.

چرا پر شدن دیسک این‌قدر بی‌صدا اتفاق می‌افتد

بیشتر چیزهایی که دیسک را پر می‌کنند، آرام و پیوسته رشد می‌کنند: لاگ‌های برنامه، لاگ‌های IIS در C:inetpublogsLogFiles، فایل‌های موقت، بکاپ‌های محلی، پوشهٔ SoftwareDistribution و فایل‌های dump. چون رشد روزانه کوچک است، هیچ‌کس متوجهش نمی‌شود تا روزی که درایو به صفر برسد. گروه دوم رشدهای ناگهانی‌اند: یک باگ که در حلقه لاگ می‌نویسد، یک rebuild ایندکس که لاگ ترنزکشن را چند برابر می‌کند، یا یک کاربر که پوشهٔ عکس‌هایش را روی اشتراک فایل کپی می‌کند.

این دو الگو دو نوع هشدار لازم دارند. برای رشد آرام، آستانهٔ ثابت کافی است به شرطی که با فاصلهٔ کافی گذاشته شود. برای رشد ناگهانی، باید سرعت تغییر را هم ببینید، وگرنه از «۲۰ درصد آزاد» تا «صفر» ممکن است فقط یک ساعت فاصله باشد.

چه چیزی را باید سنجید

  • فضای آزاد هر درایو، جدا: میانگین فضای آزاد کل سرور معنایی ندارد. درایو C: با ۲ گیگ آزاد و درایو D: با ۵۰۰ گیگ آزاد، یعنی سروری در خطر.
  • هم درصد و هم مقدار مطلق: ۱۰ درصد آزاد روی یک درایو ۴ ترابایتی یعنی ۴۰۰ گیگ، که احتمالاً هنوز کافی است. ۱۰ درصد روی درایو ۶۰ گیگی C: یعنی ۶ گیگ، که برای یک آپدیت تجمعی ویندوز کافی نیست.
  • Mount point ها و volume های بدون حرف: روی سرورهای SQL Server یا اشتراک فایل، گاهی volume ها به‌صورت پوشه mount می‌شوند. اسکریپتی که فقط درایوهای حرف‌دار را می‌خواند، آنها را نمی‌بیند.
  • صف و تأخیر I/O: دیسکی که پر نیست ولی Avg. Disk sec/Transfer بالایی دارد، مشکل دیگری است که همین‌جا باید دیده شود.

بررسی فضای دیسک ویندوز سرور با PowerShell

کلاس CIM Win32_Volume برخلاف Win32_LogicalDisk volume های mount شده بدون حرف را هم برمی‌گرداند. دستور زیر همهٔ volume های محلی را با فضای آزاد به گیگابایت و درصد نشان می‌دهد:

Get-CimInstance -ClassName Win32_Volume -Filter "DriveType = 3" |
    Where-Object { $_.Capacity -gt 0 } |
    Select-Object Name, Label,
        @{ n = 'SizeGB'; e = { [math]::Round($_.Capacity / 1GB, 1) } },
        @{ n = 'FreeGB'; e = { [math]::Round($_.FreeSpace / 1GB, 1) } },
        @{ n = 'FreePct'; e = { [math]::Round(100 * $_.FreeSpace / $_.Capacity, 1) } } |
    Sort-Object FreePct |
    Format-Table -AutoSize

برای اجرای همین بررسی روی چند سرور، می‌توانید از -ComputerName استفاده کنید، به شرطی که WinRM روی سرورها فعال باشد:

$servers = 'FILESRV-01', 'DBSERVER', 'APP-01'
Get-CimInstance -ClassName Win32_Volume -ComputerName $servers -Filter "DriveType = 3" |
    Where-Object { $_.Capacity -gt 0 -and ($_.FreeSpace / $_.Capacity) -lt 0.15 } |
    Select-Object PSComputerName, Name,
        @{ n = 'FreeGB'; e = { [math]::Round($_.FreeSpace / 1GB, 1) } }

آستانهٔ هشدار را چطور بگذاریم

هشداری که هر روز بی‌دلیل می‌آید، دیگر خوانده نمی‌شود. آستانه‌ای که خیلی پایین است، وقتی به دستتان می‌رسد که دیگر فرصتی نمانده. چند اصل عملی:

  1. دو سطح بگذارید. مثلاً «هشدار» در ۱۵ درصد و «بحرانی» در ۵ درصد. اولی برای ساعت کاری، دومی برای بیدار کردن کسی.
  2. شرط را ترکیبی بنویسید. هشدار وقتی که درصد آزاد کمتر از ۱۰ و مقدار آزاد کمتر از ۲۰ گیگ باشد. این یک شرط از هشدارهای بی‌معنی روی درایوهای بزرگ جلوگیری می‌کند.
  3. درایو C: را جدا ببینید. برای درایو سیستم، آستانهٔ مطلق مهم‌تر است. کمتر از ۱۰ تا ۱۵ گیگ روی C: یعنی آپدیت بعدی ممکن است نصب نشود.
  4. پایداری را شرط کنید. هشدار وقتی که وضعیت چند دقیقه پایدار است، نه یک لحظه. فایل موقتی که یک دقیقه ساخته و پاک می‌شود نباید کسی را بیدار کند.
  5. نرخ رشد را هم ببینید. اگر یک درایو در یک ساعت ۱۰ درصد پر شده، حتی اگر هنوز به آستانه نرسیده، چیزی غیرعادی در جریان است.

پیدا کردن اینکه چه چیزی جا گرفته

وقتی هشدار آمد، اولین سؤال این است: کدام پوشه؟ ابزارهای گرافیکی مثل WinDirStat یا TreeSize روی سرور کار را راحت می‌کنند، ولی همیشه اجازهٔ نصبشان را ندارید. اسکریپت زیر حجم پوشه‌های سطح اول یک مسیر را حساب می‌کند. روی درایوهای بزرگ ممکن است چند دقیقه طول بکشد و خودش I/O تولید می‌کند، پس آن را در ساعت شلوغ اجرا نکنید.

$root = 'C:'
Get-ChildItem -Path $root -Directory -Force -ErrorAction SilentlyContinue |
    ForEach-Object {
        $size = (Get-ChildItem -Path $_.FullName -Recurse -File -Force -ErrorAction SilentlyContinue |
                 Measure-Object -Property Length -Sum).Sum
        [pscustomobject]@{ Folder = $_.FullName; SizeGB = [math]::Round($size / 1GB, 2) }
    } |
    Sort-Object SizeGB -Descending |
    Select-Object -First 15

برای پیدا کردن بزرگ‌ترین فایل‌ها، به‌خصوص فایل‌های dump و بکاپ فراموش‌شده:

Get-ChildItem -Path 'D:' -Recurse -File -Force -ErrorAction SilentlyContinue |
    Where-Object { $_.Length -gt 1GB } |
    Sort-Object Length -Descending |
    Select-Object FullName, @{ n = 'GB'; e = { [math]::Round($_.Length / 1GB, 2) } }, LastWriteTime -First 20

آزاد کردن جا بدون شکستن چیزی

پاک کردن فایل روی سرور production همیشه ریسک دارد. این جدول جاهای رایج و روش امن پاک‌سازی هرکدام را خلاصه می‌کند:

مسیرچه چیزیروش امن
C:WindowsWinSxSاجزای ویندوز و نسخه‌های قبلیفقط با DISM؛ هرگز دستی پاک نکنید
C:inetpublogsLogFilesلاگ‌های IISحذف قدیمی‌تر از N روز، یا فشرده و منتقل کردن
C:WindowsTemp و Temp کاربرانفایل‌های موقتحذف فایل‌های قدیمی‌تر از چند روز
پوشهٔ بکاپ محلیبکاپ‌های SQL یا برنامهسیاست نگه‌داری در خود جاب بکاپ
C:WindowsSoftwareDistributionDownloadدانلودهای Windows Updateتوقف سرویس wuauserv، پاک‌سازی، شروع دوباره

برای WinSxS دستور زیر نسخه‌های جایگزین‌شدهٔ اجزا را پاک می‌کند. گزینهٔ /ResetBase جای بیشتری آزاد می‌کند ولی بعد از آن نمی‌توانید آپدیت‌های نصب‌شده را حذف کنید؛ پس فقط وقتی از آپدیت‌های فعلی مطمئنید از آن استفاده کنید.

Dism.exe /Online /Cleanup-Image /AnalyzeComponentStore
Dism.exe /Online /Cleanup-Image /StartComponentCleanup
# Dism.exe /Online /Cleanup-Image /StartComponentCleanup /ResetBase

و برای لاگ‌های IIS قدیمی‌تر از ۳۰ روز. اول با -WhatIf ببینید چه چیزی حذف می‌شود:

$limit = (Get-Date).AddDays(-30)
Get-ChildItem 'C:inetpublogsLogFiles' -Recurse -File -Filter '*.log' |
    Where-Object { $_.LastWriteTime -lt $limit } |
    Remove-Item -WhatIf

فایل‌های .ldf و .mdf را هرگز برای آزاد کردن جا پاک یا جابه‌جا نکنید. اگر لاگ ترنزکشن SQL Server دیسک را پر کرده، علت را با log_reuse_wait_desc پیدا کنید؛ پاک کردن فایل دیتابیس را از دسترس خارج می‌کند.

تخمین ساده: چند روز تا پر شدن؟

آستانهٔ ثابت می‌گوید «الان کم است»، ولی نمی‌گوید «کِی تمام می‌شود». برای جواب سؤال دوم کافی است فضای آزاد را هر روز در یک فایل ثبت کنید و از دو نقطه، نرخ مصرف روزانه را حساب کنید. اسکریپت زیر را با Scheduled Task روزی یک بار اجرا کنید تا یک تاریخچهٔ CSV ساده بسازد:

$log = 'C:Opsdisk-history.csv'
Get-CimInstance Win32_Volume -Filter "DriveType = 3" |
    Where-Object { $_.Capacity -gt 0 } |
    Select-Object @{ n = 'Date'; e = { (Get-Date).ToString('yyyy-MM-dd') } },
                  Name,
                  @{ n = 'FreeGB'; e = { [math]::Round($_.FreeSpace / 1GB, 2) } } |
    Export-Csv -Path $log -Append -NoTypeInformation -Encoding UTF8

اگر فضای آزاد درایو D: سی روز پیش ۱۲۰ گیگ بوده و امروز ۶۰ گیگ است، نرخ مصرف حدود ۲ گیگ در روز است و با همین روند حدود سی روز دیگر وقت دارید. این تخمین خطی است و رشدهای ناگهانی را پیش‌بینی نمی‌کند، ولی برای برنامه‌ریزی خرید دیسک یا تنظیم سیاست نگه‌داری، از هر آستانهٔ ثابتی مفیدتر است. نکتهٔ مهم این است که نرخ را روی بازهٔ چند هفته‌ای حساب کنید، نه یک روز؛ یک روز پرکار یا یک پاک‌سازی دستی، تخمین تک‌روزه را کاملاً بی‌معنی می‌کند.

یک منبع پنهان دیگر را هم فراموش نکنید: Volume Shadow Copy. اگر روی یک volume اشتراک فایل، Shadow Copy فعال است، فضای ذخیره‌اش ممکن است تا سقف تعیین‌شده رشد کند. دستور vssadmin list shadowstorage مقدار مصرف‌شده و سقف را نشان می‌دهد.

پیشگیری: سیاست نگه‌داری به‌جای پاک‌سازی دستی

هر بار که دستی جا آزاد می‌کنید، یک قانون نگه‌داری بنویسید تا دفعهٔ بعد خودکار انجام شود. لاگ‌های برنامه را با چرخش روزانه و سقف تعداد فایل بنویسید؛ کتابخانه‌هایی مثل Serilog و NLog این را با یک تنظیم انجام می‌دهند. برای لاگ‌های IIS یک Scheduled Task با اسکریپت بالا بسازید. بکاپ‌های محلی را فقط تا وقتی نگه دارید که کپی بیرونی‌شان تأیید شده است. و مهم‌تر از همه، داده و سیستم‌عامل را روی درایوهای جدا بگذارید تا پر شدن پوشهٔ داده، ویندوز را از کار نیندازد.

اگر لاگ‌های برنامه بخش بزرگ مشکل‌اند، شاید وقت آن رسیده که اصلاً روی دیسک سرور نمانند. در نوشتهٔ لاگ متمرکز توضیح داده‌ایم چرا نگه داشتن لاگ روی خود سرور هم جا می‌گیرد و هم جستجو را سخت می‌کند.

پایش فضای دیسک با ServerMug

اسکریپت‌های بالا برای عیب‌یابی خوب‌اند، ولی کسی باید آنها را اجرا کند. سرورماگ با یک سنسور سبک روی ویندوز سرور ۲۰۱۶ به بعد و لینوکس، فضای هر درایو را همراه با CPU، رم و شبکه هر ۱۵ ثانیه می‌خواند و نمودارش را از یک ساعت تا یک سال نگه می‌دارد. هشدار وقتی می‌آید که مشکل پایدار است، نه یک جهش لحظه‌ای، و با پیامک یا webhook ارسال می‌شود؛ ارجاع به نفر دوم، ساعت سکوت برای هشدارهای غیربحرانی و سقف روزانهٔ پیامک هم دارد. سرورماگ عمداً هیچ دستوری روی سرور اجرا نمی‌کند، پس پاک‌سازی همچنان کار خود شماست؛ کارش این است که پیش از صفر شدن درایو خبردار شوید.

برای فهرست کامل چیزهایی که روی هر سرور باید پایش شود، چک‌لیست پایش سرور ویندوز و لینوکس را ببینید. اگر درایو پرشده متعلق به SQL Server است، پر شدن لاگ ترنزکشن و فرگمنتیشن ایندکس هم به کارتان می‌آید.

پرسش‌های پرتکرار

چقدر فضای آزاد روی درایو C: کافی است؟

عدد دقیقی وجود ندارد، ولی در عمل کمتر از ۱۰ تا ۱۵ گیگابایت روی درایو سیستم دردسرساز است، چون آپدیت‌های تجمعی ویندوز سرور برای نصب به چند گیگ فضای موقت نیاز دارند. اگر برنامه‌ها یا لاگ‌ها هم روی C: می‌نویسند، این عدد باید بیشتر باشد.

آیا فعال کردن NTFS Compression راه خوبی برای آزاد کردن جاست؟

برای پوشه‌های لاگ و آرشیو که کم خوانده می‌شوند می‌تواند مفید باشد. برای فایل‌های دیتابیس، فایل‌های پرنوشتن و پوشه‌های سیستمی توصیه نمی‌شود، چون هزینهٔ CPU و I/O دارد و SQL Server پشتیبانی رسمی از فایل‌های داده روی volume فشرده را محدود کرده است.

Storage Sense روی ویندوز سرور کار می‌کند؟

Storage Sense برای ویندوز دسکتاپ طراحی شده و روی نسخه‌های سرور تکیه‌گاه قابل اعتمادی نیست. روی سرور بهتر است پاک‌سازی را با Scheduled Task و اسکریپت مشخصی انجام دهید که می‌دانید دقیقاً چه چیزی را حذف می‌کند.

جمع‌بندی

پر شدن دیسک قابل پیشگیری‌ترین خرابی سرور است. فضای هر volume را جدا بسنجید، آستانه را هم درصدی و هم مطلق بگذارید، درایو سیستم را سخت‌گیرانه‌تر ببینید و به سرعت رشد هم توجه کنید. وقتی هشدار آمد، با PowerShell پوشه‌ها و فایل‌های بزرگ را پیدا کنید و فقط با روش‌های امن مثل DISM و حذف با -WhatIf جا آزاد کنید. سپس هر پاک‌سازی دستی را به یک قانون نگه‌داری خودکار تبدیل کنید تا دفعهٔ بعد اصلاً لازم نباشد.