可以在生产服务器上运行 perfmon 吗?为什么?

Bil*_*zke 30 performance perfmon performance-tuning sql-server

还是应该将 perfmon 限制为具有模拟生产活动的负载测试的 Dev/QA 服务器?

我想运行 perfmon 两天(就像 Sql Server master Brent Ozar 建议的那样)来全面了解我的 web 应用程序的数据库性能。

Rem*_*anu 27

SQL Server 和大多数其他产品始终生成计数器,无论是否有侦听器(忽略 -x 启动选项)。计数器跟踪对被监控的应用程序是完全透明的。有一个共享内存区域,受监控的应用程序在该区域上写入数据,并且监控会话以指定的时间间隔从中读取原始值。因此,与监控相关的唯一成本是监控过程的成本和将采样值写入磁盘的成本。选择合适的收集间隔(我通常选择 15 秒)和中等数量的计数器(50-100),并写入二进制文件格式通常不会对受监控的系统产生影响。

但我建议不要使用 Perfmon(如在 perfmon.exe 中)。而是让自己熟悉 logman.exe,请参阅Logman.exe、Relog.exe 和 Typeperf.exe 工具的说明。这样您就不会将收集会话与您的会话联系起来。Logman 是一个命令行工具,可用于脚本和计划作业以启动和停止收集会话。


Hol*_*tic 15

在生产机器上运行 perfmon 没有错。比较低调,可以为你收集到很多不错的信息。如果您不在生产服务器上运行一些分析,您将如何准确地模拟生产负载?来自 Brent Ozar 在您自己的链接中:

让 Perfmon 运行一两天以收集服务器活动的良好基线。它对被监控的 SQL Server 没有那么大的侵入性,深入的结果将带来回报。我们拥有的数据越多,我们就可以更好地分析 Perfmon 结果。

我已经在许多生产 Exchange 机器上运行了 perfmon,没有任何不利影响。

  • 同意 - 运行 Perfmon 没有开销。另一个答案建议运行 Profiler 而不是 Perfmon,但运行 Profiler 会带来非常实际的开销。我已经看到 Profiler 跟踪会在跟踪框无法跟上负载的情况下关闭生产服务器,或者当增加的负载将生产服务器推到边缘时。 (5认同)

Nat*_*ley 8

自从我在播客上听过Clint Huffman,他编写了PAL一个用于分析 Perfmon 日志的实用程序。我已经在我们所有的生产应用服务器上设置了我所说的 Flight Recorder。这种做法对于诊断问题和监控趋势非常有用。

下面是我用来设置自动启动 Perfmon 收集器和日志清除的脚本。如果需要,可以向它提供一个列出要收集的性能计数器的文件(每行一个)或一个 PAL 阈值 XML 文件。我喜欢使用 PAL 阈值文件。

<#
Install-FlightRecorder.ps1
.SYNOPSIS
Installs or sets up the pieces necessary to create PerfMon Collector 
snapshots, one a minute, to a file located in C:\FlightRecorder.

.DESCRIPTION
Installs or sets up the pieces necessary to create PerfMon Collector 
snapshots, one a minute, to a file located in C:\FlightRecorder.

.PARAMETER Path
File listing performance counters to collect, one per line. 
Or a PAL Threshold XML file.

#>
[CmdletBinding()]
param (
    [string]$Path
)

#Requires -RunAsAdministrator
$ScriptDir = { Split-Path $MyInvocation.ScriptName –Parent }
$DeleteTempFile = $False

function Main {
    if (-not $Path) { $Path = DefaultFile $Path }
    if (-not (Test-Path $Path)) {
        Write-Warning "Path does not exist or is inaccessable: $Path"
        Exit 1
    }
    if ($Path -like '*.xml') { $Path = PALFile $Path }

    Install-FlightRecorder
    if ($Path.startswith($env:TEMP)) {Remove-Item $Path}
    Write-Verbose 'Installation Successful.'
}

