1.Apache APISIX介绍
1.1 什么是Apache APISIX
Apache APISIX 是一个动态、实时、高性能的云原生 API 网关,提供了负载均衡、动态上游、灰度发布、服务熔断、身份认证、可观测性等丰富的流量管理功能。可以使用Apache APISIX 处理传统的南北向流量,也可以处理服务间的东西向流量。同时,它也支持作为 K8s Ingress Controller 来使用。
Apache APISlX官网:https:/lapisix,apache.org/
南北向流量:客户端到服务器之间通信的流量 (client → server)
东西向流量:服务器和服务器之间的流量(server → server)
APISIX主要特性
- 多平台支持:APISIX 提供了多平台解决方案,它不但支持裸机运行,也支持在Kubemetes 中使用,还支持与 AWS Lambda、Azure Function、Lua 函数和Apache OpenWhisk 等云服务集成。
- 全动态能力:APISIX 支持热加载,这意味着你不需要重启服务就可以更新APISIX 的配置。
- 精细化路由:APISIX 支持使用 NGINX内置变量做为路由的匹配条件,你可以自定义匹配函数来过滤请求,匹配路由。
- 运维友好:APISIX支持与以下工具和平台集成:HashiCorp Vault、Zipkin、Apache SkyWalking、Consu、Nacos、Eureka。 通过 APISIX Dashboard,运维人员可以通过友好且直观的 UI配置 APISIX。
- 多语言插件支持:APISIX 支持多种开发语言进行插件开发,开发人员可以选择擅长语言的 SDK 开发自定义插件。
1.2 APISIX架构
APISIX 的架构主要分成两部分:
第一部分叫做数据面,它是真正去处理来自客户端请求的一个组件,去处理用户的真实流量,包括像身份验证、证书卸载、日志分析和可观测性等功能。数据面本身并不会存储任何数据,所以它是一个无状态结构。
第二部分叫做控制面。APISIX 在底层架构上和其它 API网关的一个很大不同就在于控制面。APISIX 在控制面上并没有使用传统的类似于像 MySQL去做配置存储,而是选择使用 etcd。这样做的好处主要有以下几点:
- 与产品架构的云原生技术体系更统一
- 更贴合 API 网关存放的数据类型
- 能更好地体现高可用特性
- 拥有低于毫秒级别的变化通知
使用 etcd 后,对于数据面而言只需监听 etcd 的变化即可。如果轮询数据库的话,可能需要 5-10 秒才能获取取到最新的配置;但如果监听 etcd 的配置变更,就可以将时间控制在毫秒级别之内,达到实时生效的效果。
etcd官方的定义:分布式系统中最关键数据的分布式、可靠的键值存储。
etcd是一个由CoreOS团队开源的,基于Go语言实现的,用于构建高可用的分布式键值(key-value)数据库。
APISIX 的主要概念和组件
| 概念/组件 | 描述 |
|---|---|
| Route | 通过路由定义规则来匹配客户端请求,根据匹配结果加载并执行相应的插件,最后把请求转发给到指走的上游应用。 |
| Upstream | 上游的作用是按照配置规则对服务节点进行负载均衡,它的地址信息可以直接配置到路由或服务上。 |
| Admin API | 用户可以通过 Admin API 控制 APISIX 实例。 |
1.3 Apache APISIX 的技术优势
NGINX 与 Kong 的痛点
在单体服务时代,使用 NGINX 可以应对大多数的场景,而到了云原生时代,NGINX 因为其自身架构的原因则会出现两个问题:
- 首先是 NGINX 不支持集群管理。几乎每家互联网厂商都有自己的 NGINX 配置管理系统,系统虽然大同小异但是一直没有统一的方案。
- 其次是 NGINX 不支持配置的热加载。很多公司一旦修改了配置,重新加载NGINX的时间可能需要半个小时以上。并且在 Kubernetes 体系下,上游会经常发生变化,如果使用 NGINX 来处理就需要频繁重启服务,这对于企业是不可接受的。而 Kong 的出现则解决了 NGINX 的痛点,但是又带来了新的问题:
- Kong 需要依赖于 PostgreSQL 或 Cassandra 数据库,这使 Kong 的整个架构非常臃肿,并且会给企业带来高可用的问题。如果数据库故障了,那么整个 API网关都会出现故障。
- Kong 的路由使用的是遍历查找,当网关内有超过上千个路由时,它的性能就会出现比较急剧的下降。
Kong、OpenResty都是基于Nginx打造的新一代服务器。它们兼具Web服务器的功能,但侧重于网关层特性的延伸
Apache APISIX 和 Kong 相比在技术方面的主要优势,大部分都是在底层模块上的优化和创新。+
无数据库依赖
APISIX 在设计之初,就从底层架构上避免了宕机、丢失数据等情况的发生。因为在控制面上,APISIX 使用了 etcd 存储配置信息,而不是使用关系型数据库,这样做的好处主要有以下几点:
- 与产品架构的云原生技术体系更统一:
- 更贴合 API 网关存放的数据类型;
- 能更好地体现高可用特性,
- 拥有低于毫秒级别的变化通知。
使用 etcd 存储配置信息后,对于数据面而言只需监听 etcd 的变化即可。如果采用轮询数据库的方式,可能需要 5-10 秒才能获取到最新的配置信息;如果监听 etcd 的配置信息变更,APISIX 就可以将获取最新配置的时间控制在毫秒级别之内,达到实时生效。
插件热加载
APISIX 和 NGINX 相比,有两处非常大的变化:APISIX 支持集群管理和动态加载。
思考: APISIX是如何实现热加载的
NGINX 热加载的原理
执行 nginx -s reload 热加载命令,就等同于向 NGINX 的 master 进程发送 HUP 信号。在 master 进程收到 HUP 信号后,会依次打开新的监听端口,然后启动新的 worker 进程。此时会存在新旧两套 worker 进程,在新的 worker 进程起来后,master 会向老的worker 进程发送 QUIT 信号进行优雅关闭。老的 worker 进程收到 QUIT 信号后,会首先关闭监听句柄,此时新的连接就只会流进到新的 worker 进程中,老的 worker 进程处理完当前连接后就会结束进程。
NGINX 热加载的缺陷
- 首先,NGINX 频繁热加载会造成连接不稳定,增加丢失业务的可能性。NGINX 在执行 reload 指令时,会在旧的 worker 进程上处理已经存在的连接,处理完连接上的当前请求后,会主动断开连接。此时如果客户端没处理好,就可能会丢失业务
- 这对于客户端来说明显就不是无感知的了。其次,在某些场景下,旧进程回收时间长,进而影响正常业务。比如代理 WebSocket 协议时,由于 NGINX不解析通讯帧,所以无法知道该请求是否为已处理完毕状态。即使 worker 进程收到来自 master 的退出指令,它也无法立刻退出而是需要等到这些连接出现异常、超时或者某一端主动断开后,才能正常退出。再比如NGINX 做 TCP 层和 UDP 层的反向代理时,它也没法知道一个请求究竟要经过多少次请求才算真正地结束。
- 这就导致旧 worker 进程的回收时间特别长,尤其是在直播、新闻媒体活语音识别等行业。旧 worker 进程的回收时间通常能达到半小时甚至更长,这时如果再频繁 reload,将会导致 shutting down 进程持续增加,最终甚至会导致 NGINX OOM,严重影响业务。
APISIX 在内存中直接生效的热加载方案
在 Apache APISIX 诞生之初,就是希望来解决 NGINX 热加载这个问题的。
通过上述架构图可以看到,之所以 APISIX 能摆脱 NGINX 的限制是因为它把上游等配置全部放到 APISIX Core 和 Plugin Runtime 中动态指定。
以路由为例,NGINX 需要在配置文件内进行配置,每次更改都需要 reload 之后才能生效。而为了实现路由动态配置,Apache APISIX 在 NGINX 配置文件内配置了单个server,这个 server 中只有一个 location。我们把这个 location 作为主入口,所有的请求都会经过这个 location,再由 APISIX Core 动态指定具体上游。因此 Apache APISIX的路由模块支持在运行时增减、修改和删除路由,实现了动态加载。所有的这些变化,对客户端都零感知,没有任何影响。
比如增加某个新域名的反向代理,在 APISIX 中只需创建上游,并添加新的路由即可,整个过程中不需要 NGINX 进程有任何重启。再比如插件系统,APISIX 可以通过 ip-restriction 插件实现 IP 黑白名单功能,这些能力的更新也是动态方式,同样不需要重启服务。借助架构内的 etcd,配置策略以增量方式实时推送,最终让所有规则实时、动态的生效,为用户带来极致体验。
高性能路由匹配算法
API 网关需要从每个请求的 Host、URI、HTTP 方法等特征中匹配到目标规则,以决定如何对该请求进行处理,因此一个优秀的匹配算法是必不可少的。Apache APISIX 使用的是** RadixTree**,它提供了 KV 存储查找的数据结构并对只有一个子节点的中间节点进行了压缩,因此它又被称为压缩前缀树。此外,在已知 API网关产品中 Apache APISIX 首次将 RadixTree 应用到了路由匹配中,支持一个前缀下有多个不同路由的场景。
当对某个请求进行匹配时,RadixTree 将采用层层递进的方式进行匹配,其复杂度为O(K)(K 是路由中 URI的长度,与 API数量多少无关),该算法非常适合公有云、CDN以及路由数量比较多的场景,可以很好地满足路由数量快速增长的需求,
高性能 IP 匹配算法 假设现在有一个包含 500 条 IPv4 记录的 IP 库,APISIX 会将 500 条 IPv4 的记录缓存在Hash 表中,当进行 IP 匹配时使用 Hash 的方式进行査找,时间复杂度为 O(1)。而其他 API 网关则是通过遍历的方式完成 IP 匹配,发送到网关每个请求将逐个遍历最多500 次是否相等后才能知道计算结果。所以 APISIX 的高精度 IP 匹配算法大大提高了需要进行海量IP 黑白名单匹配场景的效率.
精细化路由
API 网关通过请求中的流量特征完成预设规则的匹配,常见特征包含了请求中的 HostURI路径、URI 查询参数、URI路径参数、HTTP 请求方法、请求头等,这些特征是大部分 API 网关产品所支持的。相较于其它产品,Apache APISIX 支持了更多特征以解决复杂多变的使用场景。具体看怎么使用吧,这里只是笔记记录
- Apache APISIX 支持 NGINX 内置变量
- Apache APISIX 支持将条件表达式作为匹配规则、
- Apache APISIX 支持设置路由 tt1
- Apache APISIX 支持自定义过滤函数
支持多语言插件
APISIX 目前已经支持了 80 多种插件,但仍然难以涵盖用户的所有使用场景。在实际使用场景中,很多企业都会针对具体业务进行定制化的插件开发,通过网关去集成更多的协议或者系统,最终在网关层实现统一管理。
在 APISIX 早期版本中,开发者仅能使用 Lua 语言开发插件。虽然通过原生计算语言开发的插件具备非常高的性能,但是学习 Lua 这门新的开发语言是需要时间和理解成本的。
针对这种情况,APISIX 提供了两种方式来解决:第一种方式是通过 Plugin Runner 来支持更多的主流编程语言(比如 Java、Python、Go等等)。通过这样的方式,可以让后端工程师通过本地 RPC 通信,使用熟悉的编程语言开发 APISIX 的插件。
这样做的好处是减少了开发成本,提高了开发效率,但是在性能上会有一些损失。那么,有没有一种既能达到 Lua 原生性能,同时又兼顾高级编程语言的开发效率方案呢?
好好学习,天天向上。