网关是怎么当"门卫"的?

上篇讲了负载均衡------它解决的是"请求怎么分到多台服务器"。但微服务时代,问题升级了:几十个服务各管一摊,请求进来先找谁?谁有资格进?超载了怎么办?

这就需要API网关 。如果把后端服务比作一栋大楼里的各个科室,那网关就是大楼门口的门卫------所有进出都得经过它,由它来决定放行、拦截还是引导到对应的科室。


原文地址

墨渊书肆/网关是怎么当"门卫"的?


为什么需要网关

单体架构不需要网关

以前一个应用打成一个包,部署在一台服务器上,用户请求直接打到这个服务上,简单直接。没有中间层,也没有中间层的烦恼。

微服务架构的痛点

拆成几十个微服务后,事情变复杂了:

md 复制代码
前端要调的接口:
  /api/user/info        → 用户服务(10.0.0.1:8080)
  /api/order/list       → 订单服务(10.0.0.2:8080)
  /api/product/detail   → 商品服务(10.0.0.3:8080)
  /api/pay/create       → 支付服务(10.0.0.4:8080)
  ...

前端需要知道每个服务的IP地址和端口。一旦某个服务扩容、缩容或迁移,所有前端都要跟着改代码。

而且还有一堆横切问题:鉴权逻辑要在每个服务写一遍、限流规则分散在各处难以统一调整、日志监控没有统一入口、协议格式各不相同...

网关就是来解决这些问题的------它是所有请求的统一入口,也是整个系统的第一道防线。

但也要说清楚:网关不是免费的午餐。它带来了解决上述问题的能力,同时也引入了新的代价:

  • 额外的一跳延迟:每个请求多经过一层,通常增加1-5ms
  • 单点风险:所有流量都经过这里,挂了就是全站挂
  • 复杂度增加:多了一层就要多运维、多部署、多排查问题

所以要不要上网关,取决于你的系统规模。两三个服务直接调就行;到了十几个甚至几十个服务,网关基本是必选项。


核心职责一:路由转发

门卫的第一项工作:认识路

门卫得知道财务科在3楼、人事科在5楼、前台在1楼。网关也一样------根据请求特征把流量分发到对应的后端服务。

路由匹配方式不止一种:

