不少做运维的朋友都遇到过这种场景公司有一批 Windows 服务器老板要求“出问题必须第一时间知道”但又不愿意上重型的商业监控软件。我自己在 Windows 环境里摸底过 n 套方案最后稳定留下来的就是 Prometheus Windows Exporter Grafana Alertmanager 这套组合。它不挑机器配置、不绑硬件、能盯 CPU / 内存 / 磁盘还能邮件告警。这套组合在国外社区里很成熟国内外网上教程却经常只讲单体安装真正把四个组件串起来、跑通告警闭环的实战文档反而少。这篇文章把它们怎么下载、怎么注册成 Windows 服务、怎么配置告警规则、怎么把邮件发出去全部梳理一遍适合刚接触 Prometheus 生态、又必须在 Windows 环境落地的读者也适合已经搭好但告警一直不生效想查缺补漏的朋友。1. 选型拆解为什么是这套组合很多人第一反应是用 Zabbix 或者干脆只看系统自带的任务管理器 / 性能监视器。Zabbix 在 Windows 上装 Agent 确实不难但它的数据模型、触发器、模板配置在大型机群下会越用越沉特别是要和现有 CMDB、自动化平台对接时API 和生态都差点意思。任务管理器只能看当前值你没法“回看三天前凌晨 CPU 为什么飙了”更没法自动发告警。这套 Prometheus 组合的价值在三点指标是时序化落盘的、告警是规则驱动的、展示是模板化的。今天部署完明天加机器、加指标、加告警代价都很低。1.1 四个组件各管哪一段Prometheus 是核心的抓取和存储引擎。它定时到各个目标地址拉取指标存进本地时序数据库同时周期性地对规则做评估命中条件就生成告警事件。Windows Exporter 跑在 Windows 主机上把 CPU、内存、磁盘、网络、服务状态等系统计数器转成 Prometheus 能识别的指标格式默认监听 9182 端口。Grafana 负责把 Prometheus 里的数据画成图给人看。Alertmanager 则是告警的“中转站”对接 Prometheus 推过来的告警事件做分组、去重、静默再通过邮件、Webhook 等方式送出去。打个比方Prometheus 像仓库管理员定时去各货架目标机器盘点库存Windows Exporter 就是货架上装的传感器负责把原始数字上报Grafana 是监控大屏Alertmanager 是值班手机上的推送通知。四者各干各的边界清晰。1.2 对比传统监控的几个关键优势这套方案相比传统 Windows 监控最实际的好处有几点部署成本低二进制丢进去就能跑不需要装数据库、不需要租云服务。Prometheus 自带本地存储单机监控几百台机器的量级完全扛得住。指标可编程比如“最近 5 分钟 CPU 平均超过 85%”这种复杂条件在 PromQL 里一行表达式就搞定Zabbix 里要折腾半天触发器。生态统一后面想加 Linux 服务器、MySQL 监控、Nginx 监控只要再接一层 Exporter 就行不用换监控体系。告警链路能自治Alertmanager 支持分组、抑制、静默节假日批量重启机器也不会被告警短信淹死。1.3 适用边界与我的建议这套组合也不是万能的。它的强项是系统资源类和中间件类指标监控属于“基础设施监控”范畴。如果你要的是 APM 那种代码链路追踪、用户请求明细分析那得单独上 APM 工具Prometheus 不适合硬扛这块。另外单机版 Prometheus 的存储扩展性有限真正上千台规模、要求长期多副本存储时需要考虑 Thanos / VictoriaMetrics 这类方案。但对绝大多数内部机房、办公室服务器、云上几台 Windows 实例的场景这套组合是性价比最高的选择。2. 部署准备与服务化封装2.1 需要下载哪些安装包部署前先把安装包准备好。Prometheus 和 Alertmanager 在官方下载页有 Windows 的 zip 包Windows Exporter 在它的 GitHub Releases 页面有 msi 和 exe 两种形态Grafana 在官方站点的 Windows 版本是 zip 包。版本我建议直接用各自当前的最新稳定版不要追 beta。实际操作中我常用这样一组Prometheus 2.4x 系列、Alertmanager 0.2x 系列、Windows Exporter 0.2x 系列、Grafana 10.x 或 11.x。这些版本之间接口兼容性很好配置写法也统一。下载时注意选 amd64 架构别下成 arm64 或者 386 的。顺带说一句Windows Exporter 有两种安装方式msi 安装会自动注册成 Windows 服务省事但我不太建议一上来就用 msi因为它默认装的路径和参数不透明后期想改采集器、调端口还得去翻注册表和服务参数。我更习惯用 exe 包自定义目录配合服务封装工具把启动参数写死这样整个监控目录可以拷到别的机器直接复用。2.2 目录规划与解压我第一次搭这套东西时吃过目录规划的亏。当时各组件随便解压到下载目录结果配置路径乱七八糟服务一重启就找不到文件。后来我固定使用一个统一根目录C:\monitoring\ ├─ prometheus\ │ ├─ prometheus.yml │ ├─ rules\ │ └─ data\ ├─ windows_exporter\ ├─ alertmanager\ │ ├─ alertmanager.yml │ └─ data\ ├─ grafana\ │ ├─ bin\ │ ├─ conf\ │ └─ data\ └─ winsw\根目录建好后把插件包解压到各自子目录。注意 prometheus 里默认会带一个 data 目录如果没带就自己建一个后面通过参数指定数据落盘路径。alertmanager 同理。2.3 用 WinSW 把进程做成 Windows 服务直接在命令行里双击 exe 也能跑起来但服务器一重启、用户一注销进程就没了。正规做法是把四个组件都注册成 Windows 服务设置开机自启、失败自动拉起。我这里用的是 WinSW 这种通用服务封装工具比 Windows 自带的 sc 命令更灵活可以指定日志目录、自动重启策略、环境变量。WinSW 的使用套路很简单把下载的 WinSW-x64.exe 分别复制成四个名字并为每个名字旁边放一个同名的 xml 配置文件。比如在 prometheus 目录里把 WinSW 复制为 prometheus-service.exe并放一个 prometheus-service.xml。启动服务时 WinSW 就会读取同名 xml 里的配置。Prometheus 的 service 配置大致这样service idprometheus/id namePrometheus/name descriptionPrometheus Metrics Server/description executableC:\monitoring\prometheus\prometheus.exe/executable arguments--config.fileC:\monitoring\prometheus\prometheus.yml --storage.tsdb.pathC:\monitoring\prometheus\data --web.listen-address:9090/arguments logpathC:\monitoring\prometheus\logs/logpath logmoderotate/logmode onfailurerestart/onfailure onfailuredelay10 sec/onfailuredelay /serviceWindows Exporter 的 service 配置类似重点是 executable 指向 windows_exporter.exearguments 里指定监听端口和启用的采集器service idwindows_exporter/id nameWindows Exporter/name descriptionWindows metrics exporter/description executableC:\monitoring\windows_exporter\windows_exporter.exe/executable arguments--web.listen-address:9182 --collectors.enabledcpu,memory,logical_disk,os,net,service,system/arguments logpathC:\monitoring\windows_exporter\logs/logpath logmoderotate/logmode onfailurerestart/onfailure onfailuredelay10 sec/onfailuredelay /service注意 Windows Exporter 不同版本对 “collectors” 参数名略有差异有的版本是 --collectors.enabled有的是 --collector.enabled最稳妥的方式是先跑一下 windows_exporter.exe --help看输出里写的哪个参数名就用哪个。Alertmanager 和 Grafana 同理。Grafana 因为是带 Web 界面的服务我用这个配置service idgrafana/id nameGrafana/name descriptionGrafana Dashboard Server/description executableC:\monitoring\grafana\bin\grafana.exe/executable argumentsserver --homepathC:\monitoring\grafana --configC:\monitoring\grafana\conf\custom.ini/arguments logpathC:\monitoring\grafana\data\log/logpath logmoderotate/logmode onfailurerestart/onfailure /service每个配置文件写好之后用管理员权限打开 PowerShell进入对应目录执行cd C:\monitoring\prometheus .\prometheus-service.exe install cd C:\monitoring\windows_exporter .\windows-exporter-service.exe install cd C:\monitoring\alertmanager .\alertmanager-service.exe install cd C:\monitoring\grafana .\grafana-service.exe install安装之后可以在“服务”管理面板里看到这四个服务或者用命令确认Get-Service prometheus, windows_exporter, alertmanager, grafana2.4 开机自启、独立账号与权限细节WinSW 默认把服务注册成 LocalSystem 账户运行这个权限对 Prometheus 抓取和 Exporter 读取系统计数器来说够用了。但如果你有严格的权限管理要求建议给监控服务单独建一个账户并授予“作为服务登录”的权限。另外要注意如果服务文件夹放在 C:\Program Files 这类需要管理员权限的路径下LocalSystem 可能受 UAC 虚拟化影响导致写文件异常放在 C:\monitoring 这种自定义目录下最省心。还有个我踩过的坑WinSW 的日志目录必须提前存在否则服务会启动失败报“路径不存在”。所以在写 xml 之前先把 logs 目录都建好。3. 核心配置拆解从抓指标到发邮件3.1 Prometheus 主配置与抓取任务Prometheus 的主配置放在 C:\monitoring\prometheus\prometheus.yml。这个文件控制三件事全局抓取频率、告警规则文件路径、Alertmanager 地址以及要抓哪些目标。我的最小可用配置如下global: scrape_interval: 15s evaluation_interval: 15s scrape_timeout: 10s rule_files: - rules/windows_alerts.yml alerting: alertmanagers: - static_configs: - targets: [localhost:9093] scrape_configs: - job_name: prometheus static_configs: - targets: [localhost:9090] - job_name: windows_exporter static_configs: - targets: - localhost:9182 relabel_configs: - source_labels: [__address__] regex: (.*):.* target_label: instance replacement: $1这里有几个细节值得解释。scrape_interval 是 Prometheus 去拉取数据的频率默认 15 秒对 CPU/内存/磁盘这类指标来说足够灵敏如果以后监控高频业务指标再单独为那个 job 改小间隔不要全局调成 5 秒否则数据量涨得很快。evaluation_interval 是规则评估频率它决定告警条件多久被检查一次一般和抓取频率保持一致。rule_files 里的 rules 目录我建议单独建别把所有规则塞进主配置后面加规则时看着舒服。relabel_configs 那段是把指标里的 instance 标签从 “localhost:9182” 变成 “localhost”图例上更好看也方便在多机器时统一命名。改完配置后在服务里重启 Prometheus 服务然后浏览器打开 http://localhost:9090/targets 如果看到 windows_exporter 的状态是 UP说明抓取链路已经通了。3.2 Windows Exporter 的采集器选择与指标确认Windows Exporter 默认采集器覆盖的指标已经很全但有些采集器默认并不开启比如 IIS、MSSQL、网络接口细节等。为了控制性能和指标量我只开启了核心需要的几类cpu、memory、logical_disk、os、net、service、system。这里特别说一下 service 采集器它能监控 Windows 服务是否存活比如 SQL Server 服务挂了也能告警多余但很有用。启动后可以直接浏览器访问http://localhost:9182/metrics你会看到一堆指标输出这就是 Exporter 提供的原始指标。我们三个核心告警主要用到四个指标监控维度关键指标含义CPUwindows_cpu_time_total各 mode 下的 CPU 累计时间modeidle 表示空闲内存windows_os_physical_memory_free_bytes物理内存剩余字节数内存windows_os_physical_memory_limit_bytes物理内存总量磁盘windows_logical_disk_free_bytes逻辑盘剩余空间磁盘windows_logical_disk_size_bytes逻辑盘总容量我去生产环境首次部署时都会先在浏览器里确认这几个指标确实存在再写规则。不同版本的 Exporter 指标名可能会有差异比如老版本可能叫 wmi_ 前缀而不是 windows_ 前缀这也是先用浏览器确认的原因。3.3 告警规则怎么写从 CPU 到磁盘告警规则文件路径我放在 C:\monitoring\prometheus\rules\windows_alerts.yml内容如下groups: - name: windows_host_alerts rules: - alert: WindowsCPUHigh expr: 100 - avg by (instance) (rate(windows_cpu_time_total{modeidle}[2m])) * 100 85 for: 5m labels: severity: warning annotations: summary: {{ $labels.instance }} CPU 使用率过高 description: {{ $labels.instance }} 的 CPU 使用率超过 85%当前值 {{ $value }}% - alert: WindowsMemoryHigh expr: (1 - windows_os_physical_memory_free_bytes / windows_os_physical_memory_limit_bytes) 0.9 for: 5m labels: severity: critical annotations: summary: {{ $labels.instance }} 内存使用率过高 description: {{ $labels.instance }} 内存使用率超过 90%当前值 {{ $value | humanizePercentage }} - alert: WindowsDiskHigh expr: (1 - windows_logical_disk_free_bytes / windows_logical_disk_size_bytes) 0.85 for: 10m labels: severity: warning annotations: summary: {{ $labels.instance }} 磁盘容量告急 description: {{ $labels.instance }} 的 {{ $labels.volume }} 盘使用率超过 85%当前值 {{ $value | humanizePercentage }}写规则时有三个地方容易搞错我说下我自己的理解。CPU 那条规则关键是理解 windows_cpu_time_total 是累计值所以必须用 rate 函数算速率。modeidle 的速率代表空闲比例100 减去它就是“非空闲”比例也就是 CPU 使用率。avg by (instance) 的作用是跨所有 CPU 核取平均不然你会看到每颗核一条告警。for: 5m 表示这个条件持续 5 分钟后才真正触发告警防止 CPU 瞬时尖峰造成误报比如编译大项目时 CPU 飙 99% 十几秒这种其实不需要打扰人。内存和磁盘的规则写法上是算“已用比例”。内存里要注意 distinguish 空闲缓存Windows 本身会把空闲内存用作缓存free_bytes 可能偏低所以阈值我设在 90%低于这个数易误报。磁盘规则里我故意把 for 设成 10 分钟因为磁盘使用率缓慢上涨不是瞬间突变等 10 分钟完全来得及还能躲开磁盘碎片整理等临时波动。改完规则后重启 Prometheus 服务然后打开 http://localhost:9090/rules 页面看到三条规则都在且状态为 OK规则就生效了。3.4 Alertmanager 邮件告警配置Alertmanager 的核心配置是 alertmanager.yml。邮件告警这里要分清楚两件事一是连接邮件服务器二是定义告警分组和接收人。我的标准配置如下global: smtp_smarthost: smtp.example.com:465 smtp_from: noreplyexample.com smtp_auth_username: noreplyexample.com smtp_auth_password: 你的授权码 smtp_require_tls: true smtp_hello: alertmanager route: receiver: ops-mail group_by: [alertname, instance] group_wait: 30s group_interval: 5m repeat_interval: 4h receivers: - name: ops-mail email_configs: - to: opsexample.com headers: subject: 【监控告警】{{ .GroupLabels.alertname }} - {{ .GroupLabels.instance }}很多人在 smtp_smarthost 上踩坑。它的格式必须是 “主机:端口”端口很关键如果邮件服务商提供 465 端口SSL 加密用 smtp_require_tls: true 是没问题的如果提供的是 587 端口STARTTLS 加密那 smtp_require_tls 一般也写成 true。但如果你直接用 25 端口连很多服务商已经禁掉明文 SMTP 了邮件会一直发不出去报 “TLS required but not negotiated” 之类的错。我的经验是优先用 465 或 587不要碰 25。smtp_auth_username 和 smtp_from 通常要一致或者至少是同一域名下被授权的发件人。很多服务商会拒绝“发件人和账号不一致”的邮件提示 “Sender is not allowed”。密码字段现在很多服务商不让你填登录密码得在邮箱后台生成“客户端专用授权码”这个能大幅降低账号被盗风险生产环境一定要养成这个习惯。route 段里的 group_wait 是等待 30 秒把同组告警攒一起再发主要是避免“CPU 高、内存高、磁盘高”三个通知在 30 秒内连续轰炸收件箱而是合并成一封。repeat_interval 是同一告警恢复前多久重复提醒一次我设成 4 小时避免运维半夜被同一封邮件吵醒。3.5 Grafana 数据源与可视化配置Grafana 装好后浏览器访问 http://localhost:3000 默认账号密码是 admin / admin首次登录会强制改密码。进去先配数据源左侧菜单点 Connections - Data sources - Add data source选 PrometheusURL 填 http://localhost:9090 其他默认即可然后点 Save test出现绿色成功提示就说明连上了。光有数据源还不够得导入仪表板。Grafana 官网有大量现成的仪表板模板我常用的是 ID 为 13605 的 Windows Exporter Dashboard这套仪表板把 CPU、内存、磁盘、网络、服务状态都画好了导入后基本不用改。操作路径左侧 Dashboards - New - Import输入仪表板 ID 13605数据源选择刚才创建的 Prometheus就能看到一排排监控面板了。这里有个小技巧如果导入后部分面板显示 No Data基本是仪表板里选择的指标名和你的 Exporter 版本指标名不匹配。老版本面板用 wmi_ 前缀指标新版本都改成 windows_ 前缀最简单的办法是去面板设置里把查询条件里的 wmi_ 批量替换成 windows_。我在一次升级 Exporter 后碰到过替换完就正常了。4. 端到端联调从启动到收到告警邮件4.1 按顺序启动并检查服务状态配置都写完后重启四个服务。启动顺序不强制但我习惯按依赖关系来先启动 Windows Exporter 和 Prometheus再启动 Alertmanager最后启动 Grafana。这样带 Web 界面的组件启动时不会因为数据源没起来而报错。Restart-Service windows_exporter, prometheus, alertmanager, grafana Get-Service windows_exporter, prometheus, alertmanager, grafana | Format-Table Name, Status如果有一个服务没起来去看对应的日志。Prometheus 默认日志在服务配置的 logpath 里或者直接用命令看sc.exe queryex prometheus这一条命令能查到服务的 PID 和最近退出码排查启动失败特别有用。4.2 验证指标抓取打开 Prometheus 的 Targets 页面确认所有 job 状态都是 UP。接着去 Graph 页面执行几条查询确认数据正常rate(windows_cpu_time_total{modeidle}[2m])如果画出来是一条接近 1 的平缓曲线说明 CPU 数据正常。再查windows_os_physical_memory_free_bytes windows_logical_disk_free_bytes这两个查询能看到当前物理内存剩余和磁盘剩余确认没有 NaN 或者 0。4.3 真实触发一次告警验证邮件只看规则状态 OK 还不算数必须验证邮件真的能发出去。我把阈值临时调低再触发比直接等生产故障更可控。比如临时把磁盘规则改成expr: (1 - windows_logical_disk_free_bytes / windows_logical_disk_size_bytes) 0.1这样如果 C 盘剩余空间低于 90% 就会触发告警对这个时代的大部分 Windows 服务器来说C 盘低于 90% 其实很常见。为了让告警更加可控我一般在测试机上执行# 制作一个占空间的测试文件 fsutil file createnew C:\test_alert.tmp 5368709120这个命令会在 C 盘创建一个 5GB 的空文件注意 NTFS 下建议 fsutil因为它创建的是稀疏文件占的是逻辑空间不是立即写物理扇区速度极快。创建后等待规则评估周期最长 1 分钟Prometheus 就会触发 WindowsDiskHigh 告警随后 Alertmanager 按 30 秒的 group_wait 发送邮件。测试完成后删掉文件Remove-Item C:\test_alert.tmp再等几分钟告警自动恢复还会收到一封“告警已恢复”的邮件。能收到恢复邮件说明整个通知链路是通的。我见过不少环境只能发触发邮件恢复邮件发不出来原因多半是模板模板里用了 $labels.xxx 但是恢复时没有这个标签导致模板渲染失败这种问题在 Alertmanager 日志里能看到 ERROR。4.4 告警重复与自动恢复机制这里顺便把 Alertmanager 的重复通知机制说透。一条告警进入 Alertmanager 后它先按 route 里的 group_by 分组group_wait 期间把同一组的告警聚合group_interval 控制每组内新告警合并的频率。如果同一告警已经通知过在没有恢复的情况下要等到 repeat_interval 到期才会再次提醒。所以测试完一定要等恢复邮件否则 4 小时后又来一封容易把人搞烦。5. 生产环境常见问题与排查实录5.1 服务起不来或开机后被杀这是新手上路最常遇见的。服务起不来时先分清是哪层问题是 WinSW 本身没起来还是里面的 exe 报错。WinSW 的 xml 配置文件里如果 executable 路径写错服务会秒退。此时打开“事件查看器 - Windows 日志 - 系统”搜 WinSW 关键词通常能看到明确错误信息。另一个隐蔽问题我遇到过服务设置了失败重启但 Prometheus 本身因为数据目录损坏反复崩溃WinSW 每 10 秒拉一次每次拉起来后几秒又崩。这种情况别瞎重启先看 Prometheus 日志里关于 TSDB 的报错必要时把 data 目录里 WAL 文件夹备份后删掉重建。5.2 指标一直 No DataNo Data 的常见原因有三个第一Prometheus 没抓到目标去 Targets 页面看状态是不是 DOWN第二Exporter 采集器未启用导致指标根本没暴露出来——这可以在 /metrics 页面直接搜关键词确认第三指标名写错老版本用 wmi_ 前缀新版本用 windows_ 前缀混用必然查不到。我把排查顺序固定为先看 Targets 状态再在 Prometheus Graph 里尝试用 {jobwindows_exporter} 这种宽松标签查最后才怀疑规则本身。5.3 告警一直 Pending 不触发Prometheus 的告警状态分 Inactive、Pending、Firing。Pending 意味着条件已经满足但还没满足 for 参数要求的持续时间。如果你等了很久还是 Pending说明条件时好时坏中间有某轮评估低于阈值计时被重置了。这时候调低阈值或者缩短 for 时间再观察。另外还要确认 evaluation_interval 和 for 的关系for: 5m 且 evaluation 15s 的话至少需要连续 20 轮评估都命中才触发这是正常的。5.4 SMTP 邮件常见的几个坑我列一个高频问题对查表照着排查基本能解决现象原因处理方式邮件发不出日志报 connection refusedsmtp_smarthost 端口写错或服务器禁止外发换 465/587 端口确认服务商开放 SMTP日志报 550 或 535认证失败用授权码而非登录密码确认账号和发件人一致日志报 TLS handshake failed端口与 TLS 方式不匹配465 用 ssl 模式587 用 starttls按服务商文档调整 smtp_require_tls能发触发邮件但恢复邮件为空模板引用了恢复时没有的标签检查 subject/description 里的模板变量同一告警反复发很多封repeat_interval 太小生产环境设置成 4h 以上中文变成乱码邮件编码问题在 header 里加 Content-Type: text/plain; charsetUTF-85.5 告警轰炸与静默策略生产环境最烦的不是服务挂了没告警而是故障期间告警刷屏。比如某台机器磁盘读满了触发了磁盘、服务异常、日志写不进去三个告警收件箱瞬间进来 6 封邮件真实的故障反而被淹没。解决办法是利用 Alertmanager 的分组和抑制route 里把 group_by 设成 alertname 和 instance相当于同一个机器同类型告警合并如果还要更细可以配 inhibit_rules让 severity 为 critical 的告警抑制同实例上 severity 为 warning 的告警。这个思路在维护窗口尤其好用比如凌晨割接提前在 Alertmanager 里设一个静默指定机器或标签窗口内不打扰任何人。5.6 存储与性能优化细节Prometheus 默认把数据存在本地Windows 下存储时间序列文件时会占用不少磁盘。默认 15 秒抓取、保留 15 天的话一台几百个指标的被监控机器磁盘占用通常在几 GB 到十几 GB 之间。如果监控对象很多我建议调整两个参数一是把 --storage.tsdb.retention.time 设置成实际需要的时间跨度比如 30d二是给 Prometheus 服务单独分配一个磁盘分区避免监控数据和业务数据挤在一起。Windows 下还有个小细节如果服务装在 C 盘而 Prometheus 的 data 目录在 C 盘磁盘告警时监控本身也可能中招我就把 data 指向另一个物理盘逻辑盘也更好统计。最后分享一个我连续踩过坑才总结出来的习惯改任何配置前先备份原文件启动服务前先用命令行手动执行一遍 exe确认参数和配置没有明显错误。像 Prometheus、Alertmanager 这类配置如果写错了 yaml进程会直接闪退或者发配置校验错误手动执行能立刻看到报错比在服务里反复重启排查高效得多。我自己部署这套监控栈少说有几十次了但只要严格按照“先手动验证、再注册服务、最后改配置”的顺序来基本一次就能跑通。这套体系搭好之后后续再想加 Linux 服务器、MySQL、Redis等于往 scrape_configs 里添一行的事收益会越来越大。