让你设计一个 API 网关,需要考虑哪些核心功能?如何实现动态路由和限流?
- 标签:后端、系统设计、场景题、API网关、微服务、限流
🏛 业务架构师
设计 API 网关,我先定位它的业务角色:网关是流量的总入口,也是全站的资损闸门和契约执行者——它挂全站挂,它漏策略全站裸奔。所以设计目标排序是:可用性 > 稳定性 > 功能 > 性能。
核心功能清单
- 动态路由:请求按 path/header 匹配路由到目标服务
- 统一鉴权:token 校验、签名验证、权限粗筛
- 限流熔断:按接口/用户/app 维度限流,下游异常熔断
- 协议转换与聚合:对外 HTTPS/HTTP2,对内 RPC
- 可观测:全量访问日志、traceId 注入、按路由维度的监控
- 灰度能力:按 header/用户标签切流量——发布和营销实验的基础设施
动态路由实现
- 路由规则存配置中心(Nacos):
path 匹配条件 → 目标服务 + 插件链 - 网关监听配置变更推送,热更新路由不断流量——发布新服务、下线老版本不需要重启网关
- 变更走灰度 + 审批 + 秒级回滚:网关配置错误 = 全站故障,这纪律比功能重要
限流实现(分层令牌)
本地令牌(网关实例内存, 毫秒级判断)
+ 远程令牌(Redis+Lua 全局配额, 定期异步 replenish)- 单纯 Redis 集中限流:每次请求一次网络往返,网关扛不住;单纯本地限流:各实例配额不精确
- 两级结合:本地令牌快速消耗,异步向 Redis 补充——精度和性能兼得
- 限流维度业务化:按 app(开放平台配额)、按用户(防刷)、按接口(资损预算)——限流阈值是运营配置不是代码常量
架构师收尾:网关自身要无状态多活(水平扩展 + 同城双机房),并做全链路压测——它的容量 = 全站容量上限。另外我会坚持网关代码极简:自定义过滤器越少越好,每一段网关代码都是全站风险的乘数。
🏗 系统架构师
API 网关是微服务的流量入口,我按核心功能清单 → 动态路由 → 限流三段答。
1. 核心功能全景
- 协议接入与路由:HTTP/gRPC 统一入口,按 path/host/header 转发
- 安全:认证鉴权(JWT/SSO token 校验、API Key)、防重放(nonce+timestamp)、WAF 联动、黑白名单
- 流量治理:限流、熔断、灰度分流、超时与重试控制
- 可观测:访问日志、traceId 注入、metrics 上报
- 生命周期管理:路由与插件配置热更新、API 版本管理、Mock/文档
- 技术选型:自研(Spring Cloud Gateway / APISIX / Higress)或云托管——量级不大时托管省心,定制化强选 APISIX(etcd 配置中心 + Lua/插件动态扩展,性能接近 Nginx)
2. 动态路由实现 路由规则不写死在配置文件,存配置中心/数据库,监听变更推送生效:
text
路由模型:条件匹配(host/path/header/query) + 目标服务(注册中心服务名/LB权重)
存储:etcd/Nacos ← 管理端 API 增删改
生效:网关节点 watch 变更 → 内存路由表原子替换(读写分离,无锁读)关键点:变更推送毫秒级到全部节点;本地缓存 + 兜底快照(配置中心挂了用最后版本);路由匹配用前缀树(path 合并优化)保证万级路由下微秒级匹配;变更审计与一键回滚。
3. 限流实现(网关层核心算法)
- 单机令牌桶(APISIX
limit-req):应对单节点洪峰,配置简单 - 分布式限流:Redis + Lua 原子"计数+判断",全局限precise,但多一跳网络(本地预扣配额 + 异步对账可优化到准全局)
- 多维度规则:全局/服务/API/用户/IP 四层,优先级从粗到细匹配
- 动作分级:超限返回 429 + Retry-After、排队等待、降级到旧缓存
- 配额管理:规则同样走配置中心热更新;大促前预置活动限流预案一键切换
一句话:网关 = 路由 + 安全 + 治理 + 可观测四合一,动态性靠配置中心推送 + 原子热替换,限流要单机与分布式双层。
💻 全栈开发专家
我以 Spring Cloud Gateway / APISIX 为蓝本回答,先列核心功能,再重点讲动态路由和限流的实现。
核心功能清单
- 路由转发(协议转换、URL 改写)、动态路由
- 认证鉴权(JWT 校验、灰度放行)、接口签名与防重放
- 限流、熔断、降级
- 灰度发布(按权重/标签分流)、日志与监控(访问日志、trace 透传)
- API 生命周期管理(版本、Mock、文档聚合)
动态路由实现
路由元数据存配置中心,监听变更推送生效,不重启网关:
java
// SCG:监听 Nacos 配置变化,刷新路由
namingListener.onChange(routes -> {
routeDefinitionWriter.delete(Mono.just(routeId));
routeDefinitionWriter.save(Mono.just(def));
publisher.publishEvent(new RefreshRoutesEvent(this)); // 热生效
});APISIX 更省事:路由存 etcd,Admin API 修改后所有节点 watch etcd 秒级同步,自带一致性保障。生产上我倾向 APISIX/Higress 这类云原生网关,SCG 做业务型轻网关。
动态限流实现
单机限流(Guava RateLimiter)在多副本下不准,网关层要集群限流:Redis + Lua 令牌桶,或者 APISIX 直接启用 limit-count / limit-req 插件(底层同样是 Redis 集群计数):
lua
-- Lua 核心:原子判断并扣减
local left = redis.call('INCRBY', key, -cost)
if left < 0 then return 0 end
if left == limit - cost then redis.call('EXPIRE', key, 1) end
return 1按"维度 + 时间窗口"设计 key(接口级、用户级、App 级叠加),超限返回 429 并打上监控点。
生产要点
- 网关无状态化,配置变更灰度验证再全量;etcd/Nacos 本身高可用部署。
- 限流阈值来自压测,联动监控(SkyWalking 对网关入口 QPS/RT 看板)动态调整。
- 热点接口单独限流,防止拖垮共享的 Redis。