ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

APISIX演进之路:从Kong挑战者到云原生AI网关标杆

APISIX演进之路:从Kong挑战者到云原生AI网关标杆

干API网关这行做久了,脑子里存着一堆深夜救火的画面。四年前,我负责的平台还跑在Kong上,那天凌晨核心业务抖动,Kong依赖的PostgreSQL慢查询日志和Nginx错误日志来回翻,配个路由动辄要同步缓存,从那一刻起,我开始盯上Apache APISIX。这篇不打算做菜市场级别的对比,而是想聊聊APISIX的演进逻辑:它怎么从当年被视为Kong的挑战者,一步步变成如今AI网关赛道上的热门选择。技术路线背后的思路变化,远比表面上的Benchmark更有意思。

如果你正在做网关选型,或者在Kong、APISIX之间犹豫,又或者只是好奇“AI网关”到底和普通API网关有什么不同,这篇值得看完。我会尽量用实际踩坑的经历来讲,不堆概念。

1. 先交代背景:APISIX为什么出现在那个时间点

1.1 网关解决的本质问题

很多人一提到API网关,第一反应是“反向代理”。这话对,但太粗了。网关站在流量的最前面,干的活本质上是四件事:统一接入、安全防护、流量治理、可观测。

统一接入好理解,就是所有客户端别直接面对一堆散落的微服务,统一走一个口子进来。安全防护是在这个口子上做认证、鉴权、防注入、限流。流量治理是灰度发布、权重调整、熔断降级、流量镜像这类高级操作。可观测则是记录日志、链路追踪、指标采集。

打个比方,网关就是一个园区门口的保安加前台。来访者先在前台登记,保安核实身份,然后按访客单引导到指定房间。如果某个楼要搞消防演练,前台发出一部分人去B栋,一部分人去C栋,这就是灰度。听起来很简单,但在分布式系统里,这些操作的性能开销、配置管理难度、扩展性,都会成为巨大的坑。

1.2 Kong当年是怎么解决这些问题的

Kong在API网关领域确实是里程碑式的存在。2015年前后开源,基于OpenResty和Nginx,用插件化方式把鉴权、限流、日志这些功能拆成一个一个可以插拔的模块。它把控制面和数据面分离:数据面是Nginx worker处理请求,控制面通过Admin API来管理配置,配置持久化到PostgreSQL甚至早期的Cassandra里。

这套设计在当年非常先进。在它之前,很多人写网关逻辑就是直接改Nginx配置,改完reload,出了问题回滚都难。Kong让“动态管理路由、动态挂插件”变成了现实。很长一段时间里,它都是开源API网关的默认答案,社区生态也大,企业版卖得也很稳。

但放在今天的视角往回看,Kong的架构里藏着一个隐患:配置中心是数据库。数据库擅长的是持久化事务性数据,但对于“配置变更需要快速广播到所有数据面节点”这个场景,它并不是最优解。尤其是在路由规模上千、多可用区部署的时候,配置变更的同步链路会变得很重。

我自己当年的体会是:在Kong上改一个插件参数,有时候像发了一次生产版本。不是Kong不好,而是那个时代的架构基因决定了它的行为模式。

1.3 一个新的解题思路出现了

APISIX诞生的时候,云原生和Kubernetes正在快速普及。它从第一天起就走了一条不同的技术路线:配置中心用etcd,控制面和数据面之间通过etcd的watch机制做实时推送。

这个改变带来的直观结果是:你改一个路由规则,不用reload Nginx,不用等数据库同步,配置变更在极短时间内就能推送到所有网关节点。路由匹配用radixtree(基数树),大量路由规则下依旧能保持稳定高效的匹配性能。

APISIX后来捐赠给Apache基金会,成为Apache顶级项目,这本身也说明它的社区治理和技术方向得到了认可。从我的角度看,它在那个时间点出现,正好抓住了两个趋势:一是业务系统全面容器化,二是网关本身需要从“配置发版模式”走向“声明式实时生效模式”。

2. 与Kong的路线差异:不是跑分胜负,而是架构理念更符合云原生

2.1 存储层选型:PostgreSQL与etcd背后是两种世界观

