Files
2026-05-24 11:42:38 +08:00

9.8 KiB
Raw Permalink Blame History

tags, create time
tags create time
microservice
canary-release
blue-green
traffic-routing
istio
load-balancing
2026-05-05 10:30

流量治理

概述

灰度发布(也叫金丝雀发布)是降低变更风险的核心手段。它让你将新版本逐步推向一小部分用户,观察指标正常后再全量。

[!question] 如何安全地上线? 你修复了一个紧急 Bug,但这次改动涉及核心支付链路。直接全量发布一旦出问题损失巨大。有没有办法先小范围验证,确认没问题再放量?

答案就是按规则拆分流量——将请求按照不同维度分配到新旧版本,用真实用户的流量来检验新代码,而不是靠测试环境的人为模拟。

flowchart LR
    A["🟢 v1 (稳定版)<br/>95% 流量"] --> B["🔵 v2 (测试版)<br/>5% 流量"]
    B --> C{"监控指标?"}
    C -- "✅ 一切正常" --> D["逐步放量<br/>10% → 25% → 50%"]
    C -- "❌ 错误率飙升" --> E["自动回滚到 v1 🔄"]
    D --> F{"全部放量至 100%"}
    F --> G["🟢 v2 成为新稳定版"]

一、灰度策略全景

常见灰度策略对比

策略 描述 优点 缺点 适用场景
按百分比 随机分配 N% 流量到新版本 简单粗暴,覆盖面广 可能只命中特定用户 通用场景
按用户 ID 指定用户/内部账号走新版 可精准控制测试范围 样本不够代表性 内部验收阶段
按 Header x-canary: true 路由到新版本 灵活性最高 需要客户端配合 QA / AB 测试
按地域 某个城市/机房的新版本 地域性问题的理想试验场 地域偏差大 全球化部署
按设备类型 iOS 新用户先用新版 覆盖目标人群 样本有限 移动端发版

[!tip] 实战建议:多策略组合 生产环境中通常不会只用单一规则。推荐的做法是分层判断:

第1层:内部员工 IP → 100% 进灰度(快速发现 bug)
第2层:header x-canary=true → 100% 进灰度(QA 验证)
第3层:新注册用户 → 50% 进灰度(扩大样本)
第4层:其余用户 → 默认 v1

按权重分流的 Go 实现

在应用层面(如 go-zero 或自研网关),流量分配往往通过中间件实现:

// CanaryMiddleware: header 携带 canary=true 的请求直通灰度版本
func (m *CanaryMiddleware) Next(ctx context.Context, req any, reply any, rpc func(context.Context, any, any) error) error {
    if m.r.isGray(ctx) { // 从 header/context 提取灰度标记
        return m.grayHandler(ctx, req, reply) // 路由到灰度服务实例
    }
    return m.next(ctx, req, reply) // 走正常路径
}

客户端负载均衡中的灰度

客户端侧的灰度通常通过自定义负载算法实现,以加权轮询为例:

// WeightedRoundRobin: 权重感知轮询
type WeightedRoundRobin struct {
    servers []*Server // 包含 weight 字段
    totalWeight int
}

func (w *WeightedRoundRobin) Next() (*Server, error) {
    // 每次选取当前权重最高的可用服务器
    // v1 权重 95, v2 权重 5 → 平均每 20 次请求 1 次命中 v2
}

二、蓝绿 vs 灰度

[!summary] 两种发布策略对比

维度 蓝绿部署 灰度发布 (金丝雀)
切换方式 一次性全切 逐步放量
资源消耗 双倍(新旧并行) 初期少量副本
回滚速度 秒级(切回 LB 即可) 同样秒级
风险等级 中高(全量暴露问题) 低(渐进式)
适合场景 大型变更、重大版本 日常迭代、高风险链路

蓝绿部署流程

stateDiagram-v2
    [*] --> Blue: 初始状态
    Blue --> DeployGreen: 部署 v2 到 Green 环境
    DeployGreen --> TestGreen: 验证 Green
    TestGreen --> Switch: 切换入口流量
    Switch --> Green: 全部流量到 Green/v2
    Green --> CleanupBlue: 删除 Blue/v1
    CleanupBlue --> [*]

金丝雀发布流程

graph TB
    S1["v1 运行中<br/>100% 流量"]
    S2["部署 v2<br/>5% 流量"]
    S3["监控 15min"]
    S4{"P99 延迟 < SLA?"}

    S4 -- 否 --> Rollback["回滚 v2 🔄"]
    S4 -- 是 --> S5["放量 25%"]
    S5 --> S6["监控 30min"]
    S6 --> S7{"错误率 < 0.1%?"}
    S7 -- 否 --> Rollback
    S7 -- 是 --> S8["放量 50%"]
    S8 --> S9["监控 1h"]
    S9 --> S10{"全项达标?"}
    S10 -- 是 --> S11["100% 全量 ✅"]
    S10 -- 否 --> Rollback

    style Rollback fill:#ffebee
    style S11 fill:#e8f5e9

