多窗口燃烧速率算法:1小时、6小时、24小时、72小时窗口的燃烧速率计算逻辑与代码实现

在SRE实践中,单一时间窗口的燃烧速率往往无法全面反映服务可靠性的真实状态。短窗口(如1小时)对突发故障敏感,但容易产生误报;长窗口(如72小时)能平滑噪声,但响应延迟较高。多窗口燃烧速率算法通过组合多个时间窗口的燃烧速率,实现告警的快速检测与噪声抑制。

1. 燃烧速率核心定义

燃烧速率(Burn Rate)衡量的是错误预算消耗的速度。其计算公式为:

Burn Rate = (窗口内错误率) / (SLO目标错误率)

其中:

  • 窗口内错误率 = 窗口内错误请求数 / 窗口内总请求数
  • SLO目标错误率 = 1 - SLO目标值(例如99.9% SLO对应0.001)

当 Burn Rate > 1 时,表示错误预算正在以高于预期的速度消耗;当 Burn Rate > 14.4(即1小时消耗完30天预算)时,通常触发紧急告警。

2. 多窗口燃烧速率计算逻辑

本课程采用四个标准时间窗口:1小时、6小时、24小时、72小时。每个窗口独立计算燃烧速率,并通过阈值联动实现告警降噪。

窗口名称 窗口时长 敏感度 典型用途 告警阈值(示例)
短窗口 1小时 高 快速检测突发故障 ≥ 14.4
中短窗口 6小时 中高 检测持续异常 ≥ 6.0
中长窗口 24小时 中低 检测慢速退化 ≥ 3.0
长窗口 72小时 低 趋势分析与噪声过滤 ≥ 1.5
阈值联动原则:短窗口阈值高(容忍突发),长窗口阈值低(敏感于持续退化)。告警触发条件通常为“任意窗口超过阈值”或“多窗口同时超过阈值”,后者可显著降低误报率。

3. 多窗口燃烧速率算法流程图

下图展示了四个窗口的并行计算流程与阈值判定逻辑:

多窗口燃烧速率计算与阈值联动流程 实时请求/错误数据 1小时窗口 6小时窗口 24小时窗口 72小时窗口 计算 Burn Rate 计算 Burn Rate 计算 Burn Rate 计算 Burn Rate 阈值 ≥ 14.4? 阈值 ≥ 6.0? 阈值 ≥ 3.0? 阈值 ≥ 1.5? 多窗口联动判定逻辑 任意窗口超阈值 OR 多窗口同时超阈值 触发告警 / 记录台账

4. 代码实现:多窗口燃烧速率计算

以下Go语言代码实现了四个时间窗口的燃烧速率并行计算与阈值判定:

package main

import (
    "fmt"
    "sync"
    "time"
)

// WindowConfig 定义时间窗口配置
type WindowConfig struct {
    Name        string
    Duration    time.Duration
    Threshold   float64
}

// BurnRateResult 存储单个窗口的计算结果
type BurnRateResult struct {
    WindowName string
    BurnRate   float64
    Exceeded   bool
}

// CalculateBurnRate 计算单个窗口的燃烧速率
func CalculateBurnRate(errors, total int64, sloTarget float64) float64 {
    if total == 0 {
        return 0
    }
    errorRate := float64(errors) / float64(total)
    targetErrorRate := 1 - sloTarget
    if targetErrorRate == 0 {
        return 0
    }
    return errorRate / targetErrorRate
}

// MultiWindowBurnRate 并行计算多窗口燃烧速率
func MultiWindowBurnRate(errors, total int64, sloTarget float64, windows []WindowConfig) []BurnRateResult {
    var wg sync.WaitGroup
    results := make([]BurnRateResult, len(windows))

    for i, w := range windows {
        wg.Add(1)
        go func(idx int, config WindowConfig) {
            defer wg.Done()
            burnRate := CalculateBurnRate(errors, total, sloTarget)
            results[idx] = BurnRateResult{
                WindowName: config.Name,
                BurnRate:   burnRate,
                Exceeded:   burnRate >= config.Threshold,
            }
        }(i, w)
    }

    wg.Wait()
    return results
}

