APISIX是什么
Apache APISIX是Apache软件基金会下的云原生API网关,它兼具动态、实时、高性能等特点,提供了负载均衡、动态上游、灰度发布(金丝雀发布)、服务熔断、身份认证、可观测性等丰富的流量管理功能。
可以使用Apache APISIX来处理传统的南北向流量,也可以处理服务间的东西向流量。
同时,它也支持作为K8s Ingress Controller来使用。
APISIX的部署架构图如下所示,包含3个部分:API Gateway负责流量转发,etcd负责配置存储,API Gateway Admin是管理人员的控制台,而且三个部分都完整支持高可用。
部署APISIX
如下操作基于APISIX最新稳定分支3.4.1进行。
APISIX支持多种安装方式,但使用Docker方式进行部署是最为方便的。
所以在安装APISIX之前,需要先确定已经安装了Docker及Docker Compose。
官方给出的安装步骤如下:
# 将Apache APISIX的Docker镜像下载到本地
# 这里可以选择下载指定版本的APISIX,只需要选择指定分支即可
# 如:可以选择分支release/apisix-3.4.1
# 默认从master分支下载
git clone https://github.com/apache/apisix-docker.git
# 也可以从指定分支下载
git clone -b release/apisix-3.4.1 https://github.com/apache/apisix-docker.git
# 将当前的目录切换到apisix-docker/example路径下
cd apisix-docker/example
# 运行docker-compose命令,启动Apache APISIX
docker-compose -p docker-apisix up -d
# 对应的配置文件分别是:./dashboard_conf/conf.yaml和./apisix_conf/config.yaml
安装完毕后请执行如下命令确保APISIX已经成功部署:
curl "http://127.0.0.1:9080" --head | grep Server
如果返回如下格式数据,表明APISIX已经成功部署并启动:
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
Server: APISIX/3.4.1 # 输出了APISIX版本信息
完整的APISIX服务会运行在多个端口,其中有三个是最常用的:
- 9000:管理后台的运行端口
- 9080:客户端访问路由时使用的端口
- 9180:通过管理API执行路由添加等操作的端口
如上所说,APISIX管理后台运行在9000
端口,访问地址http://HOST:9000/
即可访问APISIX的Dashboard页面,默认管理账户:amdin/admin。
核心概念
Upstream
Upstream也称为上游,上游是对虚拟主机的抽象,即应用层服务或节点的抽象。
上游的作用是按照配置规则对服务节点进行负载均衡,它的地址信息可以直接配置到路由或服务上。当多个路由或服务引用同一个上游时,可以通过创建上游对象,在路由或服务中使用上游ID(即:upstream_id)的方式引用上游,减轻维护压力。
Route
Route也称为路由,是APISIX中最基础和最核心的资源对象。
APISIX可以通过路由定义规则来匹配客户端请求,根据匹配结果加载并执行相应的插件,最后把请求转发给到指定的上游服务。路由中主要包含三部分内容:匹配规则、插件配置和上游信息。
Service
Service也称为服务,是某类API的抽象(也可以理解为一组Route的抽象)。它通常与上游服务抽象是一一对应的,Route与Service之间,通常是N:1
的关系。
对APISIX的管理操作,几乎都是在围绕这三者来进行。
APISIX实践
如下使用APISIX来实践发布API,保护API,监控API等操作。
发布API
1.创建Upstream
curl "http://127.0.0.1:9180/apisix/admin/upstreams/1" \
-H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1" -X PUT -d '
{
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1 # 这里数数字1表示权重
}
}'
在请求路径http://127.0.0.1:9180/apisix/admin/upstreams/1
中的最后部分数字1
表示设置upstream_id为1。
可以在nodes
对象下指定多个目标地址,以达到负载均衡的效果。
2.创建Route
curl "http://127.0.0.1:9180/apisix/admin/routes/1" \
-H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1" -X PUT -d '
{
"methods": ["GET"],
"host": "example.com",
"uri": "/anything/*",
"upstream_id": "1" # 在路由中指定upstream_id
}'
注意: 创建上游非必须步骤,可以通过在路由中,添加upstream
对象,达到先创建Upstream再创建Route的效果。
curl "http://127.0.0.1:9180/apisix/admin/routes/1" \
-H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1" -X PUT -d '
{
"methods": ["GET"],
"host": "example.com",
"uri": "/anything/*",
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
在请求路径http://127.0.0.1:9180/apisix/admin/routes/1
中的最后部分数字1
表示设置路由id为1,用于唯一标识一条路由信息,在管理后台可以看到这个ID。
当然,路由ID还可以通过在请求消息体中指定:
curl -i "http://127.0.0.1:9180/apisix/admin/routes?api_key=edd1c9f034335f136f87ad84b625c8f1" -X PUT -d '
{
"id": "getting-started-ip", # 在请求消息体中指定路由ID
"uri": "/ip",
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
验证:
curl "http://127.0.0.1:9080/ip"
返回:
{
"origin": "172.18.0.1, 124.126.139.14"
}
另外,如果在创建路由时对上游服务指定了多个目标节点,客户端在访问API时将使用负载均衡机制访问目标服务。
如下示例演示添加路由:当访问路径“/headers”时,将使用轮询机制转发到“httpbin.org”或“mock.api7.ai”
curl -i "http://127.0.0.1:9180/apisix/admin/routes?api_key=edd1c9f034335f136f87ad84b625c8f1" -X PUT -d '
{
"id": "getting-started-headers", # 在请求消息体中指定路由ID
"uri": "/headers",
"upstream" : {
"type": "roundrobin",
"nodes": {
"httpbin.org:443": 1,
"mock.api7.ai:443": 1
},
"pass_host": "node",
"scheme": "https"
}
}'
验证:
curl "http://127.0.0.1:9080/headers"
来自“httpbin.org”的响应结果:
{
"headers": {
"Accept": "*/*",
"Host": "httpbin.org",
"User-Agent": "curl/7.61.1",
"X-Amzn-Trace-Id": "Root=1-64cf349d-5d3ca35e246ed48c0e7e2b49",
"X-Forwarded-Host": "127.0.0.1"
}
}
来自“mock.api7.ai”的响应结果:
{
"headers": {
"accept": "*/*",
"accept-encoding": "gzip",
"cf-connecting-ip": "124.126.139.14",
"cf-ipcountry": "CN",
"cf-ray": "7f25017fdb898873",
"cf-visitor": "{\"scheme\":\"https\"}",
"connection": "Keep-Alive",
"content-type": "application/json",
"host": "mock.api7.ai",
"user-agent": "curl/7.61.1",
"x-application-owner": "API7.ai",
"x-forwarded-for": "172.18.0.1",
"x-forwarded-host": "127.0.0.1",
"x-forwarded-port": "9080",
"x-forwarded-proto": "https",
"x-real-ip": "124.126.139.14",
"X-Application-Owner": "API7.ai",
"Content-Type": "application/json"
}
}
产生10个请求来验证负载均衡效果:
hc=$(seq 10 | xargs -i curl "http://127.0.0.1:9080/headers" -sL | grep "httpbin" | wc -l); echo httpbin.org: $hc, mock.api7.ai: $((10 - $hc))
输出:
httpbin.org: 6, mock.api7.ai: 4
3.测试Route
在创建完成路由后,你可以通过以下命令测试路由是否正常:
curl -i -X GET "http://127.0.0.1:9080/anything/get?foo1=bar1&foo2=bar2" -H "Host: example.com"
返回:
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 462
Connection: keep-alive
Date: Mon, 07 Aug 2023 02:22:28 GMT
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Server: APISIX/3.4.1
{
"args": {
"foo1": "bar1",
"foo2": "bar2"
},
"data": "",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Host": "example.com",
"User-Agent": "curl/7.61.1",
"X-Amzn-Trace-Id": "Root=1-64d05564-2f4a04cc40f5806822c53bb6",
"X-Forwarded-Host": "example.com"
},
"json": null,
"method": "GET",
"origin": "172.18.0.1, 124.126.139.14",
"url": "http://example.com/anything/get?foo1=bar1&foo2=bar2"
}
保护API
在APISIX中通过插件来实现API保护,在具体实现上是通过限流限速和安全插件保护API服务,限制非正常的访问请求,保障API服务的稳定运行。
APISIX提供了多个限流限速的插件,包括limit-conn
、limit-req
和limit-count
。
- limit-conn插件主要用于限制客户端对服务的并发请求数。
- limit-req插件使用漏桶算法限制对用户服务的请求速率。
- limit-count插件主要用于在指定的时间范围内,限制每个客户端总请求个数。
APISIX除了提供限流限速的插件外,还提供了很多其他的关于流量的插件来满足实际场景的需求:
- proxy-cache:该插件提供缓存后端响应数据的能力,它可以和其他插件一起使用。该插件支持基于磁盘和内存的缓存。
- request-validation:该插件用于提前验证向上游服务转发的请求。
- proxy-mirror:该插件提供了镜像客户端请求的能力。流量镜像是将线上真实流量拷贝到镜像服务中,以便在不影响线上服务的情况下,对线上流量或请求内容进行具体的分析。
- api-breaker:该插件实现了 API 熔断功能,从而帮助我们保护上游业务服务。
- traffic-split:该插件使用户可以逐步引导各个上游之间的流量百分比。,你可以使用该插件实现蓝绿发布,灰度发布。
- request-id:该插件通过 APISIX 为每一个请求代理添加 unique ID 用于追踪 API 请求。
- proxy-control:该插件能够动态地控制 NGINX 代理的相关行为。
- client-control:该插件能够通过设置客户端请求体大小的上限来动态地控制 NGINX 处理客户端的请求。
同时,也提供了许多用户认证和授权的插件:
- Key Authentication:用于向
Route
或Service
添加身份验证密钥(API key),需要与Consumer
一起配合才能工作,通过Consumer
将其密钥添加到查询字符串参数或标头中以验证其请求。 - Basic Authentication:使用
basic-auth
插件可以将Basic_access_authentication
添加到Route
或Service
中。 - JSON Web Token (JWT) Authentication:用于将
JWT
身份验证添加到Service
或Route
中,通过Consumer
将其密匙添加到查询字符串参数、请求头或cookie
中用来验证其请求。 - Keycloak:用于通过
Keycloak Identity Server
添加身份验证。 - Casdoor:使用
authz-casdoor
插件可添加Casdoor
集中认证方式。 - Wolf RBAC:
wolf-rbac
插件为role-based access control
系统提供了添加wolf
到Route
或Service
的功能。此插件需要与Consumer
一起使用。 - OpenID Connect:OpenID Connect(OIDC)是基于
OAuth 2.0
的身份认证协议,APISIX可以与支持该协议的身份认证服务对接,如Okta、Keycloak、Ory Hydra、Authing等,实现对客户端请求的身份认证。 - Central Authentication Service (CAS):使用
cas-auth
查询从SP(服务提供者)的角度访问CAS(中央身份验证服务2.0)IdP(身份提供者)来进行身份验证。 - HMAC:将
HMAC authentication
添加到Route
或者Service
,该插件需要和Consumer
一起使用,API的使用者必须将密匙添加到请求头中以验证其请求。 - Casbin:
authz-casbin
插件是一个基于Lua Casbin的访问控制插件,该插件支持各种access control models的强大授权场景。 - LDAP:
ldap-auth
插件可用于给路由或服务添加LDAP身份认证,该插件使用lua-resty-ldap连接LDAP服务器。 - Open Policy Agent (OPA):
opa
插件可用于与Open Policy Agent进行集成,实现后端服务的认证授权与访问服务等功能解耦,减少系统复杂性。 - Forward Authentication:
forward-auth
插件使用的是经典外部认证。当身份认证失败时,可以实现自定义错误或者重定向到认证页面的场景。forward-auth
插件巧妙地将身份认证和授权逻辑移到了一个专门的外部服务中,APISIX将用户的请求转发给认证服务并阻塞原始请求,然后在认证服务下以非2xx
状态响应时进行结果替换。
限流限速
如下以limit-count插件为例,介绍如何通过限流限速插件保护API服务。
1.创建上游
curl "http://127.0.0.1:9180/apisix/admin/upstreams/1" \
-H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1" -X PUT -d '
{
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}'
2.创建路由
curl -i http://127.0.0.1:9180/apisix/admin/routes/1 \
-H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"uri": "/index.html",
"plugins": {
"limit-count": { # 使用limit-count插件限定在60秒内最多只能访问上游2次,超过2次则返回503状态码
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key_type": "var",
"key": "remote_addr"
}
},
"upstream_id": "1" # 指定了upstream_id
}'
3.测试插件:
curl http://127.0.0.1:9080/index.html
使用上述命令在60秒内连续访问3次后,则会出现如下错误。
<html>
<head><title>503 Service Temporarily Unavailable</title></head>
<body>
<center><h1>503 Service Temporarily Unavailable</h1></center>
<hr><center>openresty</center>
<p><em>Powered by <a href="https://apisix.apache.org/">APISIX</a>.</em></p></body>
</html>
同时产生100个请求查看限速插件的效果:
count=$(seq 100 | xargs -i curl "http://127.0.0.1:9080/index.html" -I -sL | grep "503" | wc -l); echo \"200\": $((100 - $count)), \"503\": $count
输出:
# 100个请求只有2个可以正常执行,98个都失败了
"200": 2, "503": 98
授权认证
如下以key-auth
插件为例,限定访问指定路由时需要携带认证信息。
1.添加消费者(Consumer):
curl -i "http://127.0.0.1:9180/apisix/admin/consumers?api_key=edd1c9f034335f136f87ad84b625c8f1" -X PUT -d '
{
"username": "tom",
"plugins": {
"key-auth": {
"key": "abcdefghijklmnopqrstuvwxyz"
}
}
}'
2.对指定路由启用Key认证:getting-started-ip
curl -i "http://127.0.0.1:9180/apisix/admin/routes/getting-started-ip?api_key=edd1c9f034335f136f87ad84b625c8f1" -X PATCH -d '
{
"plugins": {
"key-auth": {}
}
}'
验证:
# 不带API-KEY访问:
curl -i "http://127.0.0.1:9080/ip"
# 返回:
HTTP/1.1 401 Unauthorized
Date: Sun, 06 Aug 2023 06:07:47 GMT
Content-Type: text/plain; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Server: APISIX/3.4.1
{"message":"Missing API key found in request"}
# 带API-KEY访问(使用正确的API-KEY):
curl -i "http://127.0.0.1:9080/ip" -H 'apikey: abcdefghijklmnopqrstuvwxyz'
# 返回:
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 45
Connection: keep-alive
Date: Sun, 06 Aug 2023 06:08:52 GMT
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Server: APISIX/3.4.1
{
"origin": "172.18.0.1, 124.126.139.14"
}
# 使用不正确的API-KEY访问:
curl -i "http://127.0.0.1:9080/ip" -H 'apikey: abcdefghijklmnopqrstuvwxyz123'
# 返回:
HTTP/1.1 401 Unauthorized
Date: Sun, 06 Aug 2023 06:09:39 GMT
Content-Type: text/plain; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Server: APISIX/3.4.1
{"message":"Invalid API key in request"}
监控API
APISIX中提供了很多具有丰富功能的可观测性插件,可以通过使用和设置这些插件,来了解API行为,进而使整个业务流程更加清晰。
API可观测性可分为三个关键部分:日志、指标、链路追踪。
日志
可以通过一些APISIX的日志插件,将APISIX的日志发送到指定的日志服务中。
以下示例展示了在指定路由上启动http-logger
的示例。
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"plugins": {
"http-logger": {
"uri": "http://mockbin.org/bin/5451b7cd-af27-41b8-8df1-282ffea13a61"
}
},
"upstream_id": "1",
"uri": "/get"
}'
注意: 可以通过修改uri
属性,将上述http-logger
的服务器地址更换为其他服务器地址:
{
"uri": "http://mockbin.org/bin/5451b7cd-af27-41b8-8df1-282ffea13a61"
}
创建成功后,可以通过以下命令向get
端点发送请求以生成日志。
curl -i http://127.0.0.1:9080/get
请求成功后,可以单击模拟服务器链接查看访问日志。
展示效果如下:
指标
指标是在⼀段时间内测量的数值。与日志不同,指标在默认情况下是结构化的,这使得查询和优化存储变得更加容易。
而APISIX
也提供了Prometheus
的插件来获取API
指标,并在Prometheus
中暴露它们。
通过使用APISIX
提供的Grafana
仪表板元数据,并从Prometheus
中获取指标,更加方便地监控API
。
通过以下命令启用prometheus
插件:
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"uri": "/get",
"plugins": {
"prometheus": {}
},
"upstream_id": "1" # 指定stream_id
}'
启用成功后,可以通过/apisix/prometheus/metrics
接口获取APISIX
的指标。
curl -i http://127.0.0.1:9091/apisix/prometheus/metrics
还可以通过http://localhost:9090/targets
在Prometheus
仪表板上查看端点的状态。
链路追踪
链路追踪就是将一次请求还原成调用链路,并将该请求的调用情况使用拓扑的方式展现,比如展示各个微服务节点上的耗时,请求具体经过了哪些服务器以及每个服务节点的请求状态等内容。
通过如下示例,在指定路由中启用zipkin
插件:
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"methods": [
"GET"
],
"uri": "/get",
"plugins": {
"zipkin": {
"endpoint": "http://127.0.0.1:9411/api/v2/spans",
"sample_ratio": 1
}
},
"upstream_id": "1" # 指定upstream_id
}'
通过以下命令请求APISIX:
curl -i http://127.0.0.1:9080/get
如下所示,返回结果中的header
部分附加了一些额外的跟踪标识符(TraceId、SpanId和ParentId):
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 470
Connection: keep-alive
Date: Sun, 06 Aug 2023 10:03:16 GMT
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Server: APISIX/3.4.1
{
"args": {},
"headers": {
"Accept": "*/*",
"Host": "127.0.0.1",
"User-Agent": "curl/7.61.1",
"X-Amzn-Trace-Id": "Root=1-64cf6fe0-09e409de516b26f632946e46",
"X-B3-Parentspanid": "1b9b7f3fe43796c2", // ParentId
"X-B3-Sampled": "1",
"X-B3-Spanid": "0e881fc8b8fe5ec6", // SpanId
"X-B3-Traceid": "267172faeb84010f3c50229afdb851d6", // TraceId
"X-Forwarded-Host": "127.0.0.1"
},
"origin": "172.18.0.1, 124.126.139.14",
"url": "http://127.0.0.1/get"
}
【参考】
Get APISIX
为什么Apache APISIX选择NGINX+Lua技术栈?
apisix高性能网关-中文开发文档
王院生:Apache APISIX 微服务网关极致性能架构解析
再谈 APISIX 高性能实践
APISIX架构分析:如何动态管理Nginx集群?
保姆级教程,从概念到实践帮你快速上手 Apache APISIX Ingress
实践一年之久,vivo 如何基于 APISIX 进行业务基础架构的演进
APISIX网关在雪球生产实践
APISIX+Dubbo+Nacos 最佳实践