[!warning] 关键决策点 每个放量节点都是一个"继续 or 回滚"的决策门控。不要跳过任何一步,哪怕之前几轮都顺利通过。历史教训表明:很多事故发生在最后一跳。

三、高级路由规则

Istio VirtualService

Istio 作为 Service Mesh 方案,流量治理能力强大但侵入性也更高。适合已有 K8s + Istio 基础设施的团队。

# 灰度规则:header 携带 canary=true 的用户走 v2
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: order-route
spec:
  hosts: ["order-service"]
  http:
    # 灰度规则
    - match:
        - headers:
            x-canary:
              exact: "true"
      route:
        - destination:
            host: order-service
            subset: v2
          weight: 100
    # 默认:全部走 v1
    - route:
        - destination:
            host: order-service
            subset: v1
          weight: 100

权重路由示例

# 按比例分流
http:
  - route:
      - destination:
          host: order-service
          subset: v1
        weight: 90
      - destination:
          host: order-service
          subset: v2
        weight: 10

网关层 vs Sidecar 层

流量治理可以在两个不同的层级实现,选择取决于团队的基础设施成熟度:

flowchart TD
    subgraph "网关层(中心化)"
        GW["API Gateway<br/>集中管理路由规则"]
        GW --> V1[[v1 实例集群]]
        GW --> V2[[v2 实例集群]]
    end

    subgraph "Sidecar 层(分布式)"
        GW2["API Gateway<br/>只做转发"]
        GW2 --> ProxyV1["Envoy Sidecar<br/>本地执行路由规则"]
        GW2 --> ProxyV2["Envoy Sidecar<br/>本地执行路由规则"]
        ProxyV1 --> ContainerV1[[v1 容器]]
        ProxyV2 --> ContainerV2[[v2 容器]]
    end
维度 网关层治理 Sidecar 层治理
复杂度 配置统一,易维护 需理解 Mesh 概念
性能 单点瓶颈风险 就近处理,开销更低
灵活性 依赖网关插件能力 Istio 支持更丰富的规则
学习曲线 低 高
适用团队 中小型、快速起步 大规模微服务集群

[!note] 选型建议

  • 初创期:直接在网关或应用层做路由分发即可,不必引入 Service Mesh
  • 成长期:当服务数量超过 30+、跨团队协作复杂时,考虑用 Istio 统一管理
  • 混合模式:网关层做简单的按路径/权重分发,Sidecar 层做精细的 header/metadata 路由

四、流量治理的其他维度

除了发布策略,流量治理还包括:

能力 说明 关联文档
熔断降级 下游不可用时自动降级 02-服务治理/06-容错模式
限流 保护上游不因过量请求被打垮 02-服务治理/06-容错模式
重试 对瞬态故障自动恢复 02-服务治理/06-容错模式
黑白名单 IP 级别访问控制 —
A/B Testing 基于用户分组的长期实验 —

五、灰度发布的量化决策依据

[!tip] 必须有可量化的观测指标作为决策依据

不要凭感觉放量,让数据说话:

指标 阈值参考 告警级别
错误率 < 0.1% (v1 baseline 对比) > 1% 立即回滚
P99 延迟 ≤ v1 × 1.1 > v1 × 1.3 暂停放量
CPU/Memory 在 limits 的 70% 以内 > 85% 扩容
下游依赖成功率 > 99.5% < 95% 熔断

灰度监控面板设计要点

一个完整的灰度面板应该能一眼看出新旧版本的差异:

flowchart LR
    subgraph RealTime["实时对比视图"]
        R1["📊 P99 延迟趋势<br/>v1 vs v2 双线对比"]
        R2["🔴 错误率柱状图<br/>区分 HTTP 状态码分类"]
        R3["⚡ QPS 流量分布<br/>按版本分堆叠面积图"]
    end

    subgraph HealthCheck["健康检查"]
        H1["✅ 版本 v1 正常运行<br/>副本数: 10/10"]
        H2["⚠️ 版本 v2 异常<br/>副本数: 2/5 · 失败: 3"]
    end

    RealTime --> Decision["🎯 是否继续放量?"]
    HealthCheck --> Decision

    Decision -- "指标超标" --> Rollback["触发自动回滚"]
    Decision -- "指标正常" --> Expand["推进下一放量阶段"]

    style Rollback fill:#ffebee,color:#000
    style Expand fill:#e8f5e9,color:#000

六、实践 checklist

[!example] 灰度上线前必查清单

  • 旧版本保持至少一个副本不销毁(随时回滚)
  • 灰度期间禁止其他无关变更上线
  • 已配置好 v1 vs v2 的双线对比面板
  • 定义了明确的放量阶段和触发条件(何时扩、何时停)
  • 准备了回滚脚本 / 一键回滚操作
  • 通知了相关干系人(运维、产品、客服)
  • 选择了影响面最小的时间段开始灰度

关联笔记