function Install-FlightRecorder {
    Write-Verbose 'Setting up the Flight Recorder.'
    if (-not (Test-Path c:\FlightRecorder\)) {
        mkdir c:\FlightRecorder | out-null 
    }
    if ((LOGMAN query) -match 'FlightRecorder') {
        Write-Verbose 'Removing former FlightRecorder PerfMon Collector.'
        LOGMAN stop FlightRecorder | out-null
        LOGMAN delete FlightRecorder | Write-Verbose
    }
    Write-Verbose 'Creating FlightRecorder PerfMon Collector.'
    LOGMAN create counter FlightRecorder -o "C:\FlightRecorder\FlightRecorder_$env:computername" -cf $Path -v mmddhhmm -si 00:01:00 -f bin | Write-Verbose
    SCHTASKS /Create /TN FlightRecorder-Nightly /F /SC DAILY /ST 00:00 /RU SYSTEM /TR 'powershell.exe -command LOGMAN stop FlightRecorder; LOGMAN start FlightRecorder; dir c:\FlightRecorder\*.blg |?{ $_.LastWriteTime -lt (Get-Date).AddDays(-3)} | del' | Write-Verbose
    SCHTASKS /Create /TN FlightRecorder-Startup /F /SC ONSTART /RU SYSTEM /TR "LOGMAN start FlightRecorder" | Write-Verbose
    SCHTASKS /Run /TN FlightRecorder-Startup | Write-Verbose
}

function DefaultFile {
    Write-Warning 'Counter or PAL file not specified, using default configuration.'
    $DeleteTempFile = $True
    $Path = [System.IO.Path]::GetTempFileName()
    Set-Content -Encoding ASCII $Path @'
\LogicalDisk(*)\Avg. Disk sec/Read
\LogicalDisk(*)\Avg. Disk sec/Write
\LogicalDisk(*)\Disk Transfers/sec
\LogicalDisk(C:)\Free Megabytes
\Memory\% Committed Bytes In Use
\Memory\Available MBytes
\Memory\Committed Bytes
\Memory\Free System Page Table Entries
\Memory\Pages Input/sec
\Memory\Pages/sec
\Memory\Pool Nonpaged Bytes
\Memory\Pool Paged Bytes
\Memory\System Cache Resident Bytes
\Network Interface(*)\Bytes Total/sec
\Network Interface(*)\Output Queue Length
\Paging File(*)\% Usage
\Paging File(*)\% Usage Peak
\PhysicalDisk(*)\Avg. Disk sec/Read
\PhysicalDisk(*)\Avg. Disk sec/Write
\Process(_Total)\Handle Count
\Process(_Total)\Private Bytes
\Process(_Total)\Thread Count
\Process(_Total)\Working Set
\Processor(*)\% Interrupt Time
\Processor(*)\% Privileged Time
\Processor(*)\% Processor Time
\System\Context Switches/sec
\System\Processor Queue Length
'@
    $Path
}

function PalFile {
    $DeleteTempFile = $True
    $InputPath = $Path
    $Path = [System.IO.Path]::GetTempFileName()
    $filesRead = @()
    Read-PalFile $InputPath | Select -Unique | sort | Set-Content -Encoding ASCII $Path
    $Path
}

$script:filesRead =@()
function Read-PalFile ([string]$path) {
    if (-not (Test-Path $path)) {
        Write-Warning "PAL Threshold file not found: $path"
        return
    }
    if ($script:filesRead -contains $path) {return}
    $script:filesRead += @($path)
    Write-Verbose "Reading PAL Threshold file: $path"
    $xml = [XML](Get-Content $path)
    $xml.SelectNodes('//DATASOURCE[@TYPE="CounterLog"]') | select -expand EXPRESSIONPATH
    $xml.SelectNodes('//INHERITANCE/@FILEPATH') | select -expand '#text' | where {$_ } | ForEach {
        $newpath = Join-Path (Split-Path -parent $path) $_
        Write-Debug "Inheritance file: $newpath"
        Read-PalFile $newpath
    }
}

. Main
Run Code Online (Sandbox Code Playgroud)