PHP项目域名解析异常如何告警切换备用DNS

wen PHP项目 26

本文目录导读:

PHP项目域名解析异常如何告警切换备用DNS

  1. 核心监控脚本(PHP + Shell)
  2. PHP应用层监控组件
  3. 故障注入与测试
  4. 生产环境部署建议
  5. 监控与告警最佳实践
  6. 异常恢复机制

针对PHP项目的域名解析异常告警与DNS自动切换,可以采用以下分层方案:

核心监控脚本(PHP + Shell)

监控脚本示例 (dns_monitor.sh)

#!/bin/bash
# DNS解析监控脚本
DOMAIN="yourdomain.com"
PRIMARY_DNS="8.8.8.8"  # 主DNS
BACKUP_DNS="1.1.1.1"   # 备用DNS
ALERT_EMAIL="ops@yourcompany.com"
CHECK_INTERVAL=60
check_dns() {
    local dns=$1
    local result=$(dig @$dns $DOMAIN +short +timeout=5 2>/dev/null)
    if [ -z "$result" ]; then
        echo "DNS解析失败: $dns"
        return 1
    fi
    echo "DNS正常: $result"
    return 0
}
# 主DNS重试检测
for i in {1..3}; do
    if check_dns $PRIMARY_DNS; then
        echo "主DNS正常"
        exit 0
    fi
    sleep 2
done
# 触发告警并切换
echo "主DNS异常,尝试切换到备用DNS" | mail -s "【紧急】DNS解析异常告警" $ALERT_EMAIL
# 切换系统DNS
echo "nameserver $BACKUP_DNS" > /etc/resolv.conf.bak
cp /etc/resolv.conf.bak /etc/resolv.conf
# 验证备用DNS
if ! check_dns $BACKUP_DNS; then
    echo "备用DNS也异常,启动紧急预案" | mail -s "【严重】双DNS异常" $ALERT_EMAIL
fi

PHP应用层监控组件

自定义DNS解析类 (DnsMonitor.php)

<?php
class DnsMonitor {
    private $domain;
    private $primaryDns = ['8.8.8.8', '8.8.4.4'];
    private $backupDns = ['1.1.1.1', '1.0.0.1'];
    private $errorThreshold = 3;
    private $errorCount = 0;
    public function __construct($domain) {
        $this->domain = $domain;
    }
    /**
     * 智能DNS解析(带自动切换)
     */
    public function resolveWithFailover() {
        // 尝试主DNS
        $result = $this->resolveWithDNS($this->primaryDns);
        if ($result !== false) {
            $this->errorCount = 0;
            return $result;
        }
        // 记录异常
        $this->errorCount++;
        $this->logError('主DNS解析失败');
        // 触发阈值告警
        if ($this->errorCount >= $this->errorThreshold) {
            $this->triggerAlert('DNS解析连续失败'.$this->errorCount.'次');
        }
        // 自动切换到备用DNS
        $backupResult = $this->resolveWithDNS($this->backupDns);
        if ($backupResult !== false) {
            $this->log('已切换至备用DNS');
            return $backupResult;
        }
        // 双DNS均失败
        $this->triggerAlert('主备DNS均解析失败,使用PHP默认DNS');
        return dns_get_record($this->domain, DNS_A);
    }
    private function resolveWithDNS($dnsList) {
        $context = stream_context_create([
            'dns' => [
                'nameservers' => $dnsList,
                'timeout' => 3
            ]
        ]);
        $result = @dns_get_record($this->domain, DNS_A, $dnsList);
        return $result ?: false;
    }
    private function triggerAlert($message) {
        // 告警方式1:日志
        error_log(date('Y-m-d H:i:s')." [DNS_ALERT] $message\n", 3, '/var/log/dns_alert.log');
        // 告警方式2:邮件
        mail('ops@company.com', 'DNS解析异常', $message);
        // 告警方式3:Webhook推送
        $this->sendWebhook($message);
    }
    private function sendWebhook($message) {
        $webhookUrl = 'https://hooks.slack.com/services/YOUR_WEBHOOK';
        $payload = json_encode(['text' => "[DNS告警] $message"]);
        $ch = curl_init($webhookUrl);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
        curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
        curl_exec($ch);
        curl_close($ch);
    }
}
// 使用示例
$monitor = new DnsMonitor('api.yourproject.com');
$ips = $monitor->resolveWithFailover();

故障注入与测试

测试脚本 (test_dns_failover.php)

<?php
// 模拟DNS故障
$monitor = new DnsMonitor('example.com');
// 测试1: 正常解析
echo "测试1 - 正常解析:\n";
$result = $monitor->resolveWithFailover();
print_r($result);
// 测试2: 模拟主DNS超时
echo "测试2 - 主DNS超时:\n";
$monitor->primaryDns = ['10.0.0.1']; // 无效DNS
$result = $monitor->resolveWithFailover();
echo $result ? "切换到备用DNS成功\n" : "全部失败\n";
// 测试3: 连续故障告警
echo "测试3 - 连续故障告警:\n";
for ($i=0; $i<5; $i++) {
    $monitor->errorCount = 0;
    $result = $monitor->resolveWithFailover();
    echo "尝试#$i: ".($result ? '成功' : '失败')."\n";
}

生产环境部署建议

系统级配置

# Nginx DNS resolver配置
location /api/ {
    resolver 8.8.8.8 1.1.1.1 valid=30s;
    set $backend "your-api-server.com";
    proxy_pass http://$backend;
}

Docker环境DNS配置

# docker-compose.yml
services:
  php:
    image: your-php-app
    dns:
      - 8.8.8.8
      - 1.1.1.1
    environment:
      - DNS_PRIMARY=8.8.8.8
      - DNS_BACKUP=1.1.1.1

监控与告警最佳实践

使用Prometheus监测

# prometheus dns_exporter配置
dns:
  targets:
    - yourdomain.com
  query_name: "yourdomain.com"
  query_type: "A"
  dns_server: "8.8.8.8"
  timeout: 5
  alert:
    - name: dns_resolution_failed
      for: 30s
      severity: critical

告警通道配置

  1. 即时告警:Slack/飞书 Webhook(配置在sendWebhook方法中)
  2. 紧急短信:通过API调用七牛云/阿里云短信接口
  3. 电话告警:集成PagerDuty或自建IVR系统

异常恢复机制

#!/bin/bash
# 自动恢复脚本 dns_recovery.sh
check_dns_health() {
    while true; do
        # 尝试恢复主DNS
        if dig @8.8.8.8 yourdomain.com +short > /dev/null 2>&1; then
            echo "主DNS已恢复"
            sed -i 's/nameserver 1.1.1.1/nameserver 8.8.8.8/' /etc/resolv.conf
            systemctl restart php-fpm
            break
        fi
        sleep 60
    done
}

核心要点

  • 三层检测:系统级(Ping/Dig) → PHP应用层 → 业务逻辑层
  • 智能切换:连续错误次数达到阈值才切换,避免误切
  • 恢复机制:至少30分钟自动检测恢复,降低管理员负担
  • 告警分级:解析失败→切换告警→双DNS失败→严重告警

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