PHP项目值班与告警响应

wen PHP项目 6

本文目录导读:

PHP项目值班与告警响应

  1. 监控层(前置发现)
  2. 告警层(分级响应)
  3. 响应层(标准流程)
  4. 复盘层(持续改进)
  5. 工具链推荐
  6. 值班制度关键点

针对PHP项目的值班与告警响应体系设计,需要覆盖监控层告警层响应层以及复盘层,以下是完整的实施方案:


监控层(前置发现)

应用层监控(PHP特有)

// 使用 PHP-FPM status page 监控进程健康
// 配置 nginx 访问 /status 页面
location ~ ^/(status|ping)$ {
    include fastcgi_params;
    fastcgi_pass unix:/var/run/php-fpm.sock;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
// 自定义健康检查端点
Route::get('/health', function() {
    try {
        // 检查数据库连接
        DB::connection()->getPdo();
        // 检查 Redis
        Redis::ping();
        // 检查队列(如果使用)
        Queue::size();
        return response()->json(['status' => 'healthy'], 200);
    } catch (\Exception $e) {
        Log::critical('Health check failed', ['error' => $e->getMessage()]);
        return response()->json(['status' => 'unhealthy', 'error' => $e->getMessage()], 500);
    }
});

关键指标采集(Prometheus + 自定义Exporter)

// 安装 prometheus_pushgateway 依赖
// composer require promphp/prometheus_client_php
// 在中间件中采集指标
namespace App\Http\Middleware;
class MetricsMiddleware {
    public function handle($request, \Closure $next) {
        $start = microtime(true);
        $response = $next($request);
        $duration = microtime(true) - $start;
        $statusCode = $response->status();
        // 记录请求数
        $counter = Counter::namespace('app')->name('http_requests_total')
            ->help('Total HTTP requests')
            ->label('method', 'route', 'status')
            ->incBy(1, [$request->method(), $request->path(), $statusCode]);
        // 记录请求耗时
        $histogram = Histogram::namespace('app')->name('http_request_duration_seconds')
            ->help('HTTP request duration')
            ->label('method', 'route')
            ->observe($duration, [$request->method(), $request->path()]);
        // 记录慢查询
        if ($duration > 1.0) {
            $counter->inc(1, ['method' => 'slow_request', 'route' => $request->path()]);
        }
        return $response;
    }
}

基础设施监控

# docker-compose 监控栈
version: '3.8'
services:
  prometheus:
    image: prom/prometheus
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
  grafana:
    image: grafana/grafana
    ports:
      - "3000:3000"
  node_exporter:
    image: prom/node-exporter
    network_mode: "host"
  php_fpm_exporter:
    image: bakins/php-fpm-exporter
    environment:
      - PHP_FPM_SCRAPE_URI=http://php-app/status

告警层(分级响应)

告警等级定义

等级 颜色 响应时间 示例场景
P0 致命 🔴 红色 立即响应 数据库宕机、500错误率>5%、全线崩溃
P1 严重 🟠 橙色 5分钟内 支付接口超时、核心功能不可用、慢查询>3秒
P2 警告 🟡 黄色 30分钟内 错误率上升、磁盘使用>80%、PHP进程飚升
P3 提示 🔵 蓝色 工作日内 缓存命中率下降、代码覆盖率下降

告警规则配置(Prometheus Alertmanager)

groups:
  - name: php_app_alerts
    interval: 30s
    rules:
      # P0: 应用完全宕机
      - alert: ApplicationDown
        expr: up{job="php-app"} == 0
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "PHP应用不可访问"
          description: "实例 {{ $labels.instance }} 已下线超过1分钟"
      # P1: 高错误率
      - alert: HighErrorRate
        expr: rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m]) > 0.05
        for: 2m
        labels:
          severity: major
        annotations:
          summary: "5XX错误率超过5%"
          description: "当前错误率 {{ $value | humanizePercentage }}"
      # P2: PHP进程异常
      - alert: PhpFpmBusy
        expr: php_fpm_active_processes / php_fpm_max_children > 0.8
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "PHP-FPM进程使用率超过80%"
          description: "当前使用率 {{ $value | humanizePercentage }}"

告警通知渠道

graph LR
    A[告警事件] --> B{自动决策}
    B -->|P0/P1| C[电话/短信]
    B -->|P2| D[企业微信/Slack]
    B -->|P3| E[邮件/工单系统]
    C --> F[值班负责人]
    D --> G[技术群组]
    E --> H[项目协同]

企业微信机器人配置示例:

// 发送告警到企业微信群
class WeWorkAlert {
    public static function send($level, $message) {
        $webhook = config("alert.webhook.{$level}");
        $payload = [
            'msgtype' => 'markdown',
            'markdown' => [
                'content' => "## 🚨 {$level} 告警\n> **项目**: PHP Core\n> **时间**: " . now() . "\n> **详情**: {$message}"
            ]
        ];
        Http::post($webhook, $payload);
    }
}

响应层(标准流程)

值班安排(轮值表)

// 使用 oncall 轮值系统
// 使用 PagerDuty / Opsgenie 或自建系统
class OnCallSchedule {
    public static function getCurrentOnCall() {
        $schedule = [
            ['name' => '张三', 'phone' => '138xxxx', 'start' => '2024-01-01', 'end' => '2024-01-07'],
            ['name' => '李四', 'phone' => '139xxxx', 'start' => '2024-01-08', 'end' => '2024-01-14'],
        ];
        $now = now();
        return collect($schedule)->first(function($shift) use ($now) {
            return $now->between($shift['start'], $shift['end']);
        });
    }
}

故障响应 SOP(标准操作流程)

P0 级别响应流程:

确认告警(2分钟内)
   - 回复告警通知,表明已接手
   - 创建故障工单(如 Jira)