Kong和APISIX最核心的分歧,不在于谁的代码写得更好,而在于配置应该放在哪里。

维度KongAPISIX
典型配置存储PostgreSQL,早期也支持Cassandraetcd(也可用Standalone本地文件模式)
配置变更机制通过Admin API写库,数据面需要轮询或事件机制感知变更etcd watch机制,变更实时推送
扩展性思路数据库为中心,适合传统部署分布式一致性和Kubernetes生态天然贴近
运维复杂度需要额外维护数据库高可用需要维护etcd集群,但对云原生团队来说很熟悉

为什么etcd更贴合云原生?因为Kubernetes本身就是用etcd存所有集群状态,它天然支持分布式一致、范围查询、watch监听。网关配置本质上也是“需要所有节点保持一致状态的数据”,所以用etcd而不是数据库,在理论层面更顺。

不过要注意,etcd并不适合当业务数据库去存大量历史数据。网关配置最多几千几万条,这个量级对etcd来说毫无压力。但如果你硬要把日志、审计记录都塞进etcd,那肯定出事。APISIX社区一直强调etcd只放配置,数据面产生的日志、指标走另外的管道,这个边界一定要守住。

2.2 路由匹配与热加载的工程细节

再往下说一点工程实现。Kong和APISIX都是基于Nginx/OpenResty的,但路由匹配算法的取舍不一样。Kong的路由匹配在某些场景下用基于正则和优先级的方式,路由规则数量暴涨的时候,匹配开销和规则排序复杂度都会上升。APISIX用的是radixtree,这种数据结构对前缀匹配和通配符匹配非常友好,而且支持运行时动态插入删除规则。

实际体验中,我迁移过一次路由规模比较大的服务,几百条路由里混着正则、前缀、Host匹配、Header匹配,APISIX的匹配结果依然稳定。而且插件热加载体验是真的好:启用一个新插件,修改配置后立即生效,不用像老一代方案那样担心“reload瞬间连接中断”。

注意:Nginx reload不是洪水猛兽,但高并发下reload确实会造成短暂的worker重启和连接波动。一个网关系统如果每次配置变更都要reload,就等于把“动态”这两个字打了一半折扣。APISIX这种热加载能力,在频繁调整灰度策略的时候非常爽。

2.3 我的迁移实测:从Kong到APISIX

当时我们迁一个订单查询服务,场景不算复杂:几百个路由、统一JWT鉴权、按用户限流、日志采集、部分接口要做流量镜像。

迁移步骤简单说是这样:

  1. 先从Kong Admin API把所有routes/services/upstreams的配置导出成JSON。
  2. 写个脚本做字段映射,把Kong的路由规则转换成APISIX的route资源。
  3. 在测试环境用APISIX Admin API批量导入,逐个核对路由匹配结果。
  4. 灰度切流量,先用小流量验证鉴权、限流、日志链路。
  5. 观察客户端报错率和延迟,确认稳定后再全量切换。

用一个例子说明创建路由的配置格式。比如我要创建一个路径为/api/orders的路由,走JWT鉴权,限流每秒钟每个用户最多10次,请求转发到上游服务:

routes: - uri: /api/orders name: order-service methods: ["GET", "POST"] plugins: jwt-auth: {} limit-count: count: 10 time_window: 60 key_type: var key: consumer_name rejected_code: 429 upstream: type: roundrobin nodes: "10.0.1.23:8080": 1

这段配置里,uri就是路径匹配,plugins按顺序生效,upstream定义了转发目标。APISIX的配置哲学是:一个资源就是一个JSON/YAML对象,可以通过Admin API动态创建,也可以写成声明式文件同步到etcd。

当时踩过最大的坑是路由优先级。Kong里路由规则有regex_priority,APISIX里有更细粒度的priority字段,如果你同时存在/api/orders和/api/orders/:id这种规则,没有显式设置优先级时,匹配结果可能和预期不一致。我的建议是:任何可能重叠的路由,都显式设置priority,别靠默认行为。

3. 云原生阶段,APISIX做对了什么

3.1 与Kubernetes的配合几乎是天生一对

