PHP项目告警静默如何维护时段屏蔽通知

wen PHP项目 31

本文目录导读:

PHP项目告警静默如何维护时段屏蔽通知

  1. 核心思路
  2. 方案一:基于配置文件(简单、适用单机/小项目)
  3. 方案二:基于数据库/Redis(灵活、支持动态配置)
  4. 方案三:使用任务调度 + 开关(适合整站维护)
  5. 高级:基于告警聚合(De-duplication + Silence)
  6. 最佳实践建议
  7. 简单封装示例(即时可用)

在 PHP 项目中实现告警静默(时段屏蔽通知),通常是为了在维护窗口、非工作时间或已知故障期间避免不必要的告警骚扰,以下是几种常见的架构设计与实现方案,你可以根据项目复杂度选择。


核心思路

  1. 配置中心:定义静默规则(时间范围、周期、匹配条件)。
  2. 过滤器/中间件:在告警触发点(发送通知前)检查规则。
  3. 执行:如果匹配,则丢弃告警或标记为静默。

基于配置文件(简单、适用单机/小项目)

直接在项目配置中定义静默时段,使用数组或 .env 控制。

示例配置 (config/mute.php)

return [
    'enabled' => true,
    'rules' => [
        [
            'start' => '02:00',
            'end'   => '05:00',
            'days'  => ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], // 工作日
            'match' => null, // null 表示匹配所有告警,或指定告警类名
        ],
        [
            'start' => '00:00',
            'end'   => '23:59',
            'days'  => ['Sat', 'Sun'],
            'match' => 'critical', // 仅静默 critical 级别的告警
        ],
    ],
];

核心检查逻辑

class AlertMuteService
{
    public function shouldMute(string $alert, string $level = null): bool
    {
        $config = config('mute');
        if (!$config['enabled']) {
            return false;
        }
        $now = Carbon::now();
        $currentDay = $now->shortDayName; // Mon, Tue...
        $currentTime = $now->format('H:i');
        foreach ($config['rules'] as $rule) {
            // 1. 检查日期
            if (!in_array($currentDay, $rule['days'] ?? [])) {
                continue;
            }
            // 2. 检查时间区间
            if ($currentTime < $rule['start'] || $currentTime > $rule['end']) {
                continue;
            }
            // 3. 检查匹配条件
            if ($rule['match'] !== null) {
                if ($rule['match'] === 'critical' && $level !== 'critical') {
                    continue;
                }
                // 也可以匹配告警名称 pattern
            }
            return true; // 命中静默规则
        }
        return false;
    }
}

调用时机(发送通知前)

if (app(AlertMuteService::class)->shouldMute($alert, $level)) {
    logger('Alert muted during silent period');
    return;
}
// 正常发送邮件/短信/企业微信...

基于数据库/Redis(灵活、支持动态配置)

适用于需要运营后台动态修改静默时段的项目。

数据表结构(MySQL 示例)

CREATE TABLE `alert_mute_rules` (
    `id` int PRIMARY KEY AUTO_INCREMENT,
    `name` varchar(100) COMMENT '规则名称',
    `time_zone` varchar(50) DEFAULT 'Asia/Shanghai',
    `start_time` time NOT NULL,
    `end_time` time NOT NULL,
    `days_of_week` varchar(20) COMMENT '1-7,逗号分隔,如1,2,3,4,5',
    `alert_type` varchar(50) DEFAULT NULL COMMENT 'null表示全部',
    `alert_level` varchar(20) DEFAULT NULL COMMENT 'critical/warning/info',
    `status` tinyint DEFAULT 1,
    `created_at` timestamp
);

Redis 缓存预热(推荐)

  • 将所有活跃规则保存到 Redis Sorted SetHash 中。
  • 定时任务 (Cron) 每分钟检查当前时间是否命中规则。
  • 或在发送告警时实时查询。

实时查询示例

class RedisAlertMuteChecker
{
    public function isMuted($alert): bool
    {
        $now = new DateTime('now', new DateTimeZone('Asia/Shanghai'));
        $time = $now->format('H:i');
        $dayOfWeek = $now->format('N'); // 1-7
        // 从 Redis 获取所有规则(建议用 Hash 存储,field为规则ID)
        $rules = Redis::hGetAll('alert:mute:rules');
        foreach ($rules as $rule) {
            // 解析 JSON
            $ruleData = json_decode($rule, true);
            if (!$ruleData['status']) continue;
            // 检查日期
            $days = explode(',', $ruleData['days_of_week']);
            if (!in_array($dayOfWeek, $days)) continue;
            // 检查时间区间(支持跨天,需要特殊处理)
            if ($time >= $ruleData['start_time'] && $time <= $ruleData['end_time']) {
                // 匹配告警类型/级别
                if ($ruleData['alert_type'] && $ruleData['alert_type'] !== $alert['type']) continue;
                if ($ruleData['alert_level'] && $ruleData['alert_level'] !== $alert['level']) continue;
                return true;
            }
        }
        return false;
    }
}

使用任务调度 + 开关(适合整站维护)

在项目本身进行“维护模式”时,同步静默所有告警。

方法:利用 Laravel 的 DownForMaintenance 或者项目自定义的全局变量。

if (app()->isDownForMaintenance()) {
    // 直接返回,不发送任何通知
    logger('Site under maintenance, alert muted');
    return;
}

配合定时任务:

# 凌晨 2点进入静默
0 2 * * * php artisan mute:on --reason="系统维护"
# 凌晨 5点恢复通知
0 5 * * * php artisan mute:off

高级:基于告警聚合(De-duplication + Silence)

如果使用 Prometheus + AlertManagerGrafana OnCall,在应用层之外还能做:

组件 静默功能
AlertManager 天然的 silences API,支持时间、标签匹配,php 应用只需发送告警到 AlertManager,静默由 AlertManager 维护。
Grafana OnCall 动态将告警静默、通知对接
PHP + Webhook + CRON 编写 shell 脚本定时调用 curl -XPOST alertmanager/silences

最佳实践建议

  1. 不要在生产代码里 hardcode 时间:使用配置中心或数据库。
  2. 考虑时区:如果项目部署在全球,统一使用 UTC 存储,展示时转本地。
  3. 日志记录:静默的告警也要记录日志,方便事后排查。
  4. 跨天支持23:00 - 01:00 的静默需要特殊逻辑。
  5. 优先级:如果存在多条规则,明确静默规则的优先级(如:更具体的规则优先级更高)。

简单封装示例(即时可用)

// services/AlertMuteService.php
class AlertMuteService
{
    public function check(array $alert): bool
    {
        $config = config('alert.mute_rules', []);
        $now = Carbon::now();
        foreach ($config as $rule) {
            // 解析时间
            $start = Carbon::parse($rule['start']);
            $end = Carbon::parse($rule['end']);
            // 处理跨天
            if ($start->greaterThan($end)) {
                // 跨越午夜,如 23:00 -> 01:00
                if (!($now->greaterThanOrEqualTo($start) || $now->lessThanOrEqualTo($end))) {
                    continue;
                }
            } else {
                // 普通区间
                if (!($now->between($start, $end))) {
                    continue;
                }
            }
            // 检查星期
            if (isset($rule['days']) && !in_array($now->dayOfWeek, $rule['days'])) continue;
            // 检查告警级别
            if (isset($rule['level']) && $rule['level'] !== $alert['level']) continue;
            return true;
        }
        return false;
    }
}

选择哪种方案取决于你的项目规模、告警系统架构、团队对运维的可控需求,推荐至少做到 配置化 + 数据库支持动态调整,便于快速响应线上变更。

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