Skip to content

DNS 性能监控

DNS-Go 提供实时的 DNS 性能监控功能,帮助您了解 DNS 服务器的运行状态和查询性能。

功能概述

DNS 性能监控模块提供以下功能:

  • 实时 QPS 监控:显示当前查询速率、平均 QPS、峰值 QPS
  • 查询统计:总查询量、今日查询量
  • 响应时间分析:平均响应时间、最小/最大响应时间、P50/P95/P99 分位数
  • 解析成功率:成功解析次数、失败次数、缓存命中率
  • 客户端统计:活跃客户端数、总客户端数、平均每客户端查询量
  • 查询类型分布:A、AAAA、CNAME、MX 等查询类型的分布情况
  • 上游性能监控:各上游 DNS 服务器的响应时间和成功率

架构设计

数据流

DNS 查询 → 查询日志记录 → 实时统计计算 → SSE 推送 → 前端展示

核心组件

  1. 数据收集层:在 DNS 查询处理过程中记录查询日志
  2. 统计计算层:定期计算各项性能指标
  3. 实时推送层:通过 SSE (Server-Sent Events) 向前端推送实时数据
  4. 可视化层:前端使用图表展示性能数据

实现细节

后端实现

1. 数据模型

go
// 查询统计概览
type QueryStatsOverview struct {
    TotalQueries    int64   `json:"total_queries"`     // 总查询量
    TodayQueries    int64   `json:"today_queries"`     // 今日查询量
    CurrentQps      float64 `json:"current_qps"`       // 当前 QPS
    AvgQps          float64 `json:"avg_qps"`           // 平均 QPS
    PeakQps         float64 `json:"peak_qps"`          // 峰值 QPS
    UpdateTime      string  `json:"update_time"`       // 更新时间
    FormattedQps    string  `json:"formatted_qps"`     // 格式化 QPS
    FormattedAvgQps string  `json:"formatted_avg_qps"` // 格式化平均 QPS
}

// 响应时间统计
type ResponseTimeStats struct {
    AvgResponseMs   float64 `json:"avg_response_ms"`    // 平均响应时间
    MinResponseMs   int64   `json:"min_response_ms"`    // 最小响应时间
    MaxResponseMs   int64   `json:"max_response_ms"`    // 最大响应时间
    P50ResponseMs   int64   `json:"p50_response_ms"`    // P50 分位数
    P95ResponseMs   int64   `json:"p95_response_ms"`    // P95 分位数
    P99ResponseMs   int64   `json:"p99_response_ms"`    // P99 分位数
    TotalSamples    int64   `json:"total_samples"`      // 样本总数
}

// 解析统计
type ResolutionStats struct {
    SuccessCount   int64   `json:"success_count"`    // 成功次数
    FailedCount    int64   `json:"failed_count"`     // 失败次数
    CachedCount    int64   `json:"cached_count"`     // 缓存命中次数
    TotalCount     int64   `json:"total_count"`      // 总次数
    SuccessRate    float64 `json:"success_rate"`     // 成功率
    CacheHitRate   float64 `json:"cache_hit_rate"`   // 缓存命中率
}

// 客户端统计
type ClientStats struct {
    ActiveClients        int64   `json:"active_clients"`         // 活跃客户端数
    NewClientsToday      int64   `json:"new_clients_today"`      // 今日新增客户端
    AvgQueriesPerClient  float64 `json:"avg_queries_per_client"` // 平均每客户端查询量
    TotalClients         int64   `json:"total_clients"`          // 总客户端数
}

2. 实时数据推送

使用 SSE (Server-Sent Events) 实现实时数据推送:

go
// SSE 监控流
func (h *DnsMonitorHandler) MonitorSSE(c *gin.Context) {
    // 设置 SSE 响应头
    c.Header("Content-Type", "text/event-stream")
    c.Header("Cache-Control", "no-cache")
    c.Header("Connection", "keep-alive")
    c.Header("X-Accel-Buffering", "no")

    // 创建监控会话
    session := h.service.CreateMonitorSession()
    defer h.service.CloseMonitorSession(session.ID)

    // 发送初始连接成功事件
    c.SSEvent("connected", gin.H{
        "status":    "connected",
        "timestamp": time.Now().Format(time.RFC3339),
    })
    c.Writer.Flush()

    // 启动数据推送循环
    ticker := time.NewTicker(5 * time.Second)
    defer ticker.Stop()

    for {
        select {
        case <-c.Request.Context().Done():
            return
        case <-ticker.C:
            // 获取最新监控数据
            data := h.service.GetMonitorData()
            c.SSEvent("monitor", data)
            c.Writer.Flush()
        }
    }
}

3. 统计计算

go
// 计算当前 QPS
func calculateCurrentQps() float64 {
    oneMinuteAgo := time.Now().Add(-1 * time.Minute)
    lastMinuteQueries := getQueryCountSince(oneMinuteAgo)
    return float64(lastMinuteQueries) / 60.0
}

// 计算平均 QPS
func calculateAvgQps(startTime, endTime time.Time) float64 {
    duration := endTime.Sub(startTime).Seconds()
    if duration <= 0 {
        return 0
    }
    queryCount := getQueryCountInRange(startTime, endTime)
    return float64(queryCount) / duration
}