APISIX在Kubernetes环境里的价值,远比在传统虚机上明显。官方维护的APISIX Ingress Controller可以直接用Kubernetes的Ingress资源来驱动APISIX配置,也提供了更细粒度的CRD,比如APISIXRoute、APISIXUpstream、APISIXConsumer这些自定义资源。

有了CRD之后,网关配置就可以纳入GitOps流程。你不需要SSH到某台机器上去调配置,而是提交一个YAML到代码仓库,再由CI/CD工具把这份声明同步到集群。配置有review记录,有版本历史,出问题可以回滚。这种体验,对从传统运维转过来的人来说,简直是从手工记账切换到ERP系统。

如果你已经用了Kubernetes,APISIX Ingress Controller还有一个很实际的好处:服务发现可以直接对接Kubernetes Service,上下游节点变更不用手动维护upstream列表。Pod重建、扩缩容之后,网关自动感知。

3.2 多语言插件体系,把扩展门槛降下来

早期网关插件几乎都是Lua写的。Lua本身不难,但真正能写好Lua插件、又理解Nginx异步模型的工程师,数量确实有限。APISIX很早就设计了一套Plugin Runner机制,支持Java、Go、Python、WASM等语言跑外部插件。

这个设计理解起来其实很简单。把APISIX想象成一个插座板,Lua插件是原生插头,而Plugin Runner是一个转接头,让不同语言的插头也能插进来。APISIX主进程和外部插件进程之间通过Unix Socket通信,把请求阶段的数据交给外部插件处理,拿回结果后再继续往下走。

我团队里有个业务逻辑特别复杂的限流需求,要用到公司内部的风控模型,用Go写插件比用Lua顺手太多。生产实践下来,外部插件的性能损耗是有一定代价的,但换来的是“不用等Lua专家,业务团队自己就能扩展网关能力”。这个权衡我觉得很值。

3.3 顺带聊一个容易混淆的“Apache”话题

这几天看到搜索热词里有人问“apache spark与databricks的区别”,还有人搜“apache tomcat启动失败”。每次看到这种词条,我都想说一句:Apache是一个庞大的开源生态,Spark是大数据计算引擎,Tomcat是Java应用服务器,而APISIX是云原生API网关。这四样东西唯一的共同点就是都属于Apache基金会,应用场景完全八竿子打不着。

很多人听到“Apache APISIX”,第一反应是“跟Apache HTTP Server有关系?”,第二反应是“是不是那个老古董”。其实APISIX是很新派的云原生基础设施,跟传统的Apache HTTP Server之间的距离,就像智能手机和大哥大一样。搞清楚这一点,选型时才不会先入为主。

4. AI网关时代,APISIX凭什么站在最前面

4.1 传统API网关为什么接不住AI应用

如果说过去几年网关主要接的是REST API和WebSocket,那现在越来越多请求是发给大模型服务的。这类请求有几个特殊点:

第一,上游供应商五花八门,OpenAI、Anthropic、各类国内模型服务,接口规范不统一,有的兼容OpenAI协议,有的有自己的签名流程。业务方接每一家都要单独适配。

第二,API Key管理是个大问题。你不能把厂商密钥直接放到前端或业务后端里,密钥泄露就是钱的问题。而多业务线共享密钥,又没法统计谁用了多少、谁触发限额。

第三,Prompt本身是敏感信息和核心资产。用户可能往Prompt里粘贴内部代码、客户资料,网关如果不做脱敏和审计,合规风险极高。

第四,流式响应让传统日志和监控全部失灵。普通HTTP请求返回一次就结束了,LLM的流式输出是持续不断的,内部还要关心首字延迟、token吞吐量、上下文长度这些新指标。

第五,成本控制。每个模型价格不一样,同一个模型不同时段价格也可能不一样,传统网关的限流配额是基于“请求次数”的,而AI场景更关心“token数量”和“模型单价”。

这一堆新问题,传统的路由转发、鉴权限流能力只能覆盖其中一小部分。所以“AI网关”不是营销概念,而是新场景倒逼出来的新品类。

4.2 APISIX的AI原生能力是怎么设计的

APISIX在近几个版本里已经沉淀出一套相对完整的AI网关插件体系。你可以把它理解成三块能力:

