跳转到内容

Metrics 监控系统

quicX Metrics 为 QUIC/HTTP3 实现提供全面的可观测性:54+ 指标覆盖 UDP、QUIC、HTTP/3 各层,无锁设计,支持 Prometheus 格式导出。所有指标操作为 O(1) 复杂度——原子操作避免锁竞争、预分配槽位实现零堆分配,单次指标更新 < 10ns;核心指标自动埋点,可运行时启停。本文尝试回答以下问题:

  1. 指标系统怎么做到零开销? —— 见”系统架构”与”性能保证”;
  2. 54+ 指标如何组织、各覆盖什么? —— 见”指标分类”的 13 个功能类别;
  3. 如何在项目中接入与导出? —— 见”使用指南”。
┌─────────────────────────────────────────────────┐
│ Application Code │
│ (UDP, QUIC, HTTP/3, Memory Pool, etc.) │
└────────────────┬────────────────────────────────┘
│ Metrics::CounterInc()
│ Metrics::GaugeSet()
▼
┌─────────────────────────────────────────────────┐
│ Metrics Registry (Lock-Free) │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Counter │ │ Gauge │ │
│ │ (Atomic) │ │ (Atomic) │ │
│ └──────────────┘ └──────────────┘ │
└────────────────┬────────────────────────────────┘
│ ExportPrometheus()
▼
┌─────────────────────────────────────────────────┐
│ Prometheus Exporter │
│ # TYPE metric_name counter │
│ metric_name{labels} value │
└─────────────────────────────────────────────────┘
// 预分配槽位数组
std::vector<MetricSlot> slots_; // 初始化时分配
// O(1) 注册
MetricID RegisterCounter(name, help) {
size_t id = next_id_.fetch_add(1); // 原子递增
slots_[id] = MetricSlot{name, help, COUNTER};
return id;
}
// Counter 递增 - 无锁
void CounterInc(MetricID id, uint64_t delta = 1) {
slots_[id].value.fetch_add(delta, std::memory_order_relaxed);
}
// Gauge 设置 - 无锁
void GaugeSet(MetricID id, uint64_t value) {
slots_[id].value.store(value, std::memory_order_relaxed);
}
std::string ExportPrometheus() {
std::ostringstream oss;
for (auto& slot : slots_) {
if (slot.type == COUNTER) {
oss << "# TYPE " << slot.name << " counter\n";
oss << slot.name << " "
<< slot.value.load(std::memory_order_relaxed) << "\n";
}
// ... Gauge, Histogram
}
return oss.str();
}
指标名称类型说明
udp_packets_rxCounterUDP 接收包总数
udp_packets_txCounterUDP 发送包总数
udp_bytes_rxCounterUDP 接收字节总数
udp_bytes_txCounterUDP 发送字节总数
udp_dropped_packetsCounterUDP 丢包总数
udp_send_errorsCounterUDP 发送错误总数

用途:监控网络层健康状况,识别网络拥塞和丢包问题。

指标名称类型说明
quic_connections_activeGauge当前活跃连接数
quic_connections_totalCounter累计创建连接数
quic_connections_closedCounter累计关闭连接数
quic_handshake_successCounter握手成功次数
quic_handshake_failCounter握手失败次数

用途:监控连接生命周期,评估握手成功率。

指标名称类型说明
quic_packets_rxCounterQUIC 包接收总数
quic_packets_txCounterQUIC 包发送总数
quic_packets_retransmitCounter重传包总数
quic_packets_lostCounter丢包总数
quic_packets_droppedCounter丢弃包总数
quic_packets_ackedCounter确认包总数

用途:监控传输层可靠性,计算丢包率和重传率。

指标名称类型说明
quic_streams_activeGauge当前活跃流数
quic_streams_createdCounter累计创建流数
quic_streams_closedCounter累计关闭流数
quic_streams_bytes_rxCounter流接收字节总数
quic_streams_bytes_txCounter流发送字节总数
quic_streams_reset_rxCounter接收 RESET 次数
quic_streams_reset_txCounter发送 RESET 次数

用途:监控流管理和数据传输,识别流异常。

指标名称类型说明
rtt_smoothed_usGauge平滑 RTT (微秒)
rtt_variance_usGaugeRTT 方差 (微秒)
rtt_min_usGauge最小 RTT (微秒)

用途:监控网络延迟,评估连接质量。

指标名称类型说明
congestion_window_bytesGauge当前拥塞窗口 (字节)
congestion_events_totalCounter拥塞事件总数
slow_start_exitsCounter退出慢启动次数
bytes_in_flightGauge在途字节数
pacing_rate_bytes_per_secGaugePacing 速率 (字节/秒)
pacing_delay_usHistogramPacing 延迟 (微秒)

用途:监控拥塞控制算法,优化吞吐量。

指标名称类型说明
errors_protocolCounter协议错误次数
errors_internalCounter内部错误次数
errors_flow_controlCounter流控制错误次数
errors_stream_limitCounter流限制错误次数

用途:监控系统健康状况,快速定位问题。

指标名称类型说明
quic_flow_control_blockedCounter连接级流控阻塞次数
quic_stream_data_blockedCounter流级流控阻塞次数

用途:监控流控制状态,优化窗口大小。

指标名称类型说明
idle_timeout_totalCounter空闲超时次数
pto_count_totalCounterPTO 超时次数

用途:监控超时事件,调整超时参数。