// 计算响应时间分位数
func calculateResponseTimePercentile(percentile float64) int64 {
    // 从数据库获取响应时间数据
    responseTimes := getResponseTimes()
    return calculatePercentile(responseTimes, percentile)
}

前端实现

1. 组件结构

DnsPerformance/
├── index.vue              # 主页面
├── components/
│   ├── QueryStatsCard.vue      # 查询统计卡片
│   ├── ResponseTimeCard.vue    # 响应时间卡片
│   ├── ResolutionStatsCard.vue # 解析统计卡片
│   ├── ClientStatsCard.vue     # 客户端统计卡片
│   ├── QueryTypeChart.vue      # 查询类型分布图表
│   ├── TrendChart.vue          # 趋势图表
│   └── UpstreamPerformanceCard.vue # 上游性能卡片

2. SSE 连接管理

typescript
// 创建 SSE 连接
const createSSEConnection = () => {
  const eventSource = new EventSource(
    `${import.meta.env.VITE_API_URL}/api/monitor/sse`
  );

  eventSource.addEventListener("connected", (event) => {
    console.log("SSE 连接成功:", JSON.parse(event.data));
  });

  eventSource.addEventListener("monitor", (event) => {
    const data = JSON.parse(event.data);
    updateMonitorData(data);
  });

  eventSource.onerror = (error) => {
    console.error("SSE 连接错误:", error);
    // 自动重连
    setTimeout(createSSEConnection, 5000);
  };

  return eventSource;
};

3. 数据展示

使用 Element Plus 的统计卡片和 ECharts 图表展示数据:

vue
<template>
  <div class="dns-performance">
    <el-row :gutter="16">
      <!-- QPS 统计 -->
      <el-col :xs="24" :sm="12" :md="6">
        <QueryStatsCard :data="queryStats" />
      </el-col>
      
      <!-- 响应时间 -->
      <el-col :xs="24" :sm="12" :md="6">
        <ResponseTimeCard :data="responseStats" />
      </el-col>
      
      <!-- 解析成功率 -->
      <el-col :xs="24" :sm="12" :md="6">
        <ResolutionStatsCard :data="resolutionStats" />
      </el-col>
      
      <!-- 客户端统计 -->
      <el-col :xs="24" :sm="12" :md="6">
        <ClientStatsCard :data="clientStats" />
      </el-col>
    </el-row>

    <!-- 图表区域 -->
    <el-row :gutter="16" class="chart-row">
      <el-col :xs="24" :lg="12">
        <QueryTypeChart :data="queryTypeDistribution" />
      </el-col>
      <el-col :xs="24" :lg="12">
        <TrendChart :data="trendData" />
      </el-col>
    </el-row>
  </div>
</template>

API 接口

获取查询统计概览

http
GET /api/monitor/query-stats

响应:

json
{
  "total_queries": 120,
  "today_queries": 20,
  "current_qps": 0.33,
  "avg_qps": 0.01,
  "peak_qps": 0.5,
  "update_time": "2026-02-17T13:19:56+08:00",
  "formatted_qps": "0.33",
  "formatted_avg_qps": "0.01"
}

获取响应时间统计

http
GET /api/monitor/response-stats

获取解析统计

http
GET /api/monitor/resolution-stats

获取客户端统计

http
GET /api/monitor/client-stats

获取查询类型分布

http
GET /api/monitor/query-types

SSE 实时监控流

http
GET /api/monitor/sse

配置说明

监控参数配置

config.toml 中可以配置监控相关参数:

toml
[monitor]
# 数据刷新间隔(秒)
refresh_interval = 5

# 统计时间窗口(分钟)
stats_window = 60

# 是否启用实时监控
enable_realtime = true

# 客户端活跃超时时间(分钟)
client_timeout = 30

性能优化

  1. 数据缓存:使用内存缓存存储最近的数据,减少数据库查询
  2. 增量更新:只推送变化的数据,减少网络传输
  3. 连接池管理:合理管理 SSE 连接,避免资源泄漏
  4. 采样策略:对于高频查询,采用采样策略减少计算量

故障排查

常见问题

  1. SSE 连接失败

    • 检查网络连接
    • 确认服务器支持 SSE
    • 查看浏览器控制台错误信息
  2. 数据不更新

    • 检查监控服务是否正常运行
    • 确认数据库连接正常
    • 查看服务端日志
  3. QPS 显示为 0

    • 检查是否有 DNS 查询流量
    • 确认查询日志记录正常
    • 验证时间范围设置

日志查看

bash
# 查看监控服务日志
docker logs dns-go | grep monitor

# 查看实时日志
docker logs -f dns-go

最佳实践

  1. 合理设置刷新间隔:根据实际需求设置刷新间隔,避免过于频繁的更新
  2. 关注关键指标:重点关注 QPS、响应时间、成功率等核心指标
  3. 设置告警阈值:为关键指标设置告警阈值,及时发现异常
  4. 定期分析趋势:通过趋势图表分析 DNS 使用模式和性能变化

基于 MIT 许可发布