第四章:API网关与流量治理

说实话,网关这东西,我刚入行时觉得它就是个“转发器”。直到有一次线上事故——某个接口被爬虫刷爆,整个集群都挂了。老板问我:“你不是说网关能挡吗?”我哑口无言。从那以后,我才真正开始研究网关到底该干什么。

今天这一章,咱们就把网关的核心功能、限流算法、熔断降级、灰度发布这些硬骨头啃下来。我保证,讲得接地气,但深度不减。

4.1 网关的核心功能

网关不是简单的反向代理。它更像是系统的“前厅经理”——所有请求都得先过它这一关。

我个人习惯把网关功能分成三类:

  • 路由与转发:根据请求路径、Header、参数,把请求送到正确的后端服务。比如 /api/user/** 转到用户服务,/api/order/** 转到订单服务。
  • 安全与认证:统一做鉴权、验签、IP黑白名单。我见过很多团队在每个微服务里重复写登录校验,其实网关做一次就够了。
  • 流量治理:限流、熔断、降级、灰度。这是本章的重点,也是网关最值钱的能力。

核心观点:网关是流量的“总闸门”,所有治理策略都应该在这里统一配置,而不是散落在各个服务里。

你想想看,如果每个服务自己搞限流,那限流阈值怎么定?服务A限100,服务B限200,但网关入口的流量是叠加的,根本算不清。所以,流量治理必须集中在网关层。

4.2 限流算法:令牌桶 vs 漏桶

限流是网关最基础的能力。但算法选不对,效果天差地别。我踩过这个坑,跟大家聊聊。

4.2.1 漏桶算法

漏桶算法,说白了就是一个固定大小的桶,水(请求)以恒定速率流出。如果桶满了,新来的水就溢出(被拒绝)。

它的特点是:输出速率平滑。不管前端怎么突发,后端看到的流量都是均匀的。

但问题也很明显——无法应对突发流量。比如秒杀场景,瞬间涌入1000个请求,漏桶只能慢慢放,用户体验极差。

我曾经在一个直播弹幕系统里用了漏桶,结果用户发弹幕要等好几秒才显示。后来才明白,弹幕场景需要一定的突发能力,漏桶不合适。

4.2.2 令牌桶算法

令牌桶就灵活多了。它有一个桶,里面放令牌,以固定速率生成。请求来了,先拿令牌,拿到就放行,拿不到就等或拒绝。

关键区别:令牌桶允许一定程度的突发。因为桶里可以积累令牌,最多攒到桶容量。比如桶容量100,生成速率10个/秒,如果空闲了10秒,桶里就有100个令牌。这时候突然来100个请求,可以全部放行。

// 伪代码示例:令牌桶
class TokenBucket {
    int capacity;      // 桶容量
    int tokens;        // 当前令牌数
    long lastRefill;   // 上次补充时间
    double rate;       // 令牌生成速率(个/秒)

    boolean tryAcquire() {
        refill(); // 补充令牌
        if (tokens > 0) {
            tokens--;
            return true;
        }
        return false;
    }

    void refill() {
        long now = System.currentTimeMillis();
        double elapsed = (now - lastRefill) / 1000.0;
        int newTokens = (int)(elapsed * rate);
        tokens = Math.min(capacity, tokens + newTokens);
        lastRefill = now;
    }
}

我的建议:大部分业务场景用令牌桶就够了。漏桶更适合那些对抖动零容忍的场景,比如数据库写入限流。

4.3 熔断降级

限流是防患于未然,熔断是亡羊补牢。当某个后端服务已经出问题了,网关必须主动切断流量,防止雪崩。

我记得有一次,订单服务因为数据库慢查询,响应时间从10ms飙到10秒。结果所有请求都卡在订单服务上,线程池被打满,网关也跟着挂了。这就是典型的雪崩效应。

熔断器的状态机很简单:

状态 含义 触发条件
CLOSED(关闭) 正常,请求放行 初始状态
OPEN(打开) 熔断,请求直接拒绝 错误率超过阈值(如50%)
HALF_OPEN(半开) 试探性放行少量请求 熔断一段时间后自动进入

降级是熔断后的“兜底”策略。比如订单服务熔断了,网关可以返回一个缓存数据,或者直接提示“系统繁忙,请稍后再试”。说白了,就是有损服务——宁可给用户一个降级响应,也不能让整个系统崩溃。

避坑指南:熔断阈值别设太死。我曾经设了50%错误率熔断,结果某个接口偶尔超时,但整体可用,熔断反而引发了更大范围的不可用。建议结合滑动窗口统计,比如最近10秒内的错误率。

4.4 灰度发布

灰度发布,也叫金丝雀发布。新版本先让一小部分用户用,没问题再全量推。这比蓝绿部署更省钱,也更安全。

网关做灰度,核心就是流量路由策略。常见的策略有:

  • 按用户ID哈希:比如 user_id % 100 < 5 的走灰度版本
  • 按请求Header:比如 Header 里带 X-Canary: true 的走灰度
  • 按地域/IP:比如只让北京地区的用户先体验

我个人习惯用权重路由。在网关配置里,给新版本分配5%的权重,老版本95%。观察一段时间,如果新版本无异常,逐步提升权重到100%。

// 灰度路由伪代码
String routeVersion(String userId) {
    int hash = userId.hashCode() & 0x7FFFFFFF; // 取正
    int bucket = hash % 100;
    if (bucket < 5) {
        return "v2"; // 灰度版本
    } else {
        return "v1"; // 稳定版本
    }
}

注意:灰度发布一定要有回滚能力。我见过一个团队灰度上线后,新版本有内存泄漏,但因为没配回滚策略,只能紧急重启所有节点。嗯,那场面,挺狼狈的。

4.5 知识体系总览

下面这张图,是我自己总结的网关流量治理知识体系。你可以把它当成一个检查清单——看看你的网关还缺什么。

API网关流量治理 限流算法 • 令牌桶:允许突发 • 漏桶:输出平滑 • 滑动窗口:精确控制 熔断降级 • 熔断状态机:CLOSED/OPEN/HALF_OPEN • 降级策略:缓存/默认值/错误提示 • 滑动窗口统计错误率 灰度发布 • 按用户ID哈希 • 按Header/地域 • 权重路由 网关核心功能 • 路由转发:路径/Header/参数匹配 • 安全认证:JWT/OAuth2/IP黑白名单 • 流量治理:限流+熔断+灰度 核心原则:集中治理,分层防护,有损服务

这张图把网关流量治理拆成了四个维度:限流、熔断降级、灰度发布,以及底层的核心功能。你可以在实际项目中对照着看,哪个维度还没做到位。

最后说一句:网关不是银弹。它解决的是流量入口的问题,但业务逻辑的健壮性还得靠服务自身。别把所有希望都压在网关上,该做的限流、熔断,服务内部也得有。

好了,这一章就到这里。流量治理是个实践性很强的话题,建议你回去看看自己项目的网关配置,说不定能发现不少优化点。

可可精品资料库