你有没有在小区门口见过这样的场景?外卖员、业主、装修工人、访客络绎不绝,保安队长既要核验每个人的身份,又要告诉他们去哪栋楼,高峰期还要控制人流防止堵门。如果小区里有十栋楼,每栋楼的管家都自己开门放人,那不但秩序混乱,出了事也说不清是谁的责任。 微服务架构的世界里,成千上万的“业主请求”要访问几十个“楼栋服务”,API网关就是那位经验丰富的保安队长。它站在所有服务的最前面,统一收下所有请求,查验证件(认证授权)、指路分流(路由转发)、控制人流(限流熔断),偶尔还会悄悄调整哪个门开得快一点(灰度发布)。这篇内容,我们就来聊聊如何当好这位“保安队长”——把API网关设计这件事彻底说透。
对AI从业者来说,API网关是你设计系统架构、保障服务稳定的“敲门砖”,掌握它意味着你能从单点功能开发跃迁到全局系统设计,这是迈向架构师的核心技能之一。
可视化演示
展示API网关核心功能:路由转发(客户端→网关→服务)、JWT认证鉴权、令牌桶限流与蓝绿灰度发布,动态对比流量治理策略。
本节配有交互动效(进入视口后自动加载,约 3KB)。
路由转发:统一流量入口 青色为API网关(流量入口) 浅青为客户端(Web/App/IoT) 绿色为后端服务(S1/S2/S3) Flow: Client -> Gateway -> Backend Service API网关作为微服务统一入口,负责路由分发、协议转换,客户端只需感知网关地址
网关核心作用
想象一下如果没有保安队长,外卖小哥进小区后要自己跑到3栋核实业主信息,再去5栋送餐,最后还要跑到7栋登记。路不熟、效率低不说,最要命的是——他经过的每一栋楼都要设一个“验身份”的岗亭,一栋楼配一个保安,十栋楼就要十份人力。这个场景放在微服务里,就是让人崩溃的“重复建设”。
API网关把“验身份、指路、维护秩序”这些横切关注点从每个服务中抽离出来,统一放在入口处。所谓横切关注点,是指那些几乎所有服务都需要、但又不属于任何单一业务的功能——认证、限流、日志、监控、灰度等。让每个微服务只专注于自己的“本职工作”(比如订单服务只管订单),把公共事务全部上交给网关这个“总管家”。
技术落地时,网关通常作为微服务架构中最前置的一层,所有外部请求先经过它,再由它转发到内部服务。根据Kong等开源网关的性能基准测试,一个成熟网关的单核QPS可达数万,且大多数操作在代理层完成,对业务代码零侵入。这意味着团队可以随时在网关上调整限流策略、切换认证方式,而完全不需要改动任何微服务代码——正如小区换一套闸机系统,楼栋内部陈设完全不受影响。
1. 统一流量入口:所有外部请求首先抵达网关,网关成为唯一的“大门”,这个收敛设计让安全策略、流量策略可以集中管理、集中升级。
2. 横切关注点收敛:“横切”指这类功能横跨所有服务,就像“打招呼”这个动作横跨你遇到的所有人,不单独属于谁的“本职”。
3. 服务治理枢纽:网关汇合了所有流量,天然拥有全局视图——哪些服务健康、哪些节点过载、哪些接口被疯狂调用,网关一清二楚。
回到小区场景,保安队长之所以能高效指挥,是因为他站在唯一的大门处看到了所有人流。API网关的价值正是如此——它不生产业务,但让所有业务跑得更稳、更安全、更可控。
路由转发策略
小区保安队长手里的那本“楼栋索引簿”就是网关的路由表。外卖单上写着“3栋1202送餐”,队长扫一眼就知道该让外卖员往左走。但如果单子上只写着“李女士的快递”呢?队长就得查一下业主名册,找到李女士住在哪栋。API网关的路由匹配,正是这样一层层“查索引”的过程。
网关根据请求的不同特征,将流量分发到不同的后端服务。最常见的策略是路径前缀匹配:比如以 /api/orders 开头的请求全部转给订单服务,以 /api/inventory 开头的转给库存服务。更精细的条件路由则看HTTP头、查询参数甚至请求体内容——比如带有 X-User-Type: vip 头的请求,可以优先路由到性能更强的服务节点池。
路由转发的进阶能力是负载均衡。网关内置了加权轮询、最小连接数等多种均衡算法。假设你有两个订单服务实例,一个配置权重40%、另一个权重60%,网关按比例分配流量,确保“能者多劳”。网关还可以定期探测后端服务健康状态,自动摘除失联节点,就像保安队长发现某栋楼的管家请假了,就自动把访客引导到隔壁楼栋的备用接待处。
聪明的保安队长从不让某栋楼的管家忙到崩溃,而其他楼闲到发呆。网关的路由和负载均衡策略,就是微服务世界里的“人流调控智慧”。
- 路径前缀匹配把URL路径当作索引的“关键字”,前缀命中哪个规则就转发到哪个服务,直白高效。
- Header条件路由在路径之外附加条件,当请求头的某个键值满足预设条件时才命中该路由,类似按“业主身份”分流。
- 加权负载均衡每个实例有权重 \( w_i \),请求被选中的概率与权重成正比,实现按比例的流量分发。
协议转换机制
小区门口经常有这种情况:业主用普通话喊“请开下门”,但访客说的是英语,外国朋友说的是法语。保安队长如果只会普通话,那交流就卡壳了。聪明的做法是——队长自己学几门语言,或者随身带一个翻译机。API网关面对的“语言障碍”,就是客户端与服务端之间的协议差异。
微服务内部为了追求极致性能,经常使用gRPC这类基于HTTP/2的高性能RPC框架,而外部客户端(比如移动App)通常只支持标准的HTTP/JSON。网关承担了“翻译官”的角色,把外部的HTTP请求翻译成内部gRPC调用。在实际实现中,Kong网关通过gRPC插件让JSON请求自动映射为Protobuf消息,对客户端完全透明。
WebSocket长连接代理是协议转换的另一大场景。客户端发起一次HTTP升级请求后,网关与后端建立WebSocket隧道,实现实时双向通信。这里网关不再是简单的“翻译官”,而是一个能长期维持会话的“信使”,确保消息能持续地在客户端和服务端之间来回穿梭。此外,响应体重写功能让网关还能对返回给客户端的数据做二次加工——比如从内网接口的响应里剔除敏感字段、统一包装为固定的结构体,保证客户端拿到的是“标准格式的通告”。
有了“翻译官”网关,无论客户端的“方言”多么五花八门,后端服务都可以用自己最舒适的语言交流——这正是微服务架构中通信自由与对外规范得以两全的精髓。
- HTTP转gRPC将HTTP请求中的JSON参数映射为gRPC调用所需的Protobuf结构体,请求“改头换面”进入内部网络。
- WebSocket代理网关先通过HTTP升级握手,再在客户端与后端之间建立全双工长连接,精确转发双向数据帧。
- 响应体重写对后端返回的JSON做字段过滤、重命名、包装,使不同服务的响应格式在出口处达到统一。
JWT认证体系
保安队长最头疼的事情是什么?靠“刷脸”认人。今天化个妆、明天戴个口罩,脸就认不出来了。但如果每个业主进门时给一张“盖章通行证”,上面写着楼栋号、有效期和防伪标记,队长验一下就放行,那就轻松太多。JWT(JSON Web Token)就是这个“盖章通行证”。
JWT由三段组成:Header、Payload、Signature。Header标识签名算法,就像通行证上印的“采用钢印防伪”;Payload携带业务声明——用户ID、角色、过期时间等,相当于通行证上的“姓名、楼栋、有效期”;Signature则是对前两段做数字签名,就像那个火漆钢印,一旦有人篡改通行证内容,钢印就对不上,瞬间识破。
网关验证JWT时,先用同样的算法和密钥重新计算签名,比对是否一致——这确保令牌内容没有被篡改;接着检查 exp 过期时间声明,确认通行证没有过期;最后校验权限声明,看用户是否有权限访问目标接口。由于JWT是无状态的,网关不需要“打电话回服务端确认”,验签通过就直接放行,这在分布式环境下极大减少了认证环节的性能损耗。APISIX网关甚至支持通过 jwt-auth 插件将公钥配置在网关层集中验签,实现统一的零信任接入控制。
保安队长认“章”不认“脸”,网关认“签名”不认“来源”——这套机制让服务端无需保存会话状态即可完成身份核验,正是分布式系统追求的可伸缩认证之道。
- Base64Url编码把Header和Payload分别做Base64Url编码,生成两个可安全放入URL的字符串段,中间用点号连接。
- HMAC-SHA256签名以服务端持有的密钥对输入做HMAC-SHA256哈希,得到一段定长的签名数据,这是防伪的核心。
- 验签比对接收方用同样的密钥计算期望签名,与JWT携带的签名逐一字节比对,一致则信任令牌内容。
OAuth2授权流
“通行证”适用于常驻业主,但小区经常有访客——快递员、装修工、亲戚朋友。保安队长不会随便给访客发放长期通行证,而是让他们先去业主那里确认,由业主“授权”后发放一个有时限的临时出入证。OAuth2授权协议,就是这套“访客授权”流程的标准化规范。
OAuth2最常用的授权码模式(Authorization Code Flow)有四方参与:用户、客户端应用、授权服务器、资源服务器。流程是:客户端引导用户到授权服务器登录(用户确认授权),授权服务器返回一个短期有效的授权码给客户端;客户端拿着授权码再向授权服务器换取访问令牌(Access Token);此后客户端带着令牌访问资源服务器。整个过程确保客户端应用永远拿不到用户的密码,只拿到有限权限的“临时通行证”。
网关在OAuth2体系中承担“门禁”角色:它校验访问令牌的有效性和作用域,不合法就拒绝放行。Spring Cloud Gateway、Kong等主流网关都支持集成Keycloak或自建OAuth2服务,将令牌校验逻辑集中在网关层。与JWT配合时,网关用授权服务器下发的公钥验签JWT,就能在不调用认证中心的情况下完成令牌验证——既享受OAuth2的授权管理能力,又保留JWT的无状态优势。
小区里的访客流程和网络世界的OAuth2如出一辙——不把大门钥匙(密码)给外人,只发一张有时限、能撤销的临时通行证(令牌)。这套思路已经成为现代互联网授权的事实标准。
- 获取授权码客户端引导用户到授权服务器,用户登录并同意授权后,服务器将一次性授权码通过重定向返回给客户端。
- 交换访问令牌客户端用授权码向授权服务器令牌端点发起请求,换取访问令牌和刷新令牌。授权码只能使用一次,增加安全性。
- 携带令牌访问资源客户端在HTTP请求头中带上
Authorization: Bearer <token>,网关校验通过后放行到目标服务。
限流熔断治理
早晚高峰的小区门口,如果所有人一拥而上,闸机必然瘫痪。保安队长手握流量控制权:每分钟放行多少人,超了就让他们在门外等候;如果发现某栋楼内部发生骚乱,立刻临时封闭该楼入口,防止事态扩大。这就是网关的限流与熔断能力。
限流最经典的算法是令牌桶:想象一个每秒往桶里放入固定数量令牌的装置,请求进来必须从桶里取走一个令牌才能通过,桶空则拒绝。这允许一定程度的突发流量(桶里积攒的令牌),又限制了长期平均速率(每秒注入的令牌数)。实现上,APISIX的 limit-req 插件采用漏桶算法的变体,Kong的 rate-limiting 插件支持本地与集群两种模式,在分布式环境中用Redis共享计数实现全局限流。
熔断则是“防系统性崩溃的保险丝”。以Resilience4j为例,熔断器有三个状态:CLOSED(关闭)、OPEN(打开)、HALF_OPEN(半开)。正常情况下CLOSED,请求正常通过;当错误率达到阈值(如最近100次调用中50%失败),熔断器跳闸到OPEN,所有请求立即快速失败,不再等待超时拖累系统;经过冷却时间后进入HALF_OPEN,放少量试探请求,如果成功则恢复CLOSED,否则继续保持OPEN。这让“救火”变成了“预防”,下游服务喘口气的时间都没有?恰恰相反——熔断恰恰是给下游“喘息”的机会。
小区大门的闸机不是为了挡人,而是为了让人流更有序;熔断与限流也不是为了拒绝用户,而是为了让整个系统在极端情况下依然“活着”。这是架构师的生存智慧。
- 令牌注入系统以固定速率 \( r \) 向令牌桶注入令牌,桶容量上限为 \( b \),用于允许突发流量。
- 请求取牌每个请求必须消耗一个令牌,桶空则请求被拒绝或排队等待,从而控制平均速率。
- 错误率统计滑动窗口内统计请求总数与失败数,错误率超过阈值则触发熔断,进入OPEN状态。
灰度发布方案
换小区门禁系统时,最怕什么?一夜之间全部换掉,结果新系统有bug,所有业主蒙在门外。老练的保安队长会这样操作:先让1%的业主试用新系统,观察几天没问题,再逐步扩大到10%、50%、100%。这就是灰度发布——让新版本“小步快跑”地靠近用户,而不是“孤注一掷”地全量上线。
灰度发布策略以权重为核心:网关配置新旧两个版本服务的流量权重,比如新版本占10%、旧版本占90%。网关在每次请求时按权重随机分配到其中一个版本,比如APISIX的 traffic-split 插件和Kong的 canary 插件都支持灵活的权重调节。更精细的Header定向分流则是:只有特定用户群(比如内部测试员工、带了特定Header的beta用户)的请求才进入新版本,实现“精准的小白鼠”。
灰度发布必须配套“安全气囊”——自动回滚机制。网关持续监控新版本的错误率、延迟等指标,一旦检测到新版本错误率超过预设阈值(比如5%),立即将流量全部切回旧版本,整个过程无需人工干预。这套机制让“上线”从“高风险手术”变成了“可控试验”。
灰度发布就像让新门禁系统先在小范围“实习”,实习期表现优秀再转正,表现不佳就退回原岗位——它让“变更”这件事从恐惧变成了可管理、可观测的日常操作。
- 权重分配为每个服务版本配置一个权重值,网关每次请求按权重比例随机选择目标版本。
- 指标监控实时采集新版本的请求量、成功率、P99延迟,与旧版本进行对比,判断是否达标。
- 自动回滚健康检查不通过时,将新版本权重直接归零,流量全部切回旧版本。
开源网关选型
如果小区决定采购一套门禁系统,摆在物业面前的有两个主流品牌:A品牌系统功能全、插件丰富、上手简单;B品牌系统性能极致、云原生友好、但需要更多学习成本。选择哪一套,取决于小区的规模、预算和物业团队的技术储备。开源网关选型,正是这样一个“权衡的艺术”。
Kong是最流行的开源网关之一,基于Nginx和OpenResty构建,使用Lua编写插件。它的优势在于插件生态极度丰富——认证、限流、转换、日志等数百个现成插件,加上企业版的控制平面Konga,让运维管理非常直观。对于已有Nginx运维经验的团队,Kong的学习曲线相对平缓,文档和社区资源成熟。
APISIX则走“极致性能”路线,由深圳支流科技开源并捐赠给Apache基金会。它基于etcd做配置存储,支持动态路由更新(改配置无需 reload),在基准测试中单核QPS达到数万级,比传统Nginx高一个数量级。它的插件机制使用Lua与Java、Go等多语言支持,在云原生场景下与Kubernetes的适配性更佳。Tyk作为Go语言的网关代表,则以轻量级部署和多租户特性著称。选型的本质是匹配团队的运维能力与业务场景:如果追求生态成熟度选Kong,如果追求性能与动态配置选APISIX。
选门禁系统要看小区规模,选网关要看团队与场景——真正的架构师不做“最好”的决策,只做“最合适”的权衡。Kong与APISIX各擅胜场,理解差异即是进阶之道。
- Kong插件生态以Nginx为内核,插件机制成熟且数量庞大,适合需要快速接入多种治理能力的团队。
- APISIX高性能数据面基于Nginx+lua-resty库,控制面用etcd,实现毫秒级配置热更新,性能在同级别网关中领先。
- 社区与维护度Kong背靠商业化公司,社区活跃;APISIX是Apache顶级项目,贡献者众多,两者的长期维护都有保障。
AI 应用场景
智能限流与自适应熔断
阶段:模型/服务部署后的流量治理与稳定性保障
解决的问题:AI推理服务上线后,流量波动剧烈且GPU资源成本高昂,全量放行会导致服务雪崩。传统固定阈值限流对突发流量不敏感,熔断恢复过慢。网关接入实时流量数据后,可以根据每秒请求量、GPU利用率和响应延迟动态调整令牌桶的填充速率——高峰期自动收紧限流,低谷期自动放宽;同时根据错误率趋势在故障发生前预判并开启熔断,用统计模型替代人工配置阈值。
具体案例:某AI绘画公司通过APISIX网关的 limit-req 插件,将令牌桶速率与GPU利用率监控打通,实现动态限流。大促期间流量突增5倍,系统在关键路径上自动收紧限流,将降级请求引导至排队队列,保护了核心生成服务的可用性,整体错误率控制在0.5%以内。
模型服务的统一认证与路由
阶段:模型服务的接入与API治理
解决的问题:企业内部有多个算法团队,各自部署模型服务,API风格与认证方式各异,调用方苦不堪言。通过API网关对模型服务进行统一封装,对外暴露一致的HTTP接口,网关层完成JWT认证,并利用路由规则将不同模型版本(如v1、v2)分流至对应的模型服务,实现新老模型的平滑切换与A/B测试。
具体案例:某金融科技公司在Kong网关上配置了多个模型服务的路由规则,风控模型团队发布v2版本后,通过路由权重将5%的流量灰度到新模型,并自动对比新旧模型的逾期预测准确率,达标后逐步提升流量比例,全程模型团队零干预。
AI网关的智能异常检测
阶段:数据采集与模型推理
解决的问题:网关的访问日志中蕴含着服务健康状态的大量信息,传统人工巡检难以发现“慢请求模式”和“错误码关联”等隐性特征。利用AI算法分析网关日志流,可以提前几十分钟预判下游服务即将过载,自动触发网关的限流熔断策略,形成“AI预测+网关执行”的闭环。
具体案例:某电商平台基于APISIX的访问日志,训练了一个LSTM时间序列模型预测未来5分钟的服务负载,当预测值超过预警线时,自动调整网关的限流权重,将非核心请求分流至降级策略,核心交易链路始终畅通。
Python 演示
import hashlibimport hmacimport jsonimport timefrom collections import dequefrom dataclasses import dataclass, field SECRET_KEY = "my_secret_key" def b64url_encode(data: bytes) -> str: return ( __import__("base64").urlsafe_b64encode(data) .rstrip(b"=").decode("ascii") ) def b64url_decode(data: str) -> bytes: padding = "=" * (-len(data) % 4) return __import__("base64").urlsafe_b64decode(data + padding) def generate_jwt(payload: dict, exp_seconds: int = 3600) -> str: header = {"alg": "HS256", "typ": "JWT"} payload = dict(payload) payload["exp"] = int(time.time()) + exp_seconds header_b64 = b64url_encode(json.dumps(header).encode()) payload_b64 = b64url_encode(json.dumps(payload).encode()) signing_input = f"{header_b64}.{payload_b64}" signature = hmac.new( SECRET_KEY.encode(), signing_input.encode(), hashlib.sha256, ).digest() return f"{signing_input}.{b64url_encode(signature)}" def verify_jwt(token: str) -> dict: header_b64, payload_b64, signature_b64 = token.split(".") signing_input = f"{header_b64}.{payload_b64}" expected = hmac.new( SECRET_KEY.encode(), signing_input.encode(), hashlib.sha256, ).digest() if not hmac.compare_digest( expected, b64url_decode(signature_b64), ): raise ValueError("JWT signature mismatch") payload = json.loads(b64url_decode(payload_b64)) if payload["exp"] < int(time.time()): raise ValueError("JWT expired") return payload class TokenBucket: def __init__(self, rate: float, capacity: int): self.rate = rate self.capacity = capacity self.tokens = capacity self.last_refill = time.monotonic() def allow(self) -> bool: now = time.monotonic() self.tokens = min( self.capacity, self.tokens + (now - self.last_refill) * self.rate, ) self.last_refill = now if self.tokens >= 1: self.tokens -= 1 return True return False class CircuitBreaker: def __init__(self, threshold: float = 0.5, cooldown: float = 30.0): self.threshold = threshold self.cooldown = cooldown self.state = "CLOSED" self.failures = 0 self.total = 0 self.last_triggered = 0.0 def record(self, success: bool): if self.state == "OPEN": if time.time() - self.last_triggered >= self.cooldown: self.state = "HALF_OPEN" self.failures = 0 self.total = 0 else: return self.total += 1 if not success: self.failures += 1 error_rate = self.failures / max(self.total, 1) if self.state == "HALF_OPEN": if success: self.state = "CLOSED" else: self.state = "OPEN" self.last_triggered = time.time() elif self.state == "CLOSED" and error_rate >= self.threshold: self.state = "OPEN" self.last_triggered = time.time() def can_pass(self) -> bool: return self.state != "OPEN" @dataclassclass ServiceInstance: name: str weight: int success_rate: float = 1.0 class APIGateway: def __init__(self): self.routes = {} self.bucket = TokenBucket(rate=10.0, capacity=20) self.breaker = CircuitBreaker() self.instances = { "order": [ ServiceInstance("order-v1", 90), ServiceInstance("order-v2", 10), ] } def route(self, path: str): for prefix, target in self.routes.items(): if path.startswith(prefix): return target return None def forward(self, request: dict) -> dict: if not self.bucket.allow(): return {"status": 429, "body": "Rate limited"} if not self.breaker.can_pass(): return {"status": 503, "body": "Circuit open"} try: verify_jwt(request["token"]) except ValueError as exc: return {"status": 401, "body": str(exc)} target = self.route(request["path"]) if target is None: return {"status": 404, "body": "No route"} return {"status": 200, "body": f"Forwarded to {target}"}
def generate_jwt(payload: dict, exp_seconds: int = 3600) -> str:生成带过期时间戳的JWT,对应正文中“盖章通行证”的签发环节signature = hmac.new(...).digest()使用HMAC-SHA256对Header和Payload做签名,这是JWT防篡改的核心class TokenBucket:实现令牌桶算法,rate控制令牌注入速率,capacity允许突发流量def allow(self) -> bool:按固定速率补充令牌,桶空则拒绝请求,与正文公式Tokens(t) = min(Tokens(t-1) + r*Δt, b)完全吻合class CircuitBreaker:实现CLOSED/OPEN/HALF_OPEN三态熔断状态机,错误率超阈值自动跳闸def record(self, success: bool):每次调用后记录成功/失败,过半失败触发熔断,冷却时间后进入半开试探self.instances = {"order": [...]}为订单服务配置新旧两个版本,权重90:10,对应灰度发布策略if path.startswith(prefix):用Python字符串前缀匹配实现路由转发,与Nginx的路径前缀规则同理if not self.breaker.can_pass():熔断开启时快速失败,避免所有请求阻塞在下游verify_jwt(request["token"])在网关上统一验签JWT,实现“验证一次、到处信任”
常见误区
误区很多初学者以为API网关只是一个普通的HTTP中间件,随便找个服务器部署一下就行,甚至觉得nginx就能完全替代网关的功能。
正解网关虽然本质上是反向代理的升级版,但它的核心价值在于“平台化治理”——认证、限流、熔断、灰度等能力需要深度整合。就像保安队长需要一块能总览全小区的监控大屏和一个直通所有楼栋的对讲系统,网关需要与注册中心、配置中心、监控系统打通,而不是一个孤立部署的软件。正确做法是将网关纳入服务治理体系,作为基础设施统一运维。
为何常见:从Web开发转入微服务架构时,大家天然习惯“加一层反向代理”的旧思路,忽略了网关在治理层面上的系统性角色。
误区初学者拿到一个JWT,验签通过、没过期,就认为这个用户肯定合法,于是放行一切操作。
正解JWT验签通过只证明“令牌没被篡改”和“没过期”,并不代表“用户有权执行某个操作”。就像保安队长验证了通行证是真实的,但还要看通行证上有没有访问某栋楼的权限。网关还必须校验Payload中的角色声明、权限范围(Scope)是否匹配目标接口的访问控制策略。JWT的内容是Base64Url可解码的,任何人用工具都能看到Payload——所以绝不能在JWT里放密码等敏感信息。
为何常见:“验签=信任”这个等式在单一信任域里成立,但微服务是多方参与的,必须做细粒度的权限校验,这一点容易被惯性思维忽略。
误区只对QPS做限制,认为每分钟10000个请求的限制就已经很完善了,忽略了业务维度的差异化限流。
正解真正的限流设计是立体的——既要按IP限流防止单个用户耗尽资源,也要按用户ID限流防止撞库攻击,还要按API维度限流保护核心接口,甚至要按租户限流在SaaS场景下保证多租户公平。就像小区门口的限流不只是“数人头”,还要区分业主、外卖员、装修队,给不同人群设定不同的通行规则。APISIX的limit-req插件就是支持按自定义key(如consumer、route等)做细粒度限流的。
为何常见:早期的Nginx配置让人们对限流的认知停留在"remote_addr+QPS"这种粗粒度方案上,微服务场景下流量来源复杂,单一维度限流防不住真正的风险。
误区新版本流量已经100%了,灰度就算成功了,然后就不管了,旧的灰度配置和路由规则一直留着。
正解灰度完成以后还有“收尾三件事”:第一,将新版本的权重固定为100%并清理临时灰度规则;第二,删除或归档旧版本的部署和路由,避免旧代码还在后台占用资源;第三,复盘灰度期间的监控指标,沉淀成下一次发布的基线数据。就像试验田成功培育出新品种后,要及时铲除试验田的围栏和标记,让新作物进入正规农田管理流程。
为何常见:人类对“完成”有一种天然的松懈感,总觉得“跑通了就行”,忽略了灰度流程中“收尾”这个同样重要的阶段。
误区选型时对比QPS跑分,谁的数字大就选谁,完全没考虑团队的技术栈和运维能力。
正解性能只是选型的一个维度。Kong和APISIX的单核QPS都在数万级别,对绝大多数业务场景来说都绰绰有余。真正的决策因素在于:团队熟悉Lua吗?需要多语言插件吗?配置更新要动态还是可以接受重启?控制平面是否需要UI?Kong的生态更成熟、文档更丰富;APISIX在云原生和动态配置上更领先;Tyk更轻量。就像是选车,百公里加速5秒和6秒的差异,远没有“这辆车适不适合你的驾驶习惯和通勤路况”来得重要。
为何常见:技术人骨子里对“性能数字”有迷恋,这是人性的自然倾向,但选型本质是“匹配”而不是“比拼”。
面试题
Q1. API网关的核心价值不包括以下哪一项?
- A.统一流量入口
- B.收敛认证限流等横切关注点
- C.替代数据库存储业务数据← 正确答案
- D.提供全局服务治理视图
答案:C。网关的核心价值是统一入口、横切关注点收敛和全局治理,它做的是“流量分发与治理”而非“业务数据存储”。就像保安队长负责秩序维护,不会帮业主代管保险箱里的财物。选项A、B、D都是网关的职责,C选项把网关当成了数据库,错误明显。
Q2. JWT由哪几个部分组成?
- A.Header(头部)← 正确答案
- B.Payload(负载)← 正确答案
- C.Signature(签名)← 正确答案
- D.Cipher(加密体)
答案:ABC。JWT的三段式结构是 Header.Payload.Signature。Header标识算法,Payload携带声明,Signature保证防篡改。D选项的"Cipher"是混淆项——JWT的Payload是Base64Url编码而非加密,这是初学者最常见的认知误区,编码不等于加密。
Q3. 网关将外部HTTP请求转换为内部gRPC调用的过程属于什么能力?
- A.路由转发
- B.协议转换← 正确答案
- C.限流熔断
- D.灰度发布
答案:B。HTTP转gRPC是典型的协议转换能力,网关在这里扮演“翻译官”角色,让客户端用标准的HTTP/JSON访问内部高性能的gRPC服务。路由转发关注的是“转发到哪”,限流熔断关注的是“放不放行”,灰度关注的是“分发到哪一版”,与“语言翻译”都不是一回事。
Q4. 关于令牌桶限流算法,以下说法正确的是?
- A.桶容量限制了最大突发流量← 正确答案
- B.令牌注入速率决定了长期平均速率← 正确答案
- C.令牌桶算法无法应对突发流量
- D.桶空时请求一定被拒绝← 正确答案
答案:ABD。令牌桶的两个关键参数:rate(注入速率)决定长期平均速率,capacity(桶容量)决定突发上限。桶空时请求被拒绝或排队,所以D正确。C是错误的——令牌桶恰恰是允许突发的,因为积攒的令牌可以一次性被消耗,这是它与漏桶算法的核心区别。
Q5. 熔断器进入OPEN状态后发生的现象是?
- A.所有请求正常转发
- B.所有请求立即快速失败← 正确答案
- C.请求排队等待重试
- D.路由自动切换到新版本
答案:B。熔断器OPEN时所有请求直接快速失败,不回源等待超时。这是“快速失败优于无限等待”的智慧——就像发现一栋楼煤气泄漏后立即封闭入口,而不是让居民继续进出。A是CLOSED的行为,C是限流排队,D是灰度策略,都与熔断的触发机制无关。
Q6. 在OAuth2授权码模式中,客户端获取访问令牌的前提是先获得什么?
- A.刷新令牌
- B.用户密码
- C.一次性授权码← 正确答案
- D.JWT签名密钥
答案:C。授权码模式的流程是:用户授权后授权服务器先返回一次性授权码,客户端再用授权码换访问令牌。授权码是一次性的、短期的,这确保了即使授权码在网络传输中被截获,攻击者也无法反复使用。刷新令牌是在访问令牌过期后使用,选项A是后续环节;C用户密码永远不会交给客户端;D是JWT的概念,与OAuth2流程无关。
Q7. 灰度发布策略的常见实现方式有哪些?
- A.权重灰度(新版本分配一定比例流量)← 正确答案
- B.Header定向分流(特定用户群走新版本)← 正确答案
- C.一次性全量替换新旧版本
- D.自动回滚机制(新版本异常切回旧版本)← 正确答案
答案:ABD。灰度发布的核心是“渐进式暴露”,权重灰度按比例分配流量、Header分流精准控制测试人群、自动回滚是安全兜底,这三种都是正确策略。C的全量替换是灰度要避免的“梭哈式发布”,风险极高,就像新门禁系统不经测试就一夜全部换掉,出事就是大面积事故。
Q8. 关于Kong与APISIX的比较,下列说法错误的是?
- A.Kong基于Nginx,插件生态非常丰富
- B.APISIX基于etcd做配置存储,支持动态热更新
- C.APISIX的配置变更需要重启才能生效← 正确答案
- D.APISIX在某些基准测试中单核QPS表现优于Kong
答案:C。APISIX最核心的卖点就是动态配置——配置存储在etcd中,变更无需reload即可生效,所以C错误。Kong的生态丰富(A正确),APISIX的动态更新能力(B正确),以及在基准测试中的性能优势(D正确)都是事实。选型时不要只看性能,还要考虑团队运维能力。
Q9. 以下哪些功能属于API网关提供的“横切关注点”?
- A.身份认证与授权← 正确答案
- B.限流与熔断← 正确答案
- C.业务订单状态流转
- D.灰度发布← 正确答案
答案:ABD。横切关注点是跨越所有服务、又不属于任何单一业务的功能。认证、限流、灰度都是这类公共能力,适合统一收敛在网关层。C的订单状态流转是订单服务的核心业务逻辑,属于“纵切”的业务功能,不应被网关代劳——就像保安队长不会帮商家记账,那是店主的本职工作。
Q10. 在加权轮询负载均衡中,两个实例权重分别为40和60,当服务实例2宕机被网关摘除后,实例1会分配到多少流量?
- A.40%
- B.50%
- C.60%
- D.100%← 正确答案
答案:D。负载均衡分配的权重是“相对”的——当实例2被摘除后,存活实例中实例1是唯一节点,权重归一化后它获得100%的流量,即 \( w_1 / (w_1 + w_2) = 40/40 = 100\% \)。A选项只记住了原始权重而忽略了归一化计算,这是对加权轮询“按比例”语义的常见误解。就像小区开了两个门,一个门坏了,所有人自然走另一个门。