第一块是接入代理。ai-proxy这一系列插件可以把APISIX改造成一个对上游LLM服务的统一代理入口,一个route对应一个模型供应商,对外暴露统一的OpenAI兼容接口。业务方根本不用关心上游是OpenAI还是Anthropic还是别的什么,只要请求网关的统一地址就行。替换供应商时,网关层配置改一下,业务代码完全不用动。

第二块是模型路由与容灾。ai-llm这类插件可以配置多个大模型后端,设置主备关系或按权重分发,上游某个模型限流或故障时,自动降级到可用模型上。这一条在AI场景里特别实用,因为大模型服务的稳定性再大牌,也会有波动。

第三块是Prompt管理和语义缓存。ai-prompt-template可以在网关层给请求动态拼接系统提示词,让业务方只需要传用户消息。语义缓存则是把常见问题的响应结果缓存起来,命中缓存就直接返回,大幅降低token消耗。

AI插件还可以跟APISIX原有的通用能力天然组合。比如用key-auth做多租户鉴权,用limit-count做按用户限流,用prometheus插件做指标采集,用request-logger记录每一次AI调用的请求和响应摘要,形成完整的审计流水线。

我实际体验下来,这套体系已经不止是“能用”,而是可以拿来做正式的AI应用接入基础层。有一个点我想特别提醒:启用AI插件时,路由层最好预留足够的超时时间。非流式的大模型接口经常要几十秒,流式接口更是可能持续几分钟,默认的60秒超时根本不够。需要针对AI路由单独配置read_timeout和send_timeout,否则你会看到一堆莫名其妙中断的请求。

4.3 一个真实场景:把内部知识库包装成OpenAI兼容助手

我们做过一个内部问答助手,底层是RAG架构,知识库向量化之后交给大模型生成回答。现在所有流量都走APISIX网关,业务层不需要保存模型供应商密钥,只需要在请求头带上内部统一身份凭证。

网关上做的事情是:

  1. 按用户身份做鉴权和配额管理,每个部门每个月多少token预算,超了就限流,财务月底拉账单。
  2. 经ai-proxy统一转发到模型服务,模型供应商密钥只存在于网关环境变量里。
  3. 对入站Prompt做脱敏和拦截,检测到手机号、身份证号等敏感信息直接打码。
  4. 每个请求记录model、prompt长度、响应码、耗时的审计日志,方便按业务线追溯。
  5. 在主模型不可用的时候,自动降级到备用模型,用户无感知。

这个方案做出来之后,业务线的接入成本肉眼可见地下降了。以前新业务想接AI能力,先要去申请密钥、自己处理限流、自己搞日志审计,现在直接调网关接口就够了。这其实就是AI网关的核心价值:把复杂度和风险集中收敛到一层,对外提供简洁规范的能力。

5. 从部署到排障,我的实操笔记

5.1 快速搭一套本地环境:etcd加APISIX,再加Dashboard

如果你只是想跑起来看看,最省事的方式是用Docker Compose。一个最小环境包含三个服务:etcd、apisix、apisix-dashboard。

# docker-compose.yml version: "3" services: etcd: image: bitnami/etcd:3.5 environment: - ALLOW_NONE_AUTHENTICATION=yes - ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379 - ETCD_ADVERTISE_CLIENT_URLS=http://etcd:2379 ports: - "2379:2379" apisix: image: apache/apisix:3.9.0 depends_on: - etcd ports: - "9180:9180" - "9443:9443" - "9080:9080" environment: - APISIX_STAND_ALONE=false dashboard: image: apache/apisix-dashboard:3.0.0 depends_on: - apisix ports: - "9000:9000" volumes: - ./dashboard_conf/conf.yaml:/usr/local/apisix-dashboard/conf/conf.yaml

启动后,网关数据面端口是9080,管理和API端口是9180,控制台在9000。生产环境我不建议用这种方式,但本地体验、跑通功能,docker-compose是最快的路径。

