想象你第一次去一栋 50 层高的写字楼拜访客户。没有前台,你得像没头苍蝇一样挨家公司敲门,问“你们这里有没有搞 AI 的李经理?”就算找到了,你也得在楼道里干等,保安根本不知道你是什么来路。微服务架构里,“访客”是 App、浏览器、第三方系统,“公司”则是用户服务、订单服务、支付服务这些拆分出来的后端服务。如果让每一个客户端直接去连接成百上千个服务,连接数量会爆炸,鉴权逻辑散落各处,内部服务还会直接暴露在公网,像把公司大门敞开给陌生人。 于是,微服务世界出现了“写字楼前台”——API 网关。它站在所有请求的前面,统一登记(认证鉴权)、指引路线(路由转发)、控制人流(限流熔断)、留下访客记录(日志监控)。Zuul、Spring Cloud Gateway、Kong 是三种风格迥异的“前台系统”:一个守着老式登记簿,一个装了智能闸机,一个替你管起整个园区。本文就用“前台”视角,把网关的工作、原理和落地实践一次讲透。
网关是微服务治理的“守门员”和“总路由”。学会它,你才能设计出安全、高并发、可观测的微服务系统,也是后端工程师走向架构师的关键一步。
目录
可视化演示
展示网关请求处理流水线的接收/路由/过滤/均衡/后端五阶段,Zuul/SCG/Kong性能对比,以及网关作为统一入口的路由分发。
本节配有交互动效(进入视口后自动加载,约 3KB)。
请求流水线 接收→路由→过滤 前置过滤+负载均衡 请求经滤镜链处理后转发到后端服务并返回响应。
一、网关定位:微服务世界的“写字楼前台”
没有前台时,访客如何找到目标公司?他可能得先问门卫,再上一层楼,再问秘书,最后才能见到负责人。微服务里的“访客”是 App、浏览器、第三方系统,“公司”是拆出来的用户服务、订单服务、支付服务。没有网关时,客户端要同时维护与 N 个服务的连接:每个客户端都要知道所有服务地址,都要实现一遍鉴权、超时、重试逻辑。服务一旦变多,维护成本就会像线团一样缠住整个团队;更危险的是,内部服务直接暴露公网,等于把公司大门敞开给陌生人。
网关解决了这个问题:客户端所有请求只发给它,由它负责鉴权、转发、限流和记录。它像写字楼前台一样站在“外部世界”和“内部办公区”之间,内部服务可以随时更换地址,只要前台知道就行。这个位置也叫“流量入口”或“边缘节点”,是微服务治理的第一道防线。
网关最大的价值是让连接关系从“多对多”变成“两段式”。假设有 M 个客户端、N 个后端服务:
如果说微服务是几十家公司共享一栋楼,网关就是那个贴在门口的组织架构图。访客不用记住每家公司的门牌号,只需要问前台,而公司也可以安心把门锁好,只和前台打交道。
- M 个客户端同时访问系统的 App、浏览器、合作方系统数量。
- N 个后端服务微服务架构中拆分出来的服务数量。
- 乘法变加法无网关时每个客户端连每个服务,连接数按 M×N 爆炸;有网关时客户端只连前台一次,服务也只需连前台一次。
二、核心功能:前台的一天
前台的工作看似简单,其实一天下来要干四件事:访客登记、路线指引、人流控制、访客记录。网关的核心功能恰好一一对应。
认证鉴权:前台要检查你是谁、有没有预约。网关通过 Token、API Key、OAuth 等方式验证请求身份,不合规的直接挡在门外。路由转发:前台告诉你“李经理在 23 楼”,网关则根据 URL、Header 等条件,把请求转发到对应的微服务。限流熔断:早高峰电梯挤不下,前台会暂时放慢放行速度;当后端服务已经快扛不住时,网关联动熔断器快速返回兜底响应,而不是让更多请求压垮下游。日志监控:每一位访客都有记录,出问题才能回溯。网关会记录请求耗时、状态码、错误信息,并上报到监控系统。
以最常见的限流为例,网关里常用“令牌桶算法”。想象前台有一个桶,每隔一段时间自动往桶里放一张“通行券”,请求来了必须拿一张券才能进;桶空了就原地等待或直接拒绝。
前台不只是“发号牌”,它是在用一套规则平衡体验和安全。没有这套功能的网关,充其量只是个转发器,挡不住洪峰,也留不下线索。
- 桶容量 C前台一次性最多能放的通行券数,决定了瞬时容忍多少突发请求。
- 补充速率 R每分钟/每秒往桶里新增多少张通行券,控制了长期平均流量。
- 突发受限即使瞬间涌来很多人,最多也只能放走 C 个,其余请求需等待或拒绝。
三、Zuul 原理:老式前台
如果给这个前台配上电话,Zuul 1 就是那个“一个接线员对应一通电话”的旧式接待台。只要这个接线员还在跟 A 访客说话,B 访客就得在旁边排队等,因为 Zuul 1 使用传统的 Java Servlet 阻塞模型:一个请求从进入网关到响应返回,会一直占住一个线程。
Zuul 的过滤器链像一套标准接待流程:pre 是访客登记和安检,routing 是带着访客上电梯落实到具体公司,post 是送客出门收拾现场,error 是电梯出故障时立刻广播安抚。Netflix 开源 Zuul 后,Spring Cloud Netflix 将它接入微服务体系,所以很多老项目里都能看到它的身影。
阻塞模型的核心约束在于线程是有限资源。当请求排队越来越长时:
Zuul 不是不能完成接待工作,只是它“一人一线”的模式在高峰期容易手忙脚乱。对于并发要求不极端、团队熟悉 Spring Cloud Netflix 的存量项目,它依然是一个可用的前台;但如果要撑十万人同时到访,就该考虑让更现代的“智能闸机”上场。
- 排队时间 W请求在 Zuul 线程池外等待的时长,反映当前网关负载。
- 服务时间 S网关真正执行过滤器链、转发请求、接收响应所花的时间。
- 响应时间组成阻塞模型下,只要线程池打满,响应时间就会因为排队时间无限上涨。
四、Spring Cloud Gateway:异步智能闸机
新一代写字楼不再让每个接待员一对一服务,而是装上智能闸机。访客扫码验证后闸机自动打开,多个人可以同时通过,接待员只需要在屏幕前处理异常。Spring Cloud Gateway 就是这样一台智能闸机:它基于 Spring WebFlux 和 Reactor Netty,使用响应式、非阻塞模型,少量线程就能管理海量并发请求。
Spring Cloud Gateway 中最重要的三个概念可以记成“路线、条件、关卡”:
- Route(路由):访客最终要去几楼几号房。
- Predicate(谓词):什么条件下执行这条路线,比如看到“穿工牌的人”走员工通道。
- Filter(过滤器):进门前后的各种关卡,比如扫码、过安检、记录访客。
网关启动时,所有路由谓词按顺序匹配请求,找到第一条满足条件的路由后,就交给该路由的过滤器链执行。WebFlux 模型下的线程数不必像 Zuul 那样按请求数扩张,而是趋于 CPU 核心数:
简单说,Zuul 是每个访客配一名接待员,而 Spring Cloud Gateway 是少数几个调度员盯着几十个闸机口,谁卡住了就去处理谁。它更适合新建的 Spring Cloud 微服务项目,也让“异步”成为微服务网关的主流选项。
- CPU 核心数物理机或容器可用的计算核心,决定了真正能并行计算的路数。
- 等待时间 W请求在等待下游 IO、数据库响应上花的时间,这部分不消耗 CPU。
- 计算时间 CCPU 真正做运算、序列化、解析的时间。
- 一比一配线程等待占比越高,传统同步模型越浪费线程;WebFlux 用少量线程靠事件回调覆盖大量等待。
五、Kong:园区级统一物业平台
当业务大到不只一栋楼,而是需要管理整个园区时,单栋楼的前台就不够用了。Kong 更像园区级的“统一物业平台”:它不替某一栋楼守门,而是站在所有公司共享的园区入口,通过一套可插拔的规则统一管理来访者。
Kong 的内部底座是 Nginx + OpenResty。Nginx 本身就是高效的反向代理和负载均衡器,OpenResty 则把 Lua 脚本嵌入 Nginx,让网关能力通过“插件”随意扩展。你可以加一个限流插件,像大门口增加刷卡闸机;加一个鉴权插件,像保安增加人脸识别;加一个日志插件,像前台自动登记到访记录。这些插件不只能全局生效,还可以绑定到某个“服务”或“路由”上,做到不同区域不同规则。
Kong 支持集群部署,多个节点共同服务,配置可以声明式导入导出。集群部署的价值是消除单点故障,用可用性公式可以直观看到:
Kong 适合那种服务规模特别大、希望用插件生态快速扩展、并且不想和具体开发语言绑太死的团队。它不是来打败 Zuul 或 Spring Cloud Gateway 的,而是用“园区物业”的方式,把网关从代码组件升级为独立基础设施。
- 单实例可用性 a一台网关不出故障的概率,比如 0.99。
- n 台实例网关集群的节点数量。
- 整体可用性所有实例同时故障的概率是 (1-a)^n,反过来说至少一台存活就是集群可用概率。
六、性能优化:让大堂在高峰期不拥堵
高峰期写字楼怎么避免拥堵?无外乎三招:多开几个闸机口,让每个访客在大堂少停留,排队太久就引导去备用通道。网关性能优化也是同样的思路。
第一是水平扩容。网关无状态设计后,前面加负载均衡,后面挂多个网关实例,就像大厅同时开十个闸机口。第二是让大堂动作更快。网关里做数据压缩、连接复用、缓存静态鉴权结果,减少每个请求的“处理工时”,访客自然走得快。第三是管住排队。给每个请求设置超时,避免一个慢服务拖垮整个前台;对失败请求做有限重试,而不是无限重试导致雪上加霜。
性能优化时往往用一个简单公式衡量网关吞吐能力:
一个配置良好的网关,扩容后 QPS 应该接近线性增长;如果扩容不见效,多半是某个过滤器把状态塞进了本地内存,或者下游数据库成了隐藏瓶颈。记住,前台想要快,不只是人多就行,还要让每个人办事更利索。
- 并发连接数 C同一时刻在网关内部处于活动状态的请求数量。
- 平均响应时间 T每个请求从进网关到返回结果的平均耗时。
- 吞吐量计算想提高 QPS,要么提高并发承载量,要么降低每个请求的耗时。
七、故障应对:前台失灵怎么办
如果前台突然停电,访客全部堵在一楼,整个写字楼都会瘫痪。网关作为统一入口,既是价值点,也是风险点:一旦网关挂了,所有微服务都进不去。所以故障应对的核心目标是:网关不能轻易挂,挂了也能快速恢复、快速排查。
首先要有雪崩防护。网关调用下游服务时设置超时和熔断,当某个服务频繁出错,熔断器直接打开,请求快速失败而不是继续堆积。其次是路由失效处理。如果某条路由突然报错,网关应该能快速下线该路由,或者自动切换到备份服务,避免用户一直被导向错误地址。再次是鉴权瓶颈排查。很多团队把鉴权放在网关上,导致网关承担大量计算;如果 QPS 上不去,优先检查 Redis 连接、Token 解析和加密算法是不是热点。
所有故障最终都要靠数据说话。跟踪链路里关键指标就是成功率:
前台偶尔也会处理不过来,但好的物业早有预案:备用闸机、应急通道、对讲机通话。网关也一样,把超时、熔断、限流、监控都配好,即使某个服务倒下,整个系统依然能对访客说一句:“别急,这边请。”
- 失败数 F包括超时、5xx、熔断拒绝等各种失败请求的数量。
- 总请求数 N网关注入的完整请求总数。
- 成功率计算失败比例越高,成功率越低,越需要打开链路追踪看具体在哪一环出错。
AI 应用场景
场景一:微服务迁移时的“新旧分流”入口
阶段:微服务治理 / 灰度发布
解决的问题:一个老系统由单体架构拆成微服务时,流量不能一夜之间全部切到新系统,否则风险太大。传统做法是改 DNS 或加 if-else 硬编码,既笨重又容易出错。
具体案例:一家电商公司把订单服务拆成新老两套。使用 Spring Cloud Gateway 的路由谓词,根据请求 Header 中的 version=v2 将 10% 的流量路由到新订单服务,其余 90% 仍走老服务。验证稳定后逐步调高比例,实现平滑迁移。这就像前台根据访客胸牌颜色,把 VIP 请到新电梯,普通访客走旧电梯,慢慢切换。
场景二:电商大促的限流熔断“保安”
阶段:流量治理 / 高并发保障
解决的问题:大促瞬间涌入的流量是平时的几十倍,如果全部打到订单服务,数据库一定会被打垮。传统做法是服务端各自做保护,缺少统一入口控制。
具体案例:某电商平台在 Kong 上启用 Rate Limiting 插件和熔断策略,对每个用户、每个 IP 设置每秒调用上限。当订单服务响应时间超过阈值,网关立即进入熔断状态,返回“系统繁忙”而非继续转发。这个做法就像小区物业在门口限流,里面的人还没消化完,外面的人先在外面等。
场景三:多团队 API 治理的“审计前台”
阶段:可观测性 / 安全合规
解决的问题:微服务由多个团队分别开发,如果每个团队都自己实现鉴权、审计、日志,风格不一且容易遗漏,审计时也无法统一交代。
具体案例:某金融科技公司在 Zuul 网关中编写统一的 pre 过滤器,统一解析 Token、写入审计日志、生成 TraceId。所有服务无需重复开发,管理层可以在监控后台看到“谁在什么时间调用了哪个接口”。这就像大楼统一使用一套访客登记系统,不需要每家公司在门口再单独放一个登记本。
Python 演示
# -*- coding: utf-8 -*-import timefrom dataclasses import dataclass @dataclassclass Request: path: str token: str = "" status: int = 200 class Gateway: def __init__(self, capacity=5, refill_rate=2): self.capacity = capacity self.tokens = capacity self.refill_rate = refill_rate self.last_refill = time.time() self.route_map = { "/user": "user-service", "/order": "order-service", "/pay": "pay-service", } def auth(self, req): if req.token != "ok": req.status = 401 return False return True def route(self, req): if req.path not in self.route_map: req.status = 404 return None return self.route_map[req.path] def allow(self): now = time.time() self.tokens = min( self.capacity, self.tokens + (now - self.last_refill) * self.refill_rate ) self.last_refill = now if self.tokens >= 1: self.tokens -= 1 return True return False def process(self, req): if not self.auth(req): return "未通过鉴权, 请求被拒绝" service = self.route(req) if service is None: return "路由失败, 找不到目标服务" if not self.allow(): return "触发限流, 请稍后再试" return "已路由到 " + service if __name__ == "__main__": gw = Gateway() tasks = [] for _ in range(8): tasks.append(Request(path="/user", token="ok")) tasks.append(Request(path="/pay", token="bad")) tasks.append(Request(path="/x", token="ok")) for req in tasks: print(gw.process(req))
def process(self, req)网关处理入口,串联鉴权、路由、限流三个步骤,就像前台按流程接待访客。if not self.auth(req): return "未通过鉴权, 请求被拒绝"模拟 pre 过滤器:Token 不对直接拒之门外。service = self.route(req)模拟路由转发:根据请求路径找到对应的后端服务名。if req.path not in self.route_map路由失败时返回 404,相当于访客要找的公司根本不在楼里。self.tokens = min(self.capacity, self.tokens + (now - self.last_refill) * self.refill_rate)令牌桶核心逻辑:按时间补充令牌,但不超过桶容量。if self.tokens >= 1: self.tokens -= 1每放行一个请求就消耗一张“通行券”。if not self.allow(): return "触发限流, 请稍后再试"桶空时拒绝请求,防止洪峰打垮后端服务。
常见误区
误区我以为所有请求都从网关进来,网关鉴权成功后,后面的微服务就可以完全信任了,服务之间直接调用没问题。
正解小区保安能帮你看住陌生人,但没法保证你家保险柜绝对安全。微服务之间经常互相调用,比如订单服务查询用户服务。如果服务间默认信任,一旦某个服务被攻破,攻击者就能横向跳到其他服务。正确的做法是服务间仍使用内部 token、mTLS 或服务网格做身份认证,网关只解决“外部到内部”的第一道门。
为何常见:人们容易从“外部流量”视角看系统,忽略了内部调用链同样可能被恶意利用。
误区既然网关的过滤器这么灵活,我可以把数据聚合、页面组装、业务校验都放在网关里,这样所有服务都能复用。
正解前台可以帮你找人、登记、控流,但不会替你签合同、算工资。网关适合承载横切关注点,比如鉴权、限流、日志、超时;业务逻辑和数据聚合一旦堆进网关,网关就从轻量闸机变成“巨无霸”,改一行代码都可能引起全局故障,部署和排障都会变得非常痛苦。
为何常见:因为过滤器链看起来像中间件,写起来很顺手,容易让人误以为网关是理想的“公共代码池”。
误区我看到 Spring Cloud Gateway 性能测试比 Zuul 高很多,就觉得所有项目都应该直接换掉 Zuul,选型只看性能。
正解Spring Cloud Gateway 的异步模型确实在高并发下吞吐更强,但“性能更好”不等于“综合最好”。如果团队深度使用 Spring Cloud Netflix,现有的自定义 Zuul 过滤器已经成熟,贸然迁移成本很大。而且 Spring Cloud Gateway 基于 WebFlux,习惯了 Spring MVC 的开发团队需要重新熟悉响应式编程模型。选型要结合团队、存量代码、运维能力综合考虑。
为何常见:将“技术更新”和“性能更优”简单等价于“选型唯一解”,忽略了技术栈迁移成本。
误区我以为 Kong 就是给 Nginx 加了几个扩展,最多算反向代理,跟 Spring Cloud 体系里的网关根本不是一回事。
正解Kong 不是简单的 Nginx 插件,而是基于 OpenResty 构建的完整 API 网关平台。它有 Service、Route、Consumer 等抽象,有丰富的插件生态,支持限流、熔断、鉴权、转换、可观测性。它不绑定 Java 技术栈,非常适合在云原生环境里作为独立部署的边缘网关,很多大规模 API 管理体系都是用 Kong 做的。
为何常见:因为 Kong 底层默认依赖 Nginx,容易让人把它和“Web 服务器”混为一谈。
误区我只要把网关多部署几个实例,前面加个负载均衡,就不会再发生“网关挂了全部服务不可用”的情况。
正解多放几个前台确实能避免一个人请假导致没人接待,但如果没有配置同步、状态共享、健康检查,集群照样会乱套。网关必须设计成无状态,配置通过 GitOps 或声明式方式统一下发;如果每个节点都保存本地缓存或内存态限额,流量一分布就会数据不一致。集群只是高可用的一半,另一半是管理上的标准化。
为何常见:把“高可用”简单理解为“多复制几份”,忽略了分布式系统中的配置一致性和状态同步问题。
面试题
Q1. 在微服务架构中,API 网关最核心的价值是什么?
- A.减少客户端与服务端的连接数← 正确答案
- B.替代数据库缓存加速查询
- C.让后端服务永远不会故障
- D.只负责前端静态资源分发
答案:A。网关把客户端与 N 个服务的多对多连接变成客户端连网关、网关连服务两段式关系,连接数从乘法级降为加法级,所以选 A。数据库缓存、故障免疫、静态资源服务都不是网关的首要职责。
Q2. Zuul 1 默认基于哪种网络模型处理请求?
- A.Servlet 阻塞式模型← 正确答案
- B.Spring 响应式模型
- C.Nginx 事件驱动模型
- D.Netty 协程异步模型
答案:A。Zuul 1 基于 Java Servlet,一个请求从进到出会一直占用一个线程,属于传统阻塞模型。Spring Cloud Gateway 才采用响应式模型,Nginx 是事件驱动但不是 Zuul 的底层模型。
Q3. Spring Cloud Gateway 底层直接围绕哪个框架构建?
- A.Spring MVC 模型
- B.Spring WebFlux 模型← 正确答案
- C.Apache Dubbo 模型
- D.JDBC 数据访问模型
答案:B。Spring Cloud Gateway 基于 Spring WebFlux 和 Reactor Netty,使用非阻塞响应式编程。Spring MVC 是传统同步框架,Dubbo 是 RPC 框架,JDBC 是数据库访问技术,都和网关底层模型无关。
Q4. Zuul 过滤器链中,真正把请求转发给后端微服务的是哪一类过滤器?
- A.pre 前置过滤器
- B.routing 路由过滤器← 正确答案
- C.post 后置过滤器
- D.error 错误过滤器
答案:B。Zuul 四大过滤器分工明确:pre 做鉴权和参数预处理,routing 负责把请求发到真实服务,post 处理响应,error 兜底异常。就像前台先登记、再带路、再送客、再处理突发状况,所以转发发生在 routing 阶段。
Q5. 一个令牌桶容量为 10,每秒补充 2 个令牌,那么它能支持的最大突发请求数是多少?
- A.每秒最多放行 2 个请求
- B.突发最多放行 5 个请求
- C.突发最多放行 10 个请求← 正确答案
- D.突发最多放行 20 个请求
答案:C。令牌桶的容量决定了最大突发量,桶里有 10 张通行券,所以一瞬间最多能放行 10 个请求。补充速率 2 个/秒控制的是长期平均速率,不影响突发上限,因此选 C。
Q6. Kong 的核心构建于哪两种开源技术之上?
- A.Node.js 事件平台与 Express
- B.Spring WebFlux 与 Reactor
- C.Nginx 与 OpenResty← 正确答案
- D.Netty 与 ZooKeeper
答案:C。Kong 在 Nginx 基础上引入 OpenResty,通过 Lua 脚本扩展出丰富的 API 网关能力。它不依赖 Node.js、Spring 或 Netty,因此选 C。
Q7. Spring Cloud Gateway 中,一条可用的路由配置由哪三个核心概念共同组成?
- A.Route, Predicate, Filter← 正确答案
- B.Bean, Service, Repository
- C.Gateway, Zuul, Kong
- D.Request, Response, Exception
答案:A。Route 定义转发目标,Predicate 定义匹配条件,Filter 定义请求经过时的处理增强,三者缺一不可。Bean/Service/Repository 是后端工程分层概念,Request/Response 是 HTTP 消息对象,都不是网关路由模型的核心。
Q8. 以下哪些属于网关使用中的“反模式”?
- A.把业务逻辑塞进过滤器← 正确答案
- B.在网关做数据聚合计算← 正确答案
- C.只做轻量路由转发职责
- D.把网关当缓存扛住流量← 正确答案
答案:ABD。网关适合横切关注点,但不适合承载业务逻辑和数据聚合,否则会变得臃肿而难以维护。把网关当缓存更是错误,等于把状态和压力都集中到入口。选项 C 是网关的正确姿势,不应选。
Q9. 要构建高可用的网关集群,以下哪些做法是必要的?
- A.多实例横向扩展← 正确答案
- B.前置负载均衡设备← 正确答案
- C.网关设计成无状态← 正确答案
- D.把状态缓存在本地内存
答案:ABC。多实例、前置负载均衡、无状态设计是网关集群高可用的三根支柱。本地内存缓存会让每个网关实例持有的状态不一致,无法直接替换故障节点,属于错误做法。
Q10. 关于 Kong 的插件体系,下列说法正确的是哪些?
- A.插件可热插拔扩展← 正确答案
- B.支持声明式配置管理← 正确答案
- C.支持全局与服务级作用域← 正确答案
- D.扩展必须修改核心代码
答案:ABC。Kong 的插件通过 Lua 脚本嵌入 OpenResty,可以在不修改网关核心代码的前提下热插拔,并支持配置导入导出、全局或绑定具体 Service/Route 使用。选项 D 与插件机制完全相反。