匹配方式 示例 适用场景
路径匹配 /api/users/* → 用户服务 最常用,RESTful风格
Header匹配 X-Service: order → 订单服务 灰度发布、A/B测试
Query参数 ?version=v2 → 新版本服务 功能开关、灰度
权重分配 A服务80% / B服务20% 金丝雀发布

为什么不在前端直连后端?

直连看起来省事,但问题不少:内部服务IP暴露给外部安全风险高、无法统一管控入口、服务变更时前端必须配合改代码甚至发版。

通过网关做一层抽象,后端服务扩容缩容迁移,前端完全无感知。代价是多1-5ms延迟,这个 trade-off 在绝大多数场景下都很划算。

配合服务发现效果更好:

硬编码IP的方式已经过时了。现在主流做法是网关 + 服务注册中心(如Nacos、Consul、Eureka)配合:

md 复制代码
服务启动 → 注册到注册中心(我是订单服务,IP是10.0.0.2:8080)
网关需要路由 → 从注册中心拉取服务列表 → 动态转发
服务下线 → 从注册中心注销 → 网关自动感知不再转发

这样服务上下线对网关也是透明的,不需要手动改配置。


核心职责二:统一认证与授权

门卫的第二项工作:查证件

进门先看证件,没证件不让进,证件过期也不行。VIP区域还要额外检查权限等级。

典型鉴权流程:

md 复制代码
请求到达网关
    ↓
从Header/Cookie中提取Token(JWT或SessionID)
    ↓
验证Token有效性(签名是否正确?是否过期?)
    ↓
┌── 有效 ──→ 解析出用户信息(userID、角色等)
│              ↓
│         附加到请求Header(X-User-ID, X-User-Role)
│              ↓
│         转发到后端业务服务
│
└── 无效 ──→ 返回 401 Unauthorized

集中鉴权 vs 各服务自己鉴权:

方案 优点 缺点
每个服务自己鉴权 解耦彻底,服务可独立部署 重复代码、规则改了要到处改、容易遗漏导致安全漏洞
网关统一鉴权 一处修改全局生效、安全策略集中管理、业务服务不用关心认证逻辑 网关压力增大、成为潜在瓶颈

实际中的最佳实践是分层处理

  • 网关层做粗粒度鉴权:Token有没有?是不是合法的?有没有基础权限?
  • 业务服务层做细粒度判断:这笔订单是不是你的?你有权限删除这条评论吗?

这样既避免了在每个服务重复写认证代码,又不会把所有判断逻辑都堆到网关上。


核心职责三:限流与熔断

门卫的第三项工作:控制人流

高峰期门口要限流排队,某个科室出了状况要暂时封闭通道。网关也一样------保护后端服务不被突发流量冲垮。

限流算法怎么选:

算法 原理 允许突发? 实现复杂度 典型场景
固定窗口 每秒/每分钟计数器,到期清零 边界处可能突发2倍 简单API限流
滑动窗口 时间窗口滑动计数,更平滑 基本平滑 精确控制
令牌桶 匀速产生令牌,有令牌才能通过 允许短时突发 对外接口(提升用户体验)
漏桶 请求入桶,匀速流出 不允许 对内调用(严格保护下游)

选型思路: 对外面向用户的接口用令牌桶------允许一定突发流量,用户体验更好(比如抢购时不能因为刚好卡在边界就被拒);对内部服务间的调用用漏桶或固定窗口------严格限制,保护下游不被压垮。

为什么在网关统一限流而不是每个服务自己限?

如果每个服务各设各的阈值,整体效果不可控------A限100 B限50 C限80,到底系统能扛多少没人说得清。在网关一处配置全局生效,后面所有服务都在保护范围内。

当然,对于超大流量的系统,光靠网关限流不够,还会配合客户端限流(验证码、滑块)、CDN边缘限流等多层手段。

熔断机制:

限流是"人太多时控制入场",熔断是"某个地方着火了赶紧封路"。

具体原理:网关持续统计每个后端服务的错误率/响应时间。当某个服务错误率超过阈值(比如50%的请求失败且持续10秒),触发熔断------后续请求不再转发到该服务,直接返回降级响应(比如返回缓存数据或默认值)。之后每隔一段时间尝试放一个请求过去探测(半开状态),如果恢复正常就关闭熔断恢复流量。

这跟家里电路保险丝一个道理:与其让故障蔓延拖垮整个系统,不如主动切断,保住大局。


核心职责四:协议转换

门卫的第四项工作:翻译

有时候来的客人说的是外语,门卫得帮忙翻译成内部能听懂的语言。

最常见的场景:HTTP ↔ gRPC

javascript 复制代码
浏览器(只支持 HTTP/1.1 + JSON 文本)
    ↓
  API网关(协议翻译层)
    ↓
内部微服务(HTTP/2 + gRPC + Protobuf 二进制)

为什么要这么折腾?直接都用HTTP不行吗?

行,但效率差不少。对比一下:

维度 REST (HTTP/1.1 + JSON) gRPC (HTTP/2 + Protobuf)
数据格式 文本JSON,字段名重复 二进制Protobuf,紧凑编码
传输体积 大(JSON冗余多) 小(通常只有JSON的1/3~1/5)
解析速度 慢(文本解析) 快(直接反序列化)
连接模型 每个请求一个连接(HTTP/1.1) 多路复用(HTTP/2)

综合下来,内部服务间用gRPC比REST快3-5倍不是夸张。

但问题是浏览器不支持gRPC ------浏览器只能发 HTTP 请求、只能解析 JSON 文本。所以网关承担翻译工作:对外暴露标准HTTP接口,对内转成 gRPC 调用。前端开发体验不变,后端享受高性能。

除了 gRPC,网关还可能做其他协议转换:GraphQL ↔ RESTWebSocket ↔ HTTP长轮询Thrift ↔ REST等,取决于你的技术栈。


核心职责五:日志与监控

门卫的第五项工作:登记访客

几点来的、找谁、待了多久、有没有异常情况------这些信息全记下来,方便事后追溯和分析。

作为唯一入口,网关天然适合做全链路数据采集:

  • 基础信息来源IPUser-Agent请求路径HTTP方法
  • 性能数据响应时间(RT)响应状态码响应体大小
  • 关联追踪 :生成或传递TraceID(用于在多个服务之间串联一次完整请求)

这些数据汇入ELK Stack(日志分析)、Prometheus+Grafana(监控大盘)、SkyWalking/Jaeger(分布式链路追踪)。运维人员可以在一个地方看到全局流量状况,出问题时也能快速定位是哪个环节慢了或者报错了。


BFF:Backend For Frontend

问题

一个电商商品详情页,前端可能要调6-7个后端接口才能拼出完整页面。移动端网络条件差,串行调用6次延迟叠加明显;不同端(Web/App/小程序)需要的字段还不一样------App端不需要Web端的那些营销模块数据,小程序又要比App更精简。

解决方案

BFF(Backend For Frontend)服务层位于网关之后、微服务之前,专门为特定类型的前端聚合数据:

md 复制代码
Web端请求     → BFF-Web     → 并行调用6个微服务 → 返回完整JSON
App端请求     → BFF-App     → 同样6个服务      → 只返回必要字段(省流量)
小程序请求    → BFF-MiniApp → 同样6个服务      → 极简数据

BFF的优缺点:

优点 缺点
前端只调一个接口,代码简洁 多了一层,维护成本增加
按需裁剪返回数据,节省带宽 BFF本身也可能成为性能瓶颈
不同端的数据差异在后端消化 和业务服务的边界容易模糊
后端服务变更不影响前端 要额外部署和运维BFF服务

什么时候该用BFF?

  • 前端页面需要聚合3个以上后端服务的数据 → 值得考虑
  • 存在Web/App/小程序等多个端且数据需求差异大 → 强烈推荐
  • 前端只调一两个接口就能搞定 → 没必要,直接走网关就行

另外提一句,GraphQL可以作为BFF的替代方案------一份Schema定义按需取字段,不需要为每种前端单独写一个BFF服务。不过GraphQL也有自己的学习曲线和生态问题,这里不展开。


高可用:门卫不能倒

网关有个致命弱点:它是单点。网关挂了 = 全站不可用。普通服务挂了一个其他还能用,网关挂了所有服务都访问不了。

所以高可用对网关来说不是可选项,是必选项。

常见方案:

方案 怎么做的 切换速度 复杂度 适用规模
主备模式 Keepalived + VIP漂移,一活一备 1-3秒 中小流量
双活模式 两个实例同时接收流量 无需切换 中大流量
集群+LB N个实例前挂LVS/Nginx分发 无需切换 大流量

大多数场景主备模式就够了。超大流量(比如双十一级别)会用集群+LB的方式,前面再套一层LVS做四层分发,网关本身再做多副本。

顺便说一句,网关自身也需要限流------如果请求量超过网关的处理能力,网关自己先崩了,后面的保护措施全部失效。所以好的网关实现会在最前面给自己也设一道防线:超了就直接返回"服务繁忙",宁可拒绝也不能让自己挂掉。


一个请求的完整旅程

以打开淘宝商品详情页为例,看看一个请求经历了什么:

md 复制代码
① DNS解析
   www.taobao.com → 解析到网关的VIP地址

② 到达网关,依次经过:
   - 提取Cookie/Token → 验证登录态
   - 检查该IP/用户的请求频率 → 是否触发限流
   - 匹配URL路径 /item/xxx → 路由到商品服务
   - 记录日志(IP、耗时、状态码、TraceID)

③ BFF聚合(如果配了的话):
   - 并行调用6个微服务:用户(收藏)、商品(详情)、价格(实时价)、
     库存(是否有货)、评价(评分)、推荐(相似商品)
   - 聚合成一个完整响应

④ 前端收到数据,渲染页面

用户只感觉到"嗖的一下页面出来了",背后经过了DNS→网关→BFF→多个微服务→数据库整条链路,每一步都有门卫在把关。


主流网关产品

产品 语言 核心特点 QPS上限 适合谁
Nginx C 反向代理之王,配置灵活,极高性能 10万+ 只要LB+简单路由
Kong Lua(Nginx) 插件丰富,社区活跃,插件市场大 5万+ 微服务网关
APISIX Lua(Nginx) 国产开源,动态配置热更新,高性能 10万+ 国内团队首选
Spring Cloud Gateway Java 响应式编程,Spring生态无缝集成 3万+ Java/Spring Boot项目
Envoy C++ 云原生设计,Service Mesh标配 10万+ K8s/Istio环境

选型建议:

  • 只要做反向代理 + 简单路由 → Nginx,够用且稳定
  • 微服务网关,需要鉴权/限流/插件能力 → KongAPISIX
  • Spring全家桶项目 → Spring Cloud Gateway,集成最顺滑
  • Kubernetes容器化环境 → Envoy,云原生路线

生产环境常见的是两层网关架构

md 复制代码
用户请求
  ↓
LVS/Nginx(第一层:四层分发,纯扛流量)
  ↓
Kong/APISIX/Spring Cloud Gateway(第二层:七层业务处理)
  ↓
微服务集群

第一层负责吞吐量,第二层负责业务逻辑(鉴权、限流、路由、日志)。两层各司其职,哪层出问题都不影响另一层的基本能力。


总结

回到开头那个比喻。网关就像大楼的门卫,核心就三件事:

  • 统一入口 ------ 所有请求从这里进出,后端服务对前端透明。服务怎么扩、怎么迁、怎么换,前端都不用关心。

  • 横向切面 ------ 鉴权、限流、日志、监控这些横切关注点在网关统一处理,业务服务专注自己的业务逻辑,不用每个人都去管"这个人有没有证件"这种事。

  • 协议适配 ------ 屏蔽技术栈差异。前端用熟悉的HTTP/JSON,后端可以用gRPC、Thrift甚至任何内部协议。网关在中间做翻译,两边都舒服。

没有网关的微服务就像一栋没有前台的大楼------任何人都能直接敲任意办公室的门,既混乱又不安全。有了网关,才有秩序。

当然,门卫也不是万能的。它自身的高可用要做好,性能瓶颈要盯紧,配置变更要谨慎。毕竟,它是整栋楼的咽喉。

相关推荐
上海合宙LuatOS1 小时前
合宙TCP/UDP web测试工具简介
前端·物联网·tcp/ip·udp·luatos
悟空聊架构1 小时前
100多G数据同步引发的MySQL集群“连环炸”,我是如何一步步恢复的? - 墨天轮
后端·架构
Hemy081 小时前
tauri + rust 创建初始项目
开发语言·后端·rust
锋行天下1 小时前
后端golang项目一键打包部署方案
后端
用户6757049885021 小时前
90%的人都不知道:Docker 容器 apt 报错 404 的幕后黑手竟是它!
后端·docker·容器
fie88891 小时前
基于BBO算法的网络负载均衡优化(MATLAB实现)
网络·算法·负载均衡
Apifox.1 小时前
Apifox 近期更新|AI Agent Debugger、A2A Debugger、Postman API 导入、Ask AI 侧边栏对话
前端·人工智能·后端·测试工具·测试用例·postman
星辰_mya2 小时前
领域驱动设计(DDD)“老中医”治理订单
java·后端·面试·架构