目录
1. 国内航空巨头如何从 NGINX 迁移至 APISIX?
本文主要介绍了航空公司互联网能力持续提升的大背景下, 国内某大型航空公司移动互联网基础架构团队针对南北向网关从 NGINX 升级到 APISIX 的历程。
1.1. 深入解析 NGINX 网关的痛点
我们一直使用 NGINX 作为南北向网关。随着业务规模的发展和产品的增加, 从流量的角度来说, NGINX 仍然能很好地满足我们的需求, 然而, 在其他方面我们遇到了越来越多的痛点:
- 多节点配置管理: 我们管理着多台 NGINX 和多套不同的域名, NGINX 的核心是其配置文件。随着 NGINX 数量的增加, 单纯依靠 scp 复制文件的方式来管理 NGINX 配置文件已经变得越来越困难, 尤其是在后端大量使用微服务、容器化部署后, 对反向代理配置灵活度要求更高, 配置一致性工作量也越来越大。
- NGINX 及其插件的升级: 由于历史原因, 我们同时在使用多个版本的 NGINX , 同时还使用了很多 NGINX 的插件。每次需要升级时, NGINX 自身的升级并不困难, 难点在于各种插件的升级、编译和适配, 因为很多是非官方插件, 编译时遇到各种问题排查起来非常困难, 并且与 NGINX 版本的适配也得不到保障。
- NGINX 配置的标准化: 由于我们接手来自不同团队的系统, 各自使用的 NGINX 配置习惯不尽相同, 缺乏统一的配置标准。
- 现代网关功能不足: 虽然 NGINX 很好地满足了我们对南北向网关的基本需求, 如反向代理和负载均衡等, 但随着业务发展, 我们对南北向网关提出了更多的需求, 例如服务熔断、安全防控、灰度发布等, 单纯依赖 NGINX 实现这些功能并不容易。
1.2. 剖析网关选型, 精准匹配业务需求
针对 NGINX 所遇到的各种痛点, 我们认真梳理了对新网关产品的三个主要基本需求:
- 易于管理和配置: 我们需要在多个网关节点的场景下, 方便而统一地管理和发布路由、上游服务等各种配置。
- 满足现代 API 网关基础需求: 新网关必须能实现现代 API 网关的业务需求, 如服务熔断、安全防控、灰度发布等。
- 易用性和上手门槛: 鉴于我们团队成员人数有限, 并且中间件领域没有专职的开发和运维人员, 我们希望新网关产品能通过配置和低代码的方式, 让我们轻松完成大部分基本需求。
在明确了对现有南北向网关的迭代升级和基本需求之后, 我们对市面上流行的多款产品进行了调研, 并最终选择了 APISIX 作为我们的新网关。
- OpenResty: 在调研过程中, 我们首先考虑了 OpenResty, 它被很多大厂, 例如 Bilibili, 广泛采用作为网关。对于我们来说, OpenResty 最大的优点是其配置文件与 NGINX 完全兼容。由于我们有大量复杂的域名配置, 而且有些配置相当复杂, 部分网关从 NGINX 升级到 OpenResty 时, 能实现无缝衔接, 只需复制配置文件即可使用。然而, 相较于我们后面调研的 Kong 和 APISIX, OpenResty 的开源版本默认自带的插件不够完善, 也没有可视化的配置界面, 我们需要自己进行 Lua 开发来满足部分基本功能。
- Kong: 其次, 我们对 Kong 进行了初步的调研。Kong 的默认自带插件可以满足我们大部分需求。但是, 它的开源版本的可视化界面, 即 Dashboard, 基本几年内没有更新。尤其是在了解了 APISIX 后, 我们更希望能够拥有一个可视化界面, 以简化配置过程。
- Envoy: 我们还留意到了 Envoy, 尤其在网易和阿里相继发布基于 Envoy 的下一代网关之后。Envoy 基于 C++, 对于我们这样规模的团队来说还存在较高的门槛, 因此我们最终没有选择它。
最终, 我们决定采用 APISIX 作为新的网关产品, 因为它在功能和性能上均得到了市场的认可。根据测试结果, APISIX 在压力测试下的性能表现相当出色, 在没有开启插件的情况下, 其性能是 Kong 的 2 倍; 而在开启限流和 prometheus 插件后, 性能甚至高出 Kong 的 10 倍, 延迟仅为 Kong 的十分之一。此外, APISIX 基于 OpenResty 实现, 拥有出色的路由功能, 进一步增加了我们的信心。另外, 与 Kong 相比, APISIX 吸引我们的特点主要集中在以下两个方面:
- APISIX Dashboard: 基于 Dashboard, 我们能更便捷地管理各种路由和插件的配置。特别值得一提的是, APISIX Dashboard 本身就是开源项目的一部分, 我们相信未来会随着 APISIX 的发展而持续更新, 为我们提供更好的管理体验。
- Apache 开源项目: APISIX 作为 Apache 软件基金会的顶级项目, 相较于 Kong, 我们更容易在网络上搜索到相关的技术文档。在遇到各种问题时, 我们能够得到 Apache 社区的支持, 与其他开发者共同解决疑难问题, 为我们的项目提供更加可靠的技术支持。
在前面提到的关于 NGINX 的痛点, 也能够通过 APISIX 很好地解决:
- 多节点配置管理: APISIX 将配置存储于 etcd 中, 因此我们只需要部署一套 etcd 集群即可方便地管理多个不同域名的多个 APISIX 节点。
- NGINX 及其插件的升级: APISIX 内置了常用的健康检查等插件, 与 NGINX 中常用的插件相同, 这使得我们无需再考虑升级和兼容性等问题。
- 现代网关的功能: APISIX 自带多种安全性和流量控制插件, 轻松实现服务熔断、安全防控、灰度发布等功能。总体来说, APISIX 是对我们团队现阶段最适合的产品。
1.3. NGINX 迁移 APISIX: 探索先进解决方案
在 NGINX 中所有的域名管理以及其上的功能实现都是基于 NGINX 的配置文件来实现的。虽然 APISIX 仍然基于 NGINX 和 Openresty, 但在 APISIX 中, 我们采用了完全不同的方式, 不再使用 NGINX 的配置文件来管理域名和实现功能。我们首先根据域名配置路由(route)和其上游(upstream), 然后通过插件的形式实现路由上的各种附加功能。
从 NGINX 向 APISIX 的迁移的主要工作是将 NGINX 的各路由以及相关配置用 APISIX 的相关插件进行重构。实际迁移过程远比前面一句话更复杂, 我们将这个迁移过程拆分为以下三个主要步骤:
- 提取独立功能配置: 首先从 NGINX 配置中提取出一个独立的功能配置, 并深入理解其配置的含义。
- 网络协议层面理解配置: 其次, 需要从网络协议层面理解相关配置, 并借助各种网络工具进行验证测试。
- 寻找合适的插件实现功能: 最后, 在 APISIX 中找到适合的插件来实现与 NGINX 配置相同的功能, 并再次通过各种网络工具进行验证测试, 以确保 NGINX 和 APISIX 能够实现相同的效果。
这里我们以一个 CORS 跨域相关的配置来进行举例, 我们先把 NGINX 中跨域相关配置提取出来。
add_header 'Access-Control-Allow-Origin' $corsHost;
add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Accept,Authorization,appver';
if ($request_method = 'OPTIONS') {
return 204;
}
首先理解这段 NGINX 的含义, 用 add_header 在 NGINX response 中添加了一些关于跨域配置 header, 然后如果 request 方法为 OPTIONS 的话就直接返回 204。在赋值的时候, 这里我们还使用了一个变量 corsHost, 其定义如下:
map $http_origin $corsHost {
default 0;
"~http://wap.test.com" http://wap.test.com;
"~https://wap.test.com" https://wap.test.com;
}
再从网络层面去理解下这段 NGINX 配置的含义, 这一段配置其实是为了实现 CORS 跨域访问, 允许来自于 Access-Control-Allow-Origin 源的请求能够进行跨域访问, 请求的方法由 Access-Control-Allow-Methods 定义, 同时定义了允许的 Header 和请求可以包含 Cookie 等 credentials 信息。Options 返回 204 是 CORS 的预检要求的。更详细的信息可以在 mozilla 的网站上查看相关定义: https://developer.mozilla.org/。
要将这段 NGINX 的配置, 在 APISIX 中进行实现, 我们并不需要一行行的进行配置转换, 而是可以基于 APISIX 的 cors 插件进行实现:
"cors": {
"allow_credential": true,
"allow_headers": "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Accept,Authorization,appver",
"allow_methods": "GET,POST,PUT,OPTIONS",
"allow_origins": "https://wap.test.com,http://wap.test.com,",
},
针对 OPTIONS 请求返回 204 这部分配置, 我们使用了 response-rewrite 插件来实现:
"response-rewrite": {
"status_code": 204,
"vars": [
[ "request_method",
"==",
"OPTIONS"
]
]
}
在 APISIX 中使用 cors 插件和 response-rewrite 插件实现了这段配置之后, 我们可以使用浏览器自带的网络工具进行迁移后的测试验证:
从截图可以看到, 针对 Options 返回 204, 在响应 Header 中也配置好了 Access-Control-Allow-Origin 等要求的值。
1.4. APISIX 和 NGINX 配置对比
这里我们直接对比下 NGINX 和 APISIX 的配置代码:
# NGINX conf
add_header 'Access-Control-Allow-Origin' $corsHost;
add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Accept,Authorization,appver';
if ($request_method = 'OPTIONS') {
return 204;
}
# APISIX plugins config
"cors": {
"allow_credential": true,
"allow_headers": "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Accept,Authorization,appver",
"allow_methods": "GET,POST,PUT,OPTIONS",
"allow_origins": "https://wap.test.com,http://wap.test.com,",
},
"response-rewrite": {
"status_code": 204,
"vars": [
[
"request_method",
"==",
"OPTIONS"
]
]
}
NGINX 的配置看起来更加简洁, 但对于不熟悉 NGINX 和跨域的人来说, 理解其背后的含义可能并不容易。相比之下, APISIX 对不同的业务功能进行了插件封装, 使得配置更加模块化, 基本上一眼就可以看出其实现的业务功能和背后的含义。
类似的 NGINX 的配置向 APISIX 进行迁移的代码案例我们还有很多, 例如在 NGINX 中 websocket 协议需要进行如下配置:
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection ""Upgrade"";
proxy_http_version 1.1;
而在 APISIX 就进行了封装, 非常简单明了:
"enable_websocket": true,
1.5. 成功迁移后的回顾与展望
自从我们在 2023 年 4 月份首次接触 APISIX, 到 7 月份在生产环境成功完成了从 NGINX 到 APISIX 的升级, 整个迁移过程取得了令人满意的成果。在迁移初期, 由于接手的生产 NGINX 存在各种历史遗留配置, 有些甚至不清楚其真正意义, 我们曾对 APISIX 的插件能否完全实现我们现有 NGINX 的所有功能感到担心。但最终的结果表明, APISIX 的插件完全胜任这一挑战。
NGINX 向 APISIX 迁移的核心是重新在 APISIX 中实现 NGINX 配置文件, 这并不是一行 APISIX 配置对应一行 NGINX 的配置转换。我们需要深入理解相关 NGINX 配置模块背后的含义。在 APISIX 中, 往往可以通过插件实现更加优雅的解决方案, 例如跨域支持(cors)、WebSocket 等。
在整个升级过程中, 我们发现在原有的 NGINX 中存在不少上古配置, 其中很多地方甚至是毫无意义的复制粘贴配置。这次升级的过程也是对我们整个南北向网关的一次全面梳理, 特别是基于 APISIX 的 plugin_config 等功能, 我们在网关配置层面更容易实现模块化的管理和复用。
总体来说, APISIX 完美地解决了我们之前在 NGINX 中遇到的各种痛点, 其丰富的插件使我们能够轻松应对客户端提出的各种新需求。在迁移过程中, 社区小伙伴的大力帮助也为我们解决了一些故障, 对此我们表示衷心的感谢。