为什么微服务需要一个网关
单体应用时代,前端只需要对接一个后端地址,鉴权、日志、跨域都在同一个进程里完成。拆成微服务之后,事情立刻变复杂:订单、商品、库存、支付各有各的地址,前端要记住几十个服务;每个服务都要自己写一遍登录校验、限流、日志打印;某个服务响应变慢,整个调用链都被拖住。把这些横切逻辑散落在每一个服务里,是微服务架构最常见的初期陷阱。
API 网关就是站在所有服务最前面的那一层统一入口。它把客户端的请求接进来,按照规则转发给后端的某个服务,并在转发前后统一完成鉴权、限流、日志、协议转换这类事情。对前端来说,整个后端仍然像一个系统;对后端来说,每个服务可以专注业务,不必重复造同样的轮子。
需要强调的是,网关不是银弹。它承担的是与业务无关的横切治理,而不是业务逻辑本身。把订单核心流程塞进网关,只会让它重新变成一个难以维护的"超级单体"。
- 统一入口网关屏蔽后端服务拓扑,前端只对接一个域名,服务增减对客户端透明。
- 路由转发用路径、Header、参数断言把请求映射到具体服务实例。
- 限流熔断保护下游服务不被突发流量压垮,故障时快速失败而不是排队。
- 灰度发布按用户、版本号或比例把流量导向新版本,控制爆炸半径。
网关到底统一了哪些职责
一个生产可用的网关,通常至少承担下面这几类职责,少了任何一类,它都只是一个"反向代理"而已。
- 路由与负载均衡:根据请求路径把流量分给后端服务,并在多个实例之间做轮询、加权或一致性哈希。
- 认证鉴权:统一校验登录令牌,把已登录的用户信息透传给下游,避免每个服务都去解析一次。
- 流量治理:限流、熔断、降级、超时控制,在流量高峰或下游故障时守住系统底线。
- 协议与聚合:对外统一 HTTP 接口,对内可转成 RPC;也可以把多个下游接口聚合成一个,减少前端往返。
- 观测与审计:统一记录访问日志、调用耗时、状态码,是链路追踪与监控的天然采样点。
把这些职责收在网关里,最大的收益是一致性:所有接口走同一套鉴权规则、同一套限流阈值、同一套日志格式,安全策略和监控指标的变更只需要改一处。
主流网关方案怎么选
社区里常见的网关有三类,选型不必追求最新,关键是看团队的技术栈与运维习惯。
| 方案 | 特点 | 适合场景 |
|---|---|---|
| Nginx + OpenResty | 性能极强、配置简单,Lua 可扩展 | 以反向代理和静态分发为主、逻辑较轻 |
| Kong | 基于 OpenResty,插件生态丰富,自带管理面板 | 需要现成的鉴权、限流、日志插件 |
| Spring Cloud Gateway | JVM 体系,与注册中心、配置中心深度集成 | 后端是 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);
}
}
网关治理的直觉是:宁可少给一点数据,也不让一个坏服务把整个系统的线程和连接全部耗光。
统一鉴权与可观测性
在网关做统一鉴权,意味着它先校验 Authorization 里的令牌,确认有效后把用户 id、角色等信息放进请求头再传给下游;下游服务信任网关传来的身份,不再重复校验。这样做的好处是登录态校验只做一次,而且令牌一旦失效,网关这一层立刻能挡住所有未授权请求。需要注意的是,内网服务之间的调用不能仅凭"请求来自网关"就放行,服务间仍要做最小权限校验,防止有人绕过网关直连。
可观测性方面,网关是天然的日志与指标采集点。每一次请求经过网关,都可以记录下路径、状态码、耗时、目标实例,再配合链路追踪的 trace id,把"网关到哪个服务用了多久"整条串起来。线上排查"为什么这个接口慢"时,先看网关的耗时分布,往往能立刻判断是某个下游服务的问题,还是网关自身限流造成的排队。
灰度发布与落地清单
灰度发布(金丝雀发布)让新版本只承接一小部分流量:先给内测用户或 5% 的流量放新版本,观察指标正常后再逐步放大。在网关上实现很简单——再加一条路由断言,按请求头里的版本号或用户标签,把特定流量导向新版本实例,其余流量仍走老版本。出问题时只需撤回这条规则,新版本立刻下线,不必回滚整个发布。
把前面的内容固化成一份上线清单:
- 路由配置统一走注册中心发现,不要写死 IP,实例变动自动感知。
- 每个重要接口都配独立的限流阈值,而不是全平台一刀切。
- 下游服务都要配熔断与降级兜底,超时时间小于前端等待时间。
- 网关自身做多实例部署并放在负载均衡后面,避免它成为单点。
- 灰度规则可秒级撤回,上线后盯紧错误率与 P99 耗时两条曲线。
下一篇会继续深入:当一次业务操作要跨多个服务同时成功时,数据一致性靠什么保证——那就是分布式事务与最终一致性的话题。