本文目录导读:

我来为你详细介绍如何编写自动启动服务并实现监控功能,涵盖Linux和Windows两个主要平台。
Linux 系统服务(Systemd)
创建服务单元文件
# /etc/systemd/system/myapp.service [Unit] Description=My Application Service After=network.target Wants=network-online.target [Service] Type=simple User=myapp Group=myapp WorkingDirectory=/opt/myapp Environment="NODE_ENV=production" ExecStart=/usr/bin/node /opt/myapp/app.js Restart=always RestartSec=10 StartLimitIntervalSec=60 StartLimitBurst=5 # 安全配置 CapabilityBoundingSet= NoNewPrivileges=true PrivateTmp=true ProtectSystem=full ProtectHome=true [Install] WantedBy=multi-user.target
监控脚本示例
#!/bin/bash
# /opt/myapp/monitor.sh
# 配置
SERVICE_NAME="myapp"
LOG_FILE="/var/log/myapp-monitor.log"
HEALTH_URL="http://localhost:3000/health"
TIMEOUT=10
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
check_service() {
# 检查进程是否存在
if ! systemctl is-active --quiet "$SERVICE_NAME"; then
log "ERROR: Service $SERVICE_NAME is not running"
return 1
fi
# 检查健康端点
if [ -n "$HEALTH_URL" ]; then
if ! curl -s --max-time "$TIMEOUT" "$HEALTH_URL" > /dev/null; then
log "WARNING: Health check failed for $SERVICE_NAME"
return 1
fi
fi
return 0
}
restart_service() {
log "Restarting $SERVICE_NAME..."
systemctl restart "$SERVICE_NAME"
sleep 5
# 验证重启成功
if check_service; then
log "Service restarted successfully"
return 0
else
log "ERROR: Service restart failed"
return 1
}
}
monitor_loop() {
local failures=0
local max_failures=3
while true; do
if ! check_service; then
((failures++))
if [ "$failures" -ge "$max_failures" ]; then
restart_service
failures=0
fi
else
failures=0
fi
sleep 30
done
}
# 主流程
case "$1" in
start)
log "Starting monitor..."
monitor_loop &
echo $! > /var/run/myapp-monitor.pid
;;
stop)
kill $(cat /var/run/myapp-monitor.pid)
;;
status)
check_service && echo "Running" || echo "Stopped"
;;
*)
echo "Usage: $0 {start|stop|status}"
;;
esac
Systemd监控服务
# /etc/systemd/system/myapp-monitor.service [Unit] Description=My Application Monitor After=network.target Requires=myapp.service [Service] Type=forking ExecStart=/opt/myapp/monitor.sh start ExecStop=/opt/myapp/monitor.sh stop PIDFile=/var/run/myapp-monitor.pid Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target
Windows 服务
C# Windows 服务示例
// MyService.cs
using System;
using System.Diagnostics;
using System.IO;
using System.ServiceProcess;
using System.Timers;
public partial class MyService : ServiceBase
{
private Timer _healthCheckTimer;
private Process _workerProcess;
private EventLog _eventLog;
public MyService()
{
InitializeComponent();
this.ServiceName = "MyAppService";
_eventLog = new EventLog();
if (!EventLog.SourceExists("MyAppService"))
{
EventLog.CreateEventSource("MyAppService", "Application");
}
_eventLog.Source = "MyAppService";
_eventLog.Log = "Application";
}
protected override void OnStart(string[] args)
{
_eventLog.WriteEntry("Service starting...", EventLogEntryType.Information);
try
{
StartWorkerProcess();
// 设置健康检查定时器
_healthCheckTimer = new Timer(30000); // 30秒
_healthCheckTimer.Elapsed += HealthCheckTimer_Elapsed;
_healthCheckTimer.AutoReset = true;
_healthCheckTimer.Start();
_eventLog.WriteEntry("Service started successfully", EventLogEntryType.Information);
}
catch (Exception ex)
{
_eventLog.WriteEntry($"Failed to start service: {ex.Message}",
EventLogEntryType.Error);
throw;
}
}
protected override void OnStop()
{
_eventLog.WriteEntry("Service stopping...", EventLogEntryType.Information);
_healthCheckTimer?.Stop();
_healthCheckTimer?.Dispose();
StopWorkerProcess();
_eventLog.WriteEntry("Service stopped", EventLogEntryType.Information);
}
private void StartWorkerProcess()
{
_workerProcess = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "node",
Arguments = "app.js",
WorkingDirectory = @"C:\MyApp",
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true
}
};
_workerProcess.Exited += WorkerProcess_Exited;
_workerProcess.EnableRaisingEvents = true;
_workerProcess.Start();
}
private void StopWorkerProcess()
{
if (_workerProcess != null && !_workerProcess.HasExited)
{
_workerProcess.Kill();
_workerProcess.WaitForExit(5000);
}
}
private void WorkerProcess_Exited(object sender, EventArgs e)
{
_eventLog.WriteEntry("Worker process exited unexpectedly",
EventLogEntryType.Warning);
// 自动重启
if (!_workerProcess.HasExited)
{
StartWorkerProcess();
}
}
private void HealthCheckTimer_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
// 健康检查逻辑
if (_workerProcess == null || _workerProcess.HasExited)
{
_eventLog.WriteEntry("Health check failed: process not running",
EventLogEntryType.Warning);
StartWorkerProcess();
}
// HTTP健康检查
using (var client = new System.Net.Http.HttpClient())
{
client.Timeout = TimeSpan.FromSeconds(10);
var response = client.GetAsync("http://localhost:3000/health")
.GetAwaiter().GetResult();
if (!response.IsSuccessStatusCode)
{
_eventLog.WriteEntry($"Health check returned {response.StatusCode}",
EventLogEntryType.Warning);
}
}
}
catch (Exception ex)
{
_eventLog.WriteEntry($"Health check failed: {ex.Message}",
EventLogEntryType.Warning);
}
}
}
安装服务
# install-service.ps1
$serviceName = "MyAppService"
$servicePath = "C:\MyApp\MyService.exe"
# 检查服务是否存在
if (Get-Service $serviceName -ErrorAction SilentlyContinue) {
Write-Host "Service already exists, removing..."
Stop-Service $serviceName -Force
& "C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe" /u $servicePath
}
# 安装服务
& "C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe" $servicePath
# 配置服务
Set-Service -Name $serviceName -StartupType Automatic
Start-Service $serviceName
Write-Host "Service installed and started successfully"
配置自动重启策略
Linux Systemd 配置
[Service] Restart=always RestartSec=10 StartLimitInterval=600 StartLimitBurst=10 # 限制内存使用 MemoryMax=500M MemoryHigh=400M # CPU限制 CPUQuota=80%
Windows Service 配置
# 配置服务恢复选项 sc failure $serviceName reset=86400 actions=restart/30000/restart/60000/restart/120000 sc.exe failureflag $serviceName 1
高级监控集成
Prometheus 指标暴露
# metrics.py
from prometheus_client import start_http_server, Gauge, Counter
import psutil
import time
class ServiceMonitor:
def __init__(self):
self.service_up = Gauge('service_up', 'Service status')
self.cpu_usage = Gauge('cpu_usage_percent', 'CPU usage')
self.memory_usage = Gauge('memory_usage_mb', 'Memory usage')
self.restart_count = Counter('restart_total', 'Total restarts')
def collect_metrics(self):
while True:
self.cpu_usage.set(psutil.cpu_percent())
self.memory_usage.set(psutil.virtual_memory().used / 1024 / 1024)
time.sleep(15)
if __name__ == '__main__':
monitor = ServiceMonitor()
start_http_server(8000)
monitor.collect_metrics()
邮件告警
# alert.py
import smtplib
from email.mime.text import MIMEText
import requests
def send_alert(service_name, error_message):
msg = MIMEText(f"""
Service: {service_name}
Status: DOWN
Time: {time.ctime()}
Error: {error_message}
""")
msg['Subject'] = f'ALERT: {service_name} is down'
msg['From'] = 'monitor@example.com'
msg['To'] = 'admin@example.com'
with smtplib.SMTP('smtp.example.com') as server:
server.login('user', 'password')
server.send_message(msg)
最佳实践建议
-
日志管理
- 使用结构化日志 (JSON格式)
- 实施日志轮转
- 集中日志收集
-
健康检查
- 实现多种检查方式 (进程、HTTP、端口)
- 设置合理的超时时间
- 避免检查本身成为新故障点
-
重启策略
- 设置最大重启次数防止循环重启
- 增加指数退避机制
- 记录重启原因和次数
-
监控指标
- CPU、内存、磁盘使用率
- 响应时间、错误率
- 连接数、请求数
-
安全考虑
- 最小权限原则运行服务
- 使用服务账户而非管理员账户
- 加密敏感配置
这个方案可以根据你的具体需求调整,确保服务稳定运行并快速响应故障,好的监控不仅要发现问题,还要帮助快速定位和解决问题。