2. 初步诊断(5分钟内)
   - 检查 Grafana 仪表盘
   - 查看 PHP 错误日志
   - 检查服务器负载
3. 止血操作(15分钟内)
   - 重启 PHP-FPM:sudo systemctl restart php8.1-fpm
   - 回滚最近部署:git revert HEAD
   - 扩容服务:kubectl scale deployment php-app --replicas=5
4. 根本原因分析(1小时内)
   - 查看慢查询日志
   - 检查最近代码变更
   - 分析 Xdebug 性能追踪
5. 修复与验证
   - 部署修复代码
   - 持续监控15分钟
   - 更新故障报告

常见故障自动恢复脚本

# auto_heal.sh - 自动恢复脚本
#!/bin/bash
# 检查 PHP-FPM 状态
if ! pgrep php-fpm > /dev/null; then
    echo "[$(date)] PHP-FPM 已崩溃,尝试重启..."
    systemctl restart php8.1-fpm
    sleep 5
    if pgrep php-fpm > /dev/null; then
        echo "[$(date)] 重启成功"
        # 发送恢复通知
        curl -X POST -H "Content-Type: application/json" \
            -d '{"msgtype":"text","text":{"content":"PHP-FPM 已自动恢复"}}' \
            $WEBHOOK_URL
    else
        echo "[$(date)] 重启失败,需要人工介入"
        # 升级告警
        echo "PHP-FPM 自动恢复失败" | mail -s "P0 告警" oncall@company.com
    fi
fi
# 检查磁盘空间
DISK_USAGE=$(df / | awk '{print $5}' | tail -1 | sed 's/%//')
if [ $DISK_USAGE -gt 90 ]; then
    echo "[$(date)] 磁盘使用率超过90%,清理临时文件..."
    find /tmp -type f -atime +7 -delete
    find /var/log/php -type f -mtime +30 -delete
    # 如果还是不够,扩展磁盘(云环境)
    # aws ec2 modify-volume --volume-id vol-xxx --size +10
fi

复盘层(持续改进)

故障报告模板(Postmortem)

# 故障报告:2024-01-15 数据库连接风暴
## 严重等级
P1 (严重)
## 时间线
- 14:30 告警触发(错误率>5%)
- 14:32 值班人员确认
- 14:35 发现数据库连接池耗尽
- 14:40 增加连接池大小(临时止血)
- 15:20 找到根本原因(慢查询未优化)
- 15:45 优化SQL并部署
- 16:00 确认恢复
## 根因分析
- 直接原因:`SELECT * FROM orders WHERE status = 'pending'` 未加索引,导致全表扫描
- 根本原因:代码审查不严格,未检查SQL执行计划
- 系统原因:缺少慢查询告警
## 改进措施
- [ ] 添加慢查询监控(阈值:500ms)
- [ ] 设置最大连接池告警(使用率>70%)
- [ ] 代码审查增加SQL检查步骤
- [ ] 建立数据库索引规范文档
## 负责人
- 值班:张三
- 修复:李四
- 复盘:王五

值班统计看板

-- 统计值班效果
SELECT 
    oncall_person,
    COUNT(*) as incidents,
    AVG(response_time) as avg_response,
    AVG(resolution_time) as avg_resolution,
    COUNT(CASE WHEN severity = 'P0' THEN 1 END) as p0_count
FROM incident_reports
WHERE created_at > DATE_SUB(NOW(), INTERVAL 30 DAY)
GROUP BY oncall_person;

值班交接本

# 值班交接记录示例
## 当前状态
- PHP版本:8.1.27
- 当前在线人数:2,345
- Redis内存使用:65%
- 告警静默规则:server-03 正在维护(维护窗口 22:00-02:00)
## 进行中的问题
1. #INC-456 - 用户上传图片偶尔失败(PHP内存限制问题,已分配开发修复中)
## 最近变更
- 2024-01-15 14:30 部署了 v2.3.1 (修复支付回调死循环)
- 2024-01-15 16:00 数据库添加了 orders.status 索引
## 重点关注
- 新支付渠道(Stripe)3D验证在部分国家失败
- 日志收集器磁盘剩余 15%,明天需要清理
## 值班人员
- 交班:张三 (138xxxx)
- 接班:李四 (139xxxx)

工具链推荐

开源方案

工具 用途 部署方式
Prometheus + Grafana 监控 + 可视化 Docker
Alertmanager 告警路由 自带
PagerDuty 值班调度 SaaS
Sentry PHP错误追踪 开源版
OpenTelemetry 链路追踪 代码集成

付费方案(推荐)

服务 优势 价格
Datadog 全栈监控 按主机
New Relic APM深度 按用量
Opsgenie 告警管理 按用户
Better Uptime 简单易用 低门槛

值班制度关键点

  1. 值班交接仪式

    • 每天17:00 值班交接群内通报
    • 必须阅读前一天的故障报告
    • 新值班人员需要确认告警静默规则
  2. 告警疲劳防护

    • 设置告警静默期(相同问题1小时内不重复告警)
    • 阈值动态调整(根据业务低谷/高峰期调整灵敏度)
    • 3天内未处理的告警自动升级
  3. 新人培养

    • 入职第1周:跟随值班(只观察不操作)
    • 第2-3周:处理P3告警
    • 第4周:独立值班(需师傅背书)
  4. 奖惩制度

    • 避免P0事故:奖励 $500
    • 发现并修复潜在问题:$100
    • 值班期间未及时响应:扣除当天补贴

这个体系涵盖了从监控发现到最终复盘优化的完整闭环,能够有效保障PHP项目的稳定运行,关键是要持续迭代——每次故障都是改进的机会。

抱歉,评论功能暂时关闭!