运维工程师最头疼的莫过于半夜被报警电话吵醒——某台服务器的Windows服务又崩溃了。传统的人工巡检方式存在三大致命缺陷:
我团队管理的300+台Windows服务器曾因此每月产生20+次紧急故障处理。直到开发出这套自动化方案后,服务可用性从99.2%提升至99.95%,夜间告警量下降92%。下面分享具体实现方案。
| 组件类型 | 技术选型 | 选择理由 |
|---|---|---|
| 状态检测 | PowerShell + WMI | 原生支持Windows服务管理,无需额外依赖 |
| 任务调度 | Windows任务计划程序 | 系统内置组件,稳定性远超第三方调度工具 |
| 告警通知 | SMTP+邮件API | 兼容企业现有邮件系统,支持分级告警 |
| 日志记录 | EventLog + CSV日志 | 双重日志保障,既方便实时查询又便于长期统计分析 |
| 自愈策略 | 预定义PowerShell脚本 | 针对不同服务类型定制恢复逻辑,如IIS采用"停止→清理→重启"三步恢复法 |
mermaid复制graph TD
A[定时触发] --> B[服务状态检测]
B --> C{状态正常?}
C -->|是| D[记录日志]
C -->|否| E[执行自愈脚本]
E --> F{自愈成功?}
F -->|是| G[发送恢复通知]
F -->|否| H[升级告警]
实际部署时需要特别注意:检测间隔建议设置为5-10分钟,过于频繁会影响服务器性能,间隔太长则失去监控意义
powershell复制# 服务检测函数
function Check-ServiceHealth {
param(
[string]$serviceName,
[int]$retryCount = 3
)
$service = Get-WmiObject -Class Win32_Service -Filter "Name='$serviceName'"
if ($service.State -eq 'Running') {
return $true
}
# 异常状态重试机制
for ($i = 1; $i -le $retryCount; $i++) {
Start-Sleep -Seconds 5
$service = Get-WmiObject -Class Win32_Service -Filter "Name='$serviceName'"
if ($service.State -eq 'Running') {
return $true
}
}
return $false
}
powershell复制# 告警分级处理
function Send-Alert {
param(
[string]$serviceName,
[string]$status,
[int]$level = 1
)
$mailParams = @{
From = 'monitor@company.com'
To = if ($level -ge 2) {'ops-team@company.com'} else {'dev-team@company.com'}
Subject = "[$level]服务异常告警 - $serviceName"
Body = "服务 $serviceName 状态异常:$status"
SmtpServer = 'smtp.company.com'
}
Send-MailMessage @mailParams
# 关键业务服务触发电话告警
if ($level -eq 3 -and $criticalServices.Contains($serviceName)) {
Invoke-WebRequest -Uri "http://alert-api/call?service=$serviceName" -Method POST
}
}
| 故障类型 | 自愈策略 | 成功率 | 备注 |
|---|---|---|---|
| 服务未运行 | 自动启动服务 | 98% | 适用于普通应用服务 |
| 服务假死 | 强制终止进程后重启 | 95% | 需要配置进程名匹配规则 |
| 端口占用 | 释放端口后重启 | 90% | 需提前配置允许操作的端口范围 |
| 内存泄漏 | 重启服务+发送详细诊断报告 | 100% | 同时触发根因分析流程 |
| 依赖服务异常 | 级联重启依赖服务 | 85% | 需要准确配置服务依赖关系 |
powershell复制# IIS服务专用恢复脚本
function Repair-IISService {
param(
[string]$serviceName = 'W3SVC'
)
try {
# 第一步:停止相关进程
Get-Process -Name w3wp -ErrorAction SilentlyContinue | Stop-Process -Force
# 第二步:清理临时文件
Remove-Item "$env:TEMP\iis_*" -Recurse -Force -ErrorAction SilentlyContinue
# 第三步:完整重启服务
Restart-Service -Name $serviceName -Force
# 验证恢复结果
Start-Sleep -Seconds 10
if ((Get-Service -Name $serviceName).Status -eq 'Running') {
return $true
}
}
catch {
Write-EventLog -LogName Application -Source "AutoHeal" -EntryType Error -EventId 500 -Message $_.Exception.Message
}
return $false
}
执行账户:建议使用域账户并授予以下权限
脚本执行策略:
powershell复制Set-ExecutionPolicy RemoteSigned -Scope LocalMachine -Force
任务计划配置:
建议搭配Prometheus+Grafana实现可视化监控:
yaml复制# prometheus.yml 配置示例
scrape_configs:
- job_name: 'windows_services'
metrics_path: '/metrics'
static_configs:
- targets: ['windows-exporter:9100']
关键监控指标建议:
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 脚本执行无反应 | 执行策略限制 | 检查ExecutionPolicy设置 |
| 服务反复异常 | 资源不足 | 增加内存/CPU监控 |
| 邮件告警未发送 | SMTP认证失败 | 检查465/587端口和TLS配置 |
| 自愈操作无效 | 权限不足 | 验证执行账户的本地管理员权限 |
| 日志记录缺失 | 事件日志空间不足 | 调整事件日志存储设置 |
批量检测优化:
powershell复制# 使用Get-CimInstance替代Get-WmiObject提升性能
$services = Get-CimInstance -ClassName Win32_Service -Filter "State != 'Running'"
并行检测机制:
powershell复制$services | ForEach-Object -Parallel {
$result = Check-ServiceHealth -ServiceName $_.Name
#...后续处理
} -ThrottleLimit 5
冷热路径分离:
这套系统上线后,我们团队的值班模式从"5x8小时待命"变为"真正的工作日作息",最重要的是再也不会在凌晨3点被报警电话惊醒。对于想要实现类似自动化运维的同行,建议先从非核心业务服务开始试点,逐步完善自愈策略库。