// EvaluateAlert 评估是否触发告警(多窗口联动)
func EvaluateAlert(results []BurnRateResult, requireMultiple bool, minWindows int) bool {
    exceededCount := 0
    for _, r := range results {
        if r.Exceeded {
            exceededCount++
            if !requireMultiple {
                return true // 任意窗口超阈值即告警
            }
        }
    }
    return requireMultiple && exceededCount >= minWindows
}

func main() {
    // 定义四个时间窗口
    windows := []WindowConfig{
        {Name: "1小时", Duration: 1 * time.Hour, Threshold: 14.4},
        {Name: "6小时", Duration: 6 * time.Hour, Threshold: 6.0},
        {Name: "24小时", Duration: 24 * time.Hour, Threshold: 3.0},
        {Name: "72小时", Duration: 72 * time.Hour, Threshold: 1.5},
    }

    // 模拟数据:99.9% SLO,窗口内错误请求50,总请求10000
    sloTarget := 0.999
    errors := int64(50)
    total := int64(10000)

    // 并行计算
    results := MultiWindowBurnRate(errors, total, sloTarget, windows)

    // 输出结果
    fmt.Println("多窗口燃烧速率计算结果:")
    fmt.Println("================================")
    for _, r := range results {
        status := "✅ 正常"
        if r.Exceeded {
            status = "⚠️ 超阈值"
        }
        fmt.Printf("%-8s | Burn Rate: %8.4f | %s\n", r.WindowName, r.BurnRate, status)
    }

    // 联动判定:至少2个窗口超阈值才告警
    alert := EvaluateAlert(results, true, 2)
    fmt.Println("================================")
    if alert {
        fmt.Println("🔔 触发告警:多窗口燃烧速率超标")
    } else {
        fmt.Println("✅ 未触发告警:燃烧速率在可接受范围")
    }
}

5. 多窗口联动策略对比

不同的联动策略适用于不同的场景,下表对比了三种常见策略:

联动策略 判定条件 误报率 漏报率 适用场景
OR策略 任意窗口超阈值即告警 高 低 关键业务、容忍度低
AND策略 所有窗口同时超阈值才告警 低 高 非关键业务、噪声大
N-of-M策略 至少N个窗口超阈值(推荐) 中 中 通用场景、平衡敏感度
生产实践建议:推荐使用 N-of-M策略,通常设置为“4个窗口中至少2个超阈值”。这种配置既能快速响应突发故障(1小时窗口会迅速超阈值),又能过滤掉短时抖动(仅1个窗口超阈值时不告警)。

6. 多窗口燃烧速率联动判定流程图

下图展示了N-of-M联动策略的详细判定逻辑:

N-of-M 多窗口联动判定逻辑 4个窗口的Burn Rate 统计超阈值的窗口数量 N N ∈ [0, 4] N ≥ 2 ? 是 触发告警 否 记录台账,不告警 N-of-M策略:平衡敏感度与误报率,推荐 N=2, M=4
常见陷阱:不要对所有窗口使用相同的阈值。短窗口阈值过低会导致频繁误报,长窗口阈值过高会导致漏报。阈值设置应基于SLO目标和错误预算消耗速度进行数学推导,而非经验猜测。

7. 阈值推导公式

每个窗口的阈值可以通过以下公式推导:

阈值 = (窗口时长 / 错误预算耗尽时间) × (1 - SLO目标) / (1 - SLO目标)

简化后:
阈值 = 窗口时长 / 错误预算耗尽时间

例如:30天预算在1小时内耗尽
阈值 = 1小时 / (30天 × 24小时) = 1 / 720 ≈ 0.00139
但这是错误率比值,转换为燃烧速率:
Burn Rate = 0.00139 / (1 - 0.999) = 1.39

实际上,1小时消耗完30天预算的燃烧速率为:
(30 × 24) / 1 = 720倍
即 Burn Rate = 720 时,1小时耗尽全部预算。

常用阈值(99.9% SLO):
- 1小时耗尽预算:Burn Rate = 720
- 5%预算在1小时内耗尽:Burn Rate = 720 × 5% = 36
- 2%预算在1小时内耗尽:Burn Rate = 720 × 2% = 14.4(常用)
阈值速查表(99.9% SLO):
- 1小时窗口:14.4(对应2%预算消耗)
- 6小时窗口:6.0(对应5%预算消耗)
- 24小时窗口:3.0(对应10%预算消耗)
- 72小时窗口:1.5(对应15%预算消耗)