คำตอบสั้น ๆ: หาสาเหตุที่ Windows Server ช้าด้วย Task Manager, Resource Monitor, Performance Monitor และ PowerShell พร้อมวิธีดูว่าโปรเซสใดใช้ CPU, RAM หรือดิสก์มากที่สุด
คู่มือนี้อธิบาย Windows Server ทีละขั้นตอน พร้อมคำสั่งที่ใช้ได้จริงและปัญหาที่พบบ่อย
เมื่อ Windows Server ตอบสนองช้า Remote Desktop หน่วง หรือเว็บบน IIS โหลดนาน สาเหตุส่วนใหญ่มาจากทรัพยากรตัวใดตัวหนึ่งเต็ม ได้แก่ CPU, RAM, ดิสก์ (ทั้งพื้นที่และความเร็วอ่านเขียน) หรือเครือข่าย การรู้ว่าตัวไหนเป็นคอขวดและโปรเซสใดเป็นต้นเหตุ ช่วยให้แก้ได้ตรงจุดแทนการรีสตาร์ทเครื่องไปเรื่อยๆ
บทความนี้แนะนำเครื่องมือที่มีอยู่แล้วใน Windows Server 2019 และ 2022 ตั้งแต่ดูภาพรวมอย่างเร็วไปจนถึงเก็บข้อมูลย้อนหลัง พร้อมคำสั่ง PowerShell ที่ใช้ได้บน Server Core ซึ่งไม่มีหน้าจอกราฟิก
สิ่งที่ต้องเตรียม
- เข้าเครื่องผ่าน Remote Desktop ด้วยบัญชีในกลุ่ม Administrators (บัญชีทั่วไปจะเห็นเฉพาะโปรเซสของตัวเอง)
- PowerShell 5.1 ที่มากับระบบ
- ถ้าเครื่องช้ามากจนเปิดหน้าจอไม่ได้ ให้เข้าผ่าน Console ตามบทความ การ Remote เข้า Console Server ผ่าน Web UI
ขั้นตอนที่ 1: ดูภาพรวมด้วย Task Manager
กด Ctrl + Shift + Esc (ใช้ได้ทั้งในเครื่องและใน Remote Desktop) หรือคลิกขวาที่ Taskbar แล้วเลือก Task Manager ถ้าเห็นหน้าต่างเล็กให้กด More details
- แท็บ Processes: คลิกหัวคอลัมน์ CPU, Memory หรือ Disk เพื่อเรียงจากมากไปน้อย จะเห็นทันทีว่าโปรแกรมใดใช้ทรัพยากรสูง
- แท็บ Performance: กราฟ CPU, Memory, Disk และ Ethernet แยกตัว ดูค่า Utilization และ Up time ได้ที่นี่
- แท็บ Details: แสดงชื่อไฟล์จริงของโปรเซสและ PID คลิกขวาที่หัวคอลัมน์ แล้วเลือก Select columns เพื่อเพิ่มคอลัมน์ Command line ช่วยแยกว่า
w3wp.exeแต่ละตัวเป็นของ Application Pool ใด - แท็บ Users: ดูว่าผู้ใช้ Remote Desktop แต่ละคนใช้ทรัพยากรเท่าไร
ขั้นตอนที่ 2: เจาะลึกด้วย Resource Monitor
กด Win + R พิมพ์ resmon แล้ว Enter หรือกด Open Resource Monitor ที่ด้านล่างของแท็บ Performance ใน Task Manager
- แท็บ Disk: ส่วน Disk Activity บอกว่าไฟล์ใดถูกอ่านเขียนมากที่สุด ส่วน Storage แสดง Active Time และ Disk Queue Length ถ้า Active Time อยู่ที่ 100% ต่อเนื่อง แปลว่าดิสก์เป็นคอขวด
- แท็บ Memory: แถบสีด้านล่างแยก In Use, Modified, Standby และ Free ค่า Hard Faults/sec สูงต่อเนื่องหมายถึงระบบต้องอ่านข้อมูลจาก Page File บ่อย RAM ไม่พอ
- แท็บ Network: ดูโปรเซสที่รับส่งข้อมูลมาก และส่วน TCP Connections บอก IP ปลายทางที่เชื่อมต่ออยู่
- แท็บ CPU: ติ๊กโปรเซสที่สงสัย แล้วดูส่วน Services และ Associated Handles เพื่อรู้ว่าโปรเซสนั้นเปิดไฟล์ใดอยู่
ขั้นตอนที่ 3: ตรวจด้วย PowerShell
คำสั่งต่อไปนี้ใช้ได้ทั้งเครื่องที่มีหน้าจอและ Server Core เปิด PowerShell แบบ Run as Administrator
ดูการใช้ CPU รวม 5 ครั้ง ห่างกันครั้งละ 2 วินาที
Get-Counter '\Processor(_Total)\% Processor Time' -SampleInterval 2 -MaxSamples 5
ค่าที่ได้เป็นเปอร์เซ็นต์ของทุก Core รวมกัน ถ้าอยู่เหนือ 85-90 ตลอดแปลว่า CPU ไม่พอ
10 โปรเซสที่ใช้ RAM มากที่สุด (หน่วย MB)
Get-Process | Sort-Object WorkingSet64 -Descending | Select-Object -First 10 Name, Id, @{n='RAM_MB';e={[math]::Round($_.WorkingSet64/1MB)}}
10 โปรเซสที่ใช้เวลา CPU สะสมมากที่สุดตั้งแต่เริ่มทำงาน
Get-Process | Sort-Object CPU -Descending | Select-Object -First 10 Name, Id, CPU
คอลัมน์ CPU ของคำสั่งนี้เป็นวินาทีสะสม ไม่ใช่เปอร์เซ็นต์ปัจจุบัน ถ้าต้องการค่าปัจจุบันรายโปรเซส ใช้
Get-Counter '\Process(*)\% Processor Time' | Select-Object -ExpandProperty CounterSamples | Where-Object {$_.InstanceName -notin '_total','idle'} | Sort-Object CookedValue -Descending | Select-Object -First 10 InstanceName, CookedValue
ค่า CookedValue นับเต็ม 100 ต่อหนึ่ง Core เครื่อง 4 Core จึงมีค่าสูงสุดได้ถึง 400
ดู RAM ทั้งหมดและที่เหลือ (หน่วย GB)
Get-CimInstance Win32_OperatingSystem | Select-Object @{n='Total_GB';e={[math]::Round($_.TotalVisibleMemorySize/1MB,1)}}, @{n='Free_GB';e={[math]::Round($_.FreePhysicalMemory/1MB,1)}}
ดูพื้นที่ดิสก์ทุกไดรฟ์
Get-Volume | Where-Object DriveLetter | Select-Object DriveLetter, FileSystemLabel, @{n='Size_GB';e={[math]::Round($_.Size/1GB,1)}}, @{n='Free_GB';e={[math]::Round($_.SizeRemaining/1GB,1)}}
หาโฟลเดอร์ที่กินพื้นที่มากที่สุดในระดับแรกของไดรฟ์ C: (อาจใช้เวลาหลายนาทีบนดิสก์ใหญ่)
Get-ChildItem C:\ -Directory -Force -ErrorAction SilentlyContinue | ForEach-Object { $s = (Get-ChildItem $_.FullName -Recurse -File -Force -ErrorAction SilentlyContinue | Measure-Object Length -Sum).Sum; [pscustomobject]@{Folder=$_.FullName; GB=[math]::Round($s/1GB,2)} } | Sort-Object GB -Descending