为什么微服务需要一个网关

单体应用时代,前端只需要对接一个后端地址,鉴权、日志、跨域都在同一个进程里完成。拆成微服务之后,事情立刻变复杂:订单、商品、库存、支付各有各的地址,前端要记住几十个服务;每个服务都要自己写一遍登录校验、限流、日志打印;某个服务响应变慢,整个调用链都被拖住。把这些横切逻辑散落在每一个服务里,是微服务架构最常见的初期陷阱。

API 网关就是站在所有服务最前面的那一层统一入口。它把客户端的请求接进来,按照规则转发给后端的某个服务,并在转发前后统一完成鉴权、限流、日志、协议转换这类事情。对前端来说,整个后端仍然像一个系统;对后端来说,每个服务可以专注业务,不必重复造同样的轮子。

需要强调的是,网关不是银弹。它承担的是与业务无关的横切治理,而不是业务逻辑本身。把订单核心流程塞进网关,只会让它重新变成一个难以维护的"超级单体"。

本文核心知识点
  • 统一入口网关屏蔽后端服务拓扑,前端只对接一个域名,服务增减对客户端透明。
  • 路由转发用路径、Header、参数断言把请求映射到具体服务实例。
  • 限流熔断保护下游服务不被突发流量压垮,故障时快速失败而不是排队。
  • 灰度发布按用户、版本号或比例把流量导向新版本,控制爆炸半径。
API 网关示意:蓝色渐变背景中央一个发光网关模块,多条光线管道向四周扇形延伸连接多个服务器方块,其中一条管道中途断开代表熔断
网关就是那个发光的中心:所有请求先汇入它,再被分发到四面八方的服务;某条管道断开,就是熔断在起作用。

网关到底统一了哪些职责

一个生产可用的网关,通常至少承担下面这几类职责,少了任何一类,它都只是一个"反向代理"而已。

  • 路由与负载均衡:根据请求路径把流量分给后端服务,并在多个实例之间做轮询、加权或一致性哈希。
  • 认证鉴权:统一校验登录令牌,把已登录的用户信息透传给下游,避免每个服务都去解析一次。
  • 流量治理:限流、熔断、降级、超时控制,在流量高峰或下游故障时守住系统底线。
  • 协议与聚合:对外统一 HTTP 接口,对内可转成 RPC;也可以把多个下游接口聚合成一个,减少前端往返。
  • 观测与审计:统一记录访问日志、调用耗时、状态码,是链路追踪与监控的天然采样点。

把这些职责收在网关里,最大的收益是一致性:所有接口走同一套鉴权规则、同一套限流阈值、同一套日志格式,安全策略和监控指标的变更只需要改一处。

主流网关方案怎么选

社区里常见的网关有三类,选型不必追求最新,关键是看团队的技术栈与运维习惯。

方案特点适合场景
Nginx + OpenResty性能极强、配置简单,Lua 可扩展以反向代理和静态分发为主、逻辑较轻
Kong基于 OpenResty,插件生态丰富,自带管理面板需要现成的鉴权、限流、日志插件
Spring Cloud GatewayJVM 体系,与注册中心、配置中心深度集成后端是 Spring 技术栈、习惯 Java 扩展

经验法则是:Java 微服务团队优先 Spring Cloud Gateway,因为它和服务发现、配置中心在同一套体系里,新增服务几乎零配置;多语言团队或想要开箱即用插件,Kong 更省心;只是做静态资源与简单转发,Nginx 就足够,不必为了"上微服务"而硬套网关。

路由与断言:把请求送到正确的服务

网关的路由模型可以拆成三个部分:断言判断这个请求归谁管,过滤器在转发前后加工请求,目标地址指明转发到哪里。下面是一段 Spring Cloud Gateway 的路由配置,它把 /api/order/** 的请求转发到 order-service,并去掉路径前缀:

spring:
  cloud:
    gateway:
      routes:
        - id: order-route
          uri: lb://order-service
          predicates:
            - Path=/api/order/**
          filters:
            - StripPrefix=1
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10
                redis-rate-limiter.burstCapacity: 20

这里的 lb:// 表示从注册中心里按负载均衡挑一个实例,而不是写死一个 IP。这正是网关与普通 Nginx 反代的区别:服务实例上下线时,网关自动感知,不需要人工改 upstream。断言也不止于路径,还可以按 Host、Header、参数、时间区间匹配,灰度发布就是靠它实现的。

限流:在高峰前先把门守住

限流回答的问题是:"这个用户、这个接口,一秒钟最多让它过多少请求。"它是保护数据库和下游服务的第一道闸门。常见算法有三种,各有适用场景。

算法原理特点
固定窗口每个统计周期计数,超限拒绝实现简单,窗口切换瞬间会有两倍突刺
滑动窗口把周期切细、滚动统计平滑,Redis 计数可实现,社区常用
令牌桶以固定速率往桶里放令牌,请求取走令牌允许一定突发,Spring Cloud Gateway 默认采用

限流要分层设计:网关按用户或 IP 做粗粒度的全局限流,服务内部再按热点接口做细粒度限流。被限流时返回 429 Too Many Requests,并带上 Retry-After 头,告诉客户端稍后重试,而不是让它盲目狂点。

熔断与降级:别让慢服务拖垮全站

限流管的是"太多",熔断管的是"太慢或坏了"。当下游服务连续超时或报错,网关会直接切断对它的调用,快速返回一个兜底结果,而不是让每个请求都干等直到线程池耗尽。这就像家里的保险丝:出问题时主动断开,保护整个电路。

一个典型的熔断状态机有三个状态:关闭(正常放行)、打开(直接拒绝并走降级)、半开(放少量请求试探是否恢复)。降级则是熔断打开时的兜底策略:商品详情接口挂了,就返回缓存里的旧数据或一个友好的提示,而不是整页报错。

// 伪代码:调用库存服务失败时走降级
public InventoryDTO queryStock(String skuId) {
    try {
        return inventoryClient.query(skuId);
    } catch (Exception e) {
        // 库存服务异常,返回缓存兜底并打点告警
        log.warn("库存服务异常,走降级 sku={}", skuId);
        return cache.getStockFallback(skuId);
    }
}
网关治理的直觉是:宁可少给一点数据,也不让一个坏服务把整个系统的线程和连接全部耗光。