生产环境我的建议是用Helm部署在Kubernetes集群里,etcd单独维护一个三节点集群,APISIX实例至少两个副本,控制台可以按需部署,甚至可以不暴露公网。还有一点非常重要:生产环境etcd的TLS必须开,否则网关控制面数据裸奔在网络上,隐患非常大。

5.2 Dashboard里添加流复制的正确处理方式

最近总有人搜“apisix dashboard添加流复制”,我估计很多人在界面上找不到入口。先说结论:Dashboard里不是每个插件的配置项都有漂亮的表单,traffic-split插件一般要直接编辑JSON配置。

流量复制(也叫流量镜像)的真实语义是:把真实请求复制一份到另一个上游服务,但客户端只拿到原上游的响应。这个东西常用于影子发布,拿真实流量去压测新版本服务,不影响线上用户。

通过Admin API创建一个简单的流量复制配置如下:

curl http://127.0.0.1:9180/apisix/admin/routes/1 -X PUT -d ' { "uri": "/api/sample", "plugins": { "traffic-split": { "rules": [ { "weighted_upstreams": [ { "upstream": { "type": "roundrobin", "nodes": { "10.0.0.8:8080": 10 } } } ] } ] } }, "upstream": { "type": "roundrobin", "nodes": { "10.0.0.7:8080": 100 } } } '

这段配置的含义是:所有请求正常打到10.0.0.7的正式服务,同时以10比100的权重,也就是约9%的比例复制到10.0.0.8的影子服务。关键是影子服务的响应不会返回给客户端,你只需要去影子服务查它的日志和指标就行。

注意:traffic-split复制的是请求,但下游如果做了数据库写入操作,影子环境会把真实数据写到测试库里。影子服务的数据库一定要隔离,要么连测试库,要么把写的操作全部mock掉,否则你就等着被脏数据坑一晚上吧。

5.3 常见故障清单与排查思路

根据我自己的生产经验,整理了一份网关故障速查表:

故障现象可能原因排查方向
路由配置不生效配置了Standalone模式但又用Admin API写配置;或者etcd连接失败先确认APISIX运行模式,再看etcd到网关的网络连通性,最后用curl /apisix/admin/routes确认配置是否真的写入
请求全部401认证插件没有正确挂在route上,或者consumer不存在检查插件是否启用、key和secret是否匹配、consumer是否创建成功
流式接口中断、超时Nginx默认读取超时太短,或者开启了缓冲单独给AI路由设置长read_timeout、send_timeout,关掉proxy_buffering
限流误伤大量用户limit-count的key选择不合理,比如用了全局IPkey改成consumer_name或user_id,IP这个维度在NAT环境下普遍不太靠谱
插件配置格式报错插件字段名写错,不同版本字段兼容性有变化去官方文档对照config字段,测试环境先验证,别直接怼生产
配置回滚困难没有做etcd定期快照每次批量变更前,用etcdctl snapshot save打快照,便于快速恢复

排查时我最常用的三板斧:第一,看APISIX错误日志,默认在日志文件里,Kubernetes环境用kubectl logs直接看;第二,用Admin API查询当前配置,确认数据面看到的东西是不是和预期一致;第三,在测试环境用curl带不同header反复打路由,逐步缩小范围。

排查到怀疑插件顺序问题时,可以把插件全部摘掉,只留下转发,先确认基础链路通。然后一个一个挂插件回来,每挂一个就压一遍,定位到是哪个环节引入问题。这种二分法看着笨,但在生产环境反而最安全。

最后分享一个我个人受用很久的小技巧

如果你所在的公司后续需要把AI能力开放给多条业务线,千万别一上来就让每个业务都直接拿模型厂商的Key。先在APISIX上把AI代理路由建好,统一挂鉴权、限流、日志三个插件,再让业务来注册接入。我这么干过之后,省掉了大量“谁又把Key泄露到Git仓库”的头痛事,也把每个月的模型账单控得明明白白。

另外一个建议是:APISIX的学习曲线没有想象中陡,但你要先接受配置流这套思考方式。总拿它当普通静态Nginx用,只会平白增加心智负担。等你看懂了etcd里那份配置结构,等于打通了整个云原生网关的任督二脉。这个工具最后的边界是团队自身的运维体系,而不是它本身的功能上限。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进