指标名称类型说明
http3_requests_totalCounterHTTP/3 请求总数
http3_requests_activeGauge当前活跃请求数
http3_requests_failedCounter失败请求总数
http3_push_promises_rxCounter接收 Push Promise 次数

用途:监控 HTTP/3 业务指标,评估服务质量。

指标名称类型说明
mem_pool_allocated_blocksGauge已分配块数
mem_pool_free_blocksGauge空闲块数
mem_pool_allocationsCounter分配次数
mem_pool_deallocationsCounter释放次数

用途:监控内存使用,优化内存池配置。

指标名称类型说明
frames_rx_totalCounter接收 Frame 总数
frames_tx_totalCounter发送 Frame 总数

用途:监控协议层活动,分析通信模式。

指标名称类型说明
ack_delay_usHistogramACK 延迟 (微秒)
ack_ranges_per_frameHistogram每个 ACK Frame 的 Range 数
ack_frequencyGaugeACK 频率 (每秒 ACK 数)

用途:监控 ACK 行为,优化确认策略。

#include <quicx/common/metrics.h>
// 1. 配置 Metrics
quicx::MetricsConfig config;
config.enable_ = true; // 启用 metrics
config.initial_slots_ = 1024; // 初始槽位数
config.prefix_ = "quicx_"; // 指标名称前缀
// 2. 初始化 Metrics 系统
quicx::Metrics::Initialize(config);
// 获取 Prometheus 格式的 metrics 数据
std::string metrics_data = quicx::Metrics::ExportPrometheus();
// 输出到文件
std::ofstream file("/var/lib/prometheus/quicx.prom");
file << metrics_data;
file.close();
// 或通过 HTTP endpoint 提供
// (参见 HTTP/3 Metrics Endpoint 部分)
#include <quicx/http3/if_server.h>
// 创建 HTTP/3 server
auto server = quicx::IServer::Create(settings);
// 配置 server
quicx::Http3ServerConfig config;
config.quic_config_.cert_file_ = "server.crt";
config.quic_config_.key_file_ = "server.key";
// 启用 metrics endpoint
config.metrics_.http_enable_ = true;
config.metrics_.http_path_ = "/metrics";
// 初始化并启动
server->Init(config);
server->Start("0.0.0.0", 8443);

访问 metrics:

终端窗口
# 使用 HTTP/3 客户端
curl --http3 https://localhost:8443/metrics
Benchmark Time CPU
-------------------------------------------------
CounterInc/1 8.2 ns 8.2 ns
CounterInc/100 820 ns 820 ns
GaugeSet/1 7.5 ns 7.5 ns
GaugeSet/100 750 ns 750 ns
ExportPrometheus/100 45.2 µs 45.2 µs
ExportPrometheus/1000 452.0 µs 452.0 µs
  1. 极低延迟:单次更新 < 10ns
  2. 线性扩展:性能与指标数量线性相关
  3. 零竞争:无锁设计,多线程无竞争
  4. 内存高效:预分配,无运行时分配
每个指标槽位:~128 字节
1000 个指标:~128 KB
导出缓冲区:~100 KB (临时)
// 根据预期指标数量配置
config.initial_slots_ = expected_metrics * 1.5; // 留 50% 余量
// 每 15 秒导出一次(Prometheus 默认抓取间隔)
std::thread exporter([]{
while (running) {
std::string data = Metrics::ExportPrometheus();
WriteToFile("/var/lib/prometheus/quicx.prom", data);
std::this_thread::sleep_for(std::chrono::seconds(15));
}
});

优先监控:

  • 连接数 (quic_connections_active)
  • 丢包率 (quic_packets_lost / quic_packets_tx)
  • RTT (rtt_smoothed_us)
  • 错误率 (errors_*)
  • 吞吐量 (quic_streams_bytes_*)
# Prometheus 告警规则示例
groups:
- name: quicx_alerts
rules:
- alert: HighPacketLoss
expr: rate(quic_packets_lost[5m]) / rate(quic_packets_tx[5m]) > 0.05
annotations:
summary: "High packet loss rate (> 5%)"
- alert: HighRTT
expr: rtt_smoothed_us > 100000 # > 100ms
annotations:
summary: "High RTT detected"
- alert: TooManyErrors
expr: sum(rate(errors_protocol[5m])) > 10
annotations:
summary: "High error rate"

原因:Metrics 未初始化或已禁用

解决:

// 确保初始化
Metrics::Initialize(config);
// 确保启用
config.enable_ = true;

原因:没有注册任何指标

解决:

// 确保调用了 InitializeStandardMetrics()
// 这在 Metrics::Initialize() 中自动调用

原因:槽位数不足,导致重新分配

解决:

// 增加初始槽位数
config.initial_slots_ = 2048; // 或更大
// 1. 在 metrics_std.h 中声明
struct MetricsStd {
static MetricID MyCustomMetric;
};
// 2. 在 metrics_std.cpp 中定义
MetricID MetricsStd::MyCustomMetric = kInvalidMetricID;
// 3. 在 InitializeStandardMetrics() 中注册
MetricsStd::MyCustomMetric =
Metrics::RegisterCounter("my_custom_metric", "My custom metric");
// 4. 在代码中使用
Metrics::CounterInc(MetricsStd::MyCustomMetric);
// 注册 Histogram
MetricID latency_hist = Metrics::RegisterHistogram(
"request_latency_us",
"Request latency in microseconds",
{10, 50, 100, 500, 1000, 5000} // buckets
);
// 记录观测值
Metrics::HistogramObserve(latency_hist, latency_value);