Pembuatan skrip dengan riwayat performa PowerShell dan Storage Spaces Direct
Di Windows Server 2019, Storage Spaces Direct merekam dan menyimpan riwayat performa yang luas untuk komputer virtual, server, drive, volume, adaptor jaringan, dan banyak lagi. Riwayat performa mudah dikueri dan diproses di PowerShell sehingga Anda dapat dengan cepat beralih dari data mentah ke jawaban aktual untuk pertanyaan seperti:
- Apakah ada lonjakan CPU minggu lalu?
- Apakah ada disk fisik yang menunjukkan latensi abnormal?
- VM mana yang paling banyak menggunakan IOPS penyimpanan saat ini?
- Apakah bandwidth jaringan saya jenuh?
- Kapan volume ini akan kehabisan ruang kosong?
- Dalam sebulan terakhir, VM mana yang paling banyak menggunakan memori?
Get-ClusterPerf
Cmdlet dibangun untuk pembuatan skrip. Ini menerima input dari cmdlet seperti Get-VM
atau Get-PhysicalDisk
oleh alur untuk menangani asosiasi, dan Anda dapat menyalurkan outputnya ke cmdlet utilitas seperti Sort-Object
, Where-Object
, dan Measure-Object
untuk dengan cepat menyusun kueri yang kuat.
Topik ini menyediakan dan menjelaskan 6 contoh skrip yang menjawab 6 pertanyaan di atas. Mereka menyajikan pola yang dapat Anda terapkan untuk menemukan puncak, menemukan rata-rata, garis tren plot, deteksi outlier yang berjalan, dan banyak lagi, di berbagai data dan jangka waktu. Mereka disediakan sebagai kode starter gratis bagi Anda untuk menyalin, memperluas, dan menggunakan kembali.
Catatan
Untuk brevity, contoh skrip menghilangkan hal-hal seperti penanganan kesalahan yang mungkin Anda harapkan dari kode PowerShell berkualitas tinggi. Mereka dimaksudkan terutama untuk inspirasi dan pendidikan daripada penggunaan produksi.
Sampel 1: CPU, saya melihat Anda!
Sampel ini menggunakan ClusterNode.Cpu.Usage
seri dari LastWeek
jangka waktu untuk menunjukkan penggunaan CPU maksimum ("tanda air tinggi"), minimum, dan rata-rata untuk setiap server dalam kluster. Ini juga melakukan analisis kuartil sederhana untuk menunjukkan berapa jam penggunaan CPU lebih dari 25%, 50%, dan 75% dalam 8 hari terakhir.
Cuplikan layar
Pada cuplikan layar di bawah ini, kita melihat bahwa Server-02 memiliki lonjakan yang tidak dapat dijelaskan minggu lalu:
Cara kerjanya
Output dari Get-ClusterPerf
pipa dengan baik ke cmdlet bawaan Measure-Object
, kami hanya menentukan Value
properti . -Maximum
Dengan bendera , -Minimum
, dan -Average
, Measure-Object
memberi kita tiga kolom pertama hampir secara gratis. Untuk melakukan analisis kuartil, kita dapat menyalurkan dan Where-Object
menghitung berapa banyak nilai -Gt
(lebih besar dari) 25, 50, atau 75. Langkah terakhir adalah mempercantik dengan Format-Hours
fungsi pembantu dan Format-Percent
- tentu opsional.
Skrip
Berikut skripnya:
Function Format-Hours {
Param (
$RawValue
)
# Weekly timeframe has frequency 15 minutes = 4 points per hour
[Math]::Round($RawValue/4)
}
Function Format-Percent {
Param (
$RawValue
)
[String][Math]::Round($RawValue) + " " + "%"
}
$Output = Get-ClusterNode | ForEach-Object {
$Data = $_ | Get-ClusterPerf -ClusterNodeSeriesName "ClusterNode.Cpu.Usage" -TimeFrame "LastWeek"
$Measure = $Data | Measure-Object -Property Value -Minimum -Maximum -Average
$Min = $Measure.Minimum
$Max = $Measure.Maximum
$Avg = $Measure.Average
[PsCustomObject]@{
"ClusterNode" = $_.Name
"MinCpuObserved" = Format-Percent $Min
"MaxCpuObserved" = Format-Percent $Max
"AvgCpuObserved" = Format-Percent $Avg
"HrsOver25%" = Format-Hours ($Data | Where-Object Value -Gt 25).Length
"HrsOver50%" = Format-Hours ($Data | Where-Object Value -Gt 50).Length
"HrsOver75%" = Format-Hours ($Data | Where-Object Value -Gt 75).Length
}
}
$Output | Sort-Object ClusterNode | Format-Table
Sampel 2: Api, kebakaran, outlier latensi
Sampel ini menggunakan PhysicalDisk.Latency.Average
seri dari LastHour
jangka waktu untuk mencari outlier statistik, yang didefinisikan sebagai drive dengan latensi rata-rata per jam melebihi +3σ (tiga simpangihan standar) di atas rata-rata populasi.
Penting
Untuk brevity, skrip ini tidak menerapkan perlindungan terhadap varians rendah, tidak menangani sebagian data yang hilang, tidak membedakan dengan model atau firmware, dll. Harap lakukan penilaian yang baik dan jangan mengandalkan skrip ini saja untuk menentukan apakah akan mengganti hard disk. Ini disajikan di sini hanya untuk tujuan pendidikan.
Cuplikan layar
Pada cuplikan layar di bawah ini, kita melihat tidak ada outlier:
Cara kerjanya
Pertama, kami mengecualikan drive diam atau hampir diam dengan memeriksa bahwa PhysicalDisk.Iops.Total
secara -Gt 1
konsisten . Untuk setiap HDD aktif, kami menyalurkan jangka waktunya LastHour
, terdiri dari 360 pengukuran pada interval 10 detik, untuk Measure-Object -Average
mendapatkan latensi rata-ratanya dalam satu jam terakhir. Ini mengatur populasi kita.
Kami menerapkan rumus yang dikenal luas untuk menemukan rata-rata μ
dan simpang siur σ
standar populasi. Untuk setiap HDD aktif, kami membandingkan latensi rata-ratanya dengan rata-rata populasi dan dibagi dengan simpang siur standar. Kami menyimpan nilai mentah, sehingga kami dapat Sort-Object
hasil kami, tetapi menggunakan Format-Latency
dan Format-StandardDeviation
membantu fungsi untuk mempercantik apa yang akan kami tampilkan - tentu opsional.
Jika ada drive lebih dari +3σ, kami Write-Host
berwarna merah; jika tidak, berwarna hijau.
Skrip
Berikut skripnya:
Function Format-Latency {
Param (
$RawValue
)
$i = 0 ; $Labels = ("s", "ms", "μs", "ns") # Petabits, just in case!
Do { $RawValue *= 1000 ; $i++ } While ( $RawValue -Lt 1 )
# Return
[String][Math]::Round($RawValue, 2) + " " + $Labels[$i]
}
Function Format-StandardDeviation {
Param (
$RawValue
)
If ($RawValue -Gt 0) {
$Sign = "+"
}
Else {
$Sign = "-"
}
# Return
$Sign + [String][Math]::Round([Math]::Abs($RawValue), 2) + "σ"
}
$HDD = Get-StorageSubSystem Cluster* | Get-PhysicalDisk | Where-Object MediaType -Eq HDD
$Output = $HDD | ForEach-Object {
$Iops = $_ | Get-ClusterPerf -PhysicalDiskSeriesName "PhysicalDisk.Iops.Total" -TimeFrame "LastHour"
$AvgIops = ($Iops | Measure-Object -Property Value -Average).Average
If ($AvgIops -Gt 1) { # Exclude idle or nearly idle drives
$Latency = $_ | Get-ClusterPerf -PhysicalDiskSeriesName "PhysicalDisk.Latency.Average" -TimeFrame "LastHour"
$AvgLatency = ($Latency | Measure-Object -Property Value -Average).Average
[PsCustomObject]@{
"FriendlyName" = $_.FriendlyName
"SerialNumber" = $_.SerialNumber
"MediaType" = $_.MediaType
"AvgLatencyPopulation" = $null # Set below
"AvgLatencyThisHDD" = Format-Latency $AvgLatency
"RawAvgLatencyThisHDD" = $AvgLatency
"Deviation" = $null # Set below
"RawDeviation" = $null # Set below
}
}
}
If ($Output.Length -Ge 3) { # Minimum population requirement
# Find mean μ and standard deviation σ
$μ = ($Output | Measure-Object -Property RawAvgLatencyThisHDD -Average).Average
$d = $Output | ForEach-Object { ($_.RawAvgLatencyThisHDD - $μ) * ($_.RawAvgLatencyThisHDD - $μ) }
$σ = [Math]::Sqrt(($d | Measure-Object -Sum).Sum / $Output.Length)
$FoundOutlier = $False
$Output | ForEach-Object {
$Deviation = ($_.RawAvgLatencyThisHDD - $μ) / $σ
$_.AvgLatencyPopulation = Format-Latency $μ
$_.Deviation = Format-StandardDeviation $Deviation
$_.RawDeviation = $Deviation
# If distribution is Normal, expect >99% within 3σ
If ($Deviation -Gt 3) {
$FoundOutlier = $True
}
}
If ($FoundOutlier) {
Write-Host -BackgroundColor Black -ForegroundColor Red "Oh no! There's an HDD significantly slower than the others."
}
Else {
Write-Host -BackgroundColor Black -ForegroundColor Green "Good news! No outlier found."
}
$Output | Sort-Object RawDeviation -Descending | Format-Table FriendlyName, SerialNumber, MediaType, AvgLatencyPopulation, AvgLatencyThisHDD, Deviation
}
Else {
Write-Warning "There aren't enough active drives to look for outliers right now."
}
Sampel 3: Tetangga berisik? Itu tulisan!
Riwayat performa juga dapat menjawab pertanyaan tentang saat ini. Pengukuran baru tersedia secara real time, setiap 10 detik. Sampel ini menggunakan VHD.Iops.Total
seri dari MostRecent
jangka waktu untuk mengidentifikasi komputer virtual tersibuk (beberapa mungkin mengatakan "paling berisik") yang menggunakan IOPS penyimpanan terbanyak, di setiap host dalam kluster, dan menunjukkan perincian baca/tulis aktivitas mereka.
Cuplikan layar
Pada cuplikan layar di bawah ini, kita melihat 10 komputer virtual teratas berdasarkan aktivitas penyimpanan:
Cara kerjanya
Tidak seperti Get-PhysicalDisk
, Get-VM
cmdlet tidak sadar kluster - cmdlet hanya mengembalikan VM di server lokal. Untuk mengkueri dari setiap server secara paralel, kami membungkus panggilan kami di Invoke-Command (Get-ClusterNode).Name { ... }
. Untuk setiap VM, kita mendapatkan VHD.Iops.Total
pengukuran , VHD.Iops.Read
, dan VHD.Iops.Write
. Dengan tidak menentukan -TimeFrame
parameter, kita mendapatkan MostRecent
satu titik data untuk masing-masing.
Tip
Seri ini mencerminkan jumlah aktivitas VM ini ke semua file VHD/VHDX-nya. Ini adalah contoh di mana riwayat performa secara otomatis dikumpulkan untuk kita. Untuk mendapatkan perincian per-VHD/VHDX, Anda dapat menyalurkan individu Get-VHD
ke Get-ClusterPerf
alih-alih VM.
Hasil dari setiap server berkumpul sebagai $Output
, yang kita bisa Sort-Object
dan kemudian Select-Object -First 10
. Perhatikan bahwa Invoke-Command
menghias hasil dengan properti yang PsComputerName
menunjukkan dari mana asalnya, yang dapat kita cetak untuk mengetahui di mana VM berjalan.
Skrip
Berikut skripnya:
$Output = Invoke-Command (Get-ClusterNode).Name {
Function Format-Iops {
Param (
$RawValue
)
$i = 0 ; $Labels = (" ", "K", "M", "B", "T") # Thousands, millions, billions, trillions...
Do { if($RawValue -Gt 1000){$RawValue /= 1000 ; $i++ } } While ( $RawValue -Gt 1000 )
# Return
[String][Math]::Round($RawValue) + " " + $Labels[$i]
}
Get-VM | ForEach-Object {
$IopsTotal = $_ | Get-ClusterPerf -VMSeriesName "VHD.Iops.Total"
$IopsRead = $_ | Get-ClusterPerf -VMSeriesName "VHD.Iops.Read"
$IopsWrite = $_ | Get-ClusterPerf -VMSeriesName "VHD.Iops.Write"
[PsCustomObject]@{
"VM" = $_.Name
"IopsTotal" = Format-Iops $IopsTotal.Value
"IopsRead" = Format-Iops $IopsRead.Value
"IopsWrite" = Format-Iops $IopsWrite.Value
"RawIopsTotal" = $IopsTotal.Value # For sorting...
}
}
}
$Output | Sort-Object RawIopsTotal -Descending | Select-Object -First 10 | Format-Table PsComputerName, VM, IopsTotal, IopsRead, IopsWrite
Sampel 4: Seperti yang mereka katakan, "25-gig adalah 10-gig baru"
Sampel ini menggunakan NetAdapter.Bandwidth.Total
seri dari LastDay
jangka waktu untuk mencari tanda-tanda saturasi jaringan, yang didefinisikan sebagai >90% dari bandwidth maksimum teoritis. Untuk setiap adaptor jaringan dalam kluster, ini membandingkan penggunaan bandwidth yang diamati tertinggi di hari terakhir dengan kecepatan tautan yang dinyatakan.
Cuplikan layar
Pada cuplikan layar di bawah ini, kita melihat bahwa satu Fabrikam NX-4 Pro #2 memuncak di hari terakhir:
Cara kerjanya
Kami mengulangi trik kami Invoke-Command
dari atas ke Get-NetAdapter
di setiap server dan menyalurkan ke .Get-ClusterPerf
Sepanjang jalan, kami mengambil dua properti yang relevan: string-nya LinkSpeed
seperti "10 Gbps", dan bilangan bulat mentahnya Speed
seperti 10000000000. Kami menggunakan Measure-Object
untuk mendapatkan rata-rata dan puncak dari hari terakhir (pengingat: setiap pengukuran dalam LastDay
jangka waktu mewakili 5 menit) dan dikalikan dengan 8 bit per byte untuk mendapatkan perbandingan apel-ke-apel.
Catatan
Beberapa vendor, seperti Chelsio, menyertakan aktivitas akses memori langsung jarak jauh (RDMA) di penghitung kinerja Adaptor Jaringan mereka, sehingga termasuk dalam seri iniNetAdapter.Bandwidth.Total
. Yang lain, seperti Mellanox, mungkin tidak. Jika vendor Anda tidak melakukannya, cukup tambahkan NetAdapter.Bandwidth.RDMA.Total
seri di versi skrip ini.
Skrip
Berikut skripnya:
$Output = Invoke-Command (Get-ClusterNode).Name {
Function Format-BitsPerSec {
Param (
$RawValue
)
$i = 0 ; $Labels = ("bps", "kbps", "Mbps", "Gbps", "Tbps", "Pbps") # Petabits, just in case!
Do { $RawValue /= 1000 ; $i++ } While ( $RawValue -Gt 1000 )
# Return
[String][Math]::Round($RawValue) + " " + $Labels[$i]
}
Get-NetAdapter | ForEach-Object {
$Inbound = $_ | Get-ClusterPerf -NetAdapterSeriesName "NetAdapter.Bandwidth.Inbound" -TimeFrame "LastDay"
$Outbound = $_ | Get-ClusterPerf -NetAdapterSeriesName "NetAdapter.Bandwidth.Outbound" -TimeFrame "LastDay"
If ($Inbound -Or $Outbound) {
$InterfaceDescription = $_.InterfaceDescription
$LinkSpeed = $_.LinkSpeed
$MeasureInbound = $Inbound | Measure-Object -Property Value -Maximum
$MaxInbound = $MeasureInbound.Maximum * 8 # Multiply to bits/sec
$MeasureOutbound = $Outbound | Measure-Object -Property Value -Maximum
$MaxOutbound = $MeasureOutbound.Maximum * 8 # Multiply to bits/sec
$Saturated = $False
# Speed property is Int, e.g. 10000000000
If (($MaxInbound -Gt (0.90 * $_.Speed)) -Or ($MaxOutbound -Gt (0.90 * $_.Speed))) {
$Saturated = $True
Write-Warning "In the last day, adapter '$InterfaceDescription' on server '$Env:ComputerName' exceeded 90% of its '$LinkSpeed' theoretical maximum bandwidth. In general, network saturation leads to higher latency and diminished reliability. Not good!"
}
[PsCustomObject]@{
"NetAdapter" = $InterfaceDescription
"LinkSpeed" = $LinkSpeed
"MaxInbound" = Format-BitsPerSec $MaxInbound
"MaxOutbound" = Format-BitsPerSec $MaxOutbound
"Saturated" = $Saturated
}
}
}
}
$Output | Sort-Object PsComputerName, InterfaceDescription | Format-Table PsComputerName, NetAdapter, LinkSpeed, MaxInbound, MaxOutbound, Saturated
Sampel 5: Buat penyimpanan trendi lagi!
Untuk melihat tren makro, riwayat performa dipertahankan hingga 1 tahun. Sampel ini menggunakan Volume.Size.Available
seri dari LastYear
jangka waktu untuk menentukan tingkat penyimpanan yang diisi dan memperkirakan kapan akan penuh.
Cuplikan layar
Pada cuplikan layar di bawah ini, kita melihat volume Backup menambahkan sekitar 15 GB per hari:
Pada tingkat ini, ia akan mencapai kapasitasnya dalam 42 hari lagi.
Cara kerjanya
Jangka LastYear
waktu memiliki satu titik data per hari. Meskipun Anda hanya benar-benar membutuhkan dua poin untuk menyesuaikan garis tren, dalam praktiknya lebih baik membutuhkan lebih banyak, seperti 14 hari. Kami menggunakan Select-Object -Last 14
untuk menyiapkan array titik (x, y), untuk x dalam rentang [1, 14]. Dengan titik-titik ini, kami menerapkan algoritma kuadrat paling sedikit linier yang mudah untuk menemukan $A
dan $B
yang membuat parameter garis paling pas y = ax + b. Selamat datang di SMA lagi.
Membagi properti volume SizeRemaining
dengan tren (kelerengan $A
) memungkinkan kita memperkirakan secara mentah berapa hari, pada tingkat pertumbuhan penyimpanan saat ini, sampai volume penuh. Fungsi pembantu Format-Bytes
, Format-Trend
, dan Format-Days
mempercantik output.
Penting
Perkiraan ini linier dan hanya didasarkan pada 14 pengukuran harian terbaru. Ada teknik yang lebih canggih dan akurat. Harap lakukan penilaian yang baik dan jangan mengandalkan skrip ini saja untuk menentukan apakah akan berinvestasi dalam memperluas penyimpanan Anda. Ini disajikan di sini hanya untuk tujuan pendidikan.
Skrip
Berikut skripnya:
Function Format-Bytes {
Param (
$RawValue
)
$i = 0 ; $Labels = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB")
Do { $RawValue /= 1024 ; $i++ } While ( $RawValue -Gt 1024 )
# Return
[String][Math]::Round($RawValue) + " " + $Labels[$i]
}
Function Format-Trend {
Param (
$RawValue
)
If ($RawValue -Eq 0) {
"0"
}
Else {
If ($RawValue -Gt 0) {
$Sign = "+"
}
Else {
$Sign = "-"
}
# Return
$Sign + $(Format-Bytes ([Math]::Abs($RawValue))) + "/day"
}
}
Function Format-Days {
Param (
$RawValue
)
[Math]::Round($RawValue)
}
$CSV = Get-Volume | Where-Object FileSystem -Like "*CSV*"
$Output = $CSV | ForEach-Object {
$N = 14 # Require 14 days of history
$Data = $_ | Get-ClusterPerf -VolumeSeriesName "Volume.Size.Available" -TimeFrame "LastYear" | Sort-Object Time | Select-Object -Last $N
If ($Data.Length -Ge $N) {
# Last N days as (x, y) points
$PointsXY = @()
1..$N | ForEach-Object {
$PointsXY += [PsCustomObject]@{ "X" = $_ ; "Y" = $Data[$_-1].Value }
}
# Linear (y = ax + b) least squares algorithm
$MeanX = ($PointsXY | Measure-Object -Property X -Average).Average
$MeanY = ($PointsXY | Measure-Object -Property Y -Average).Average
$XX = $PointsXY | ForEach-Object { $_.X * $_.X }
$XY = $PointsXY | ForEach-Object { $_.X * $_.Y }
$SSXX = ($XX | Measure-Object -Sum).Sum - $N * $MeanX * $MeanX
$SSXY = ($XY | Measure-Object -Sum).Sum - $N * $MeanX * $MeanY
$A = ($SSXY / $SSXX)
$B = ($MeanY - $A * $MeanX)
$RawTrend = -$A # Flip to get daily increase in Used (vs decrease in Remaining)
$Trend = Format-Trend $RawTrend
If ($RawTrend -Gt 0) {
$DaysToFull = Format-Days ($_.SizeRemaining / $RawTrend)
}
Else {
$DaysToFull = "-"
}
}
Else {
$Trend = "InsufficientHistory"
$DaysToFull = "-"
}
[PsCustomObject]@{
"Volume" = $_.FileSystemLabel
"Size" = Format-Bytes ($_.Size)
"Used" = Format-Bytes ($_.Size - $_.SizeRemaining)
"Trend" = $Trend
"DaysToFull" = $DaysToFull
}
}
$Output | Format-Table
Sampel 6: Memori babi, Anda dapat menjalankan tetapi Anda tidak dapat menyembunyikan
Karena riwayat performa dikumpulkan dan disimpan secara terpusat untuk seluruh kluster, Anda tidak perlu menyatukan data dari mesin yang berbeda, tidak peduli berapa kali VM berpindah antar host. Sampel ini menggunakan VM.Memory.Assigned
seri dari LastMonth
jangka waktu untuk mengidentifikasi komputer virtual yang menggunakan memori terbanyak selama 35 hari terakhir.
Cuplikan layar
Pada cuplikan layar di bawah ini, kita melihat 10 komputer virtual teratas berdasarkan penggunaan memori bulan lalu:
Cara kerjanya
Kami mengulangi trik kami Invoke-Command
, diperkenalkan di atas, ke Get-VM
di setiap server. Kami menggunakan Measure-Object -Average
untuk mendapatkan rata-rata bulanan untuk setiap VM, lalu Sort-Object
diikuti dengan Select-Object -First 10
untuk mendapatkan leaderboard kami. (Atau mungkin itu milik kita Daftar paling dicari ?)
Skrip
Berikut skripnya:
$Output = Invoke-Command (Get-ClusterNode).Name {
Function Format-Bytes {
Param (
$RawValue
)
$i = 0 ; $Labels = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB")
Do { if( $RawValue -Gt 1024 ){ $RawValue /= 1024 ; $i++ } } While ( $RawValue -Gt 1024 )
# Return
[String][Math]::Round($RawValue) + " " + $Labels[$i]
}
Get-VM | ForEach-Object {
$Data = $_ | Get-ClusterPerf -VMSeriesName "VM.Memory.Assigned" -TimeFrame "LastMonth"
If ($Data) {
$AvgMemoryUsage = ($Data | Measure-Object -Property Value -Average).Average
[PsCustomObject]@{
"VM" = $_.Name
"AvgMemoryUsage" = Format-Bytes $AvgMemoryUsage.Value
"RawAvgMemoryUsage" = $AvgMemoryUsage.Value # For sorting...
}
}
}
}
$Output | Sort-Object RawAvgMemoryUsage -Descending | Select-Object -First 10 | Format-Table PsComputerName, VM, AvgMemoryUsage
Itu saja! Semoga sampel ini menginspirasi Anda dan membantu Anda memulai. Dengan riwayat performa Storage Spaces Direct dan cmdlet yang kuat dan ramah Get-ClusterPerf
skrip, Anda didayakan untuk bertanya - dan menjawab! – pertanyaan kompleks saat Anda mengelola dan memantau infrastruktur Windows Server 2019 Anda.