apisix/doc/architecture-design-cn.md
2019-09-18 12:16:32 +08:00

15 KiB
Raw Blame History

目录

APISIX

插件加载流程

插件内部结构

APISIX Config

通过修改本地 conf/config.yaml 文件完成对 APISIX 服务本身的基本配置。

apisix:
  node_listen: 9080             # APISIX listening port

etcd:
  host: "http://127.0.0.1:2379" # etcd address
  prefix: "apisix"              # apisix configurations prefix
  timeout: 60

plugins:                        # plugin name list
  - example-plugin
  - limit-req
  - limit-count
  - ...

注意 不要手工修改 APISIX 自身的 conf/nginx.conf 文件,当服务每次启动时,apisix 会根据 conf/config.yaml 配置自动生成新的 conf/nginx.conf 并自动启动服务。

返回目录

Route

Route 字面意思就是路由,通过定义一些规则来匹配客户端的请求,然后根据匹配结果加载并执行相应的 插件,并把请求转发给到指定 Upstream。

Route 中主要包含三部分内容:匹配规则(比如 uri、host、remote_addr 等),插件配置(限流限速等)和上游信息。 请看下图示例,是一些 Route 规则的实例,当某些属性值相同时,图中用相同颜色标识。

我们直接在 Route 中完成所有参数的配置,优点是容易设置,每个 Route 都相对独立自由度比较高。但当我们的 Route 有比较多的重复配置(比如启用相同的插件配置或上游信息),一旦我们要更新这些相同属性时,就需要遍历所有 Route 并进行修改,给后期管理维护增加不少复杂度。

上面提及重复的缺点在 APISIX 中独立抽象了 ServiceUpstream 两个概念来解决。

下面创建的 Route 示例,是把 uri 为 "/index.html" 的请求代理到地址为 "39.97.63.215:80" 的 Upstream 服务:

$ curl http://127.0.0.1:9080/apisix/admin/routes/1 -X PUT -i -d '
{
    "uri": "/index.html",
    "upstream": {
        "type": "roundrobin",
        "nodes": {
            "39.97.63.215:80": 1
        }
    }
}'

HTTP/1.1 201 Created
Date: Sat, 31 Aug 2019 01:17:15 GMT
Content-Type: text/plain
Transfer-Encoding: chunked
Connection: keep-alive
Server: APISIX web server

{"node":{"value":{"uri":"\/index.html","upstream":{"nodes":{"39.97.63.215:80":1},"type":"roundrobin"}},"createdIndex":61925,"key":"\/apisix\/routes\/1","modifiedIndex":61925},"action":"create"}

当我们接受到成功应答,表示该 Route 已成功创建。

Route 选项

除了 uri 匹配条件外,还支持更多过滤条件。

名字 可选项 类型 说明
uri 必须 匹配规则 除了如 /foo/bar/foo/gloo 这种全量匹配外,使用不同 Router 还允许更高级匹配,更多见 Router
host 可选 匹配规则 当前请求域名,比如 foo.com;也支持泛域名,比如 *.foo.com
remote_addr 可选 匹配规则 客户端请求 IP 地址,比如 192.168.1.101192.168.1.102,也支持 CIDR 格式如 192.168.1.0/24。特别的APISIX 也完整支持 IPv6 地址匹配,比如:::1fe80::1, fe80::1/64 等。
methods 可选 匹配规则 如果为空或没有该选项,代表没有任何 method 限制也可以是一个或多个组合GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONSCONNECTTRACE。
plugins 可选 Plugin 详见 Plugin
upstream 可选 Upstream 启用的 Upstream 配置,详见 Upstream
upstream_id 可选 Upstream 启用的 upstream id详见 Upstream
service_id 可选 Service 绑定的 Service 配置,详见 Service

返回目录

Service

Service 是某类 API 的抽象(也可以理解为一组 Route 的抽象)。它通常与上游服务抽象是一一对应的,RouteService 之间,通常是 N:1 的关系,参看下图。

不同 Route 规则同时绑定到一个 Service 上,这些 Route 将具有相同的上游和插件配置,减少冗余配置。

比如下面的例子,创建了一个启用限流插件的 Service然后把 id 为 100101 的 Route 都绑定在这个 Service 上。

# create new Service
$ curl http://127.0.0.1:9080/apisix/admin/services/200 -X PUT -d '
{
    "plugins": {
        "limit-count": {
            "count": 2,
            "time_window": 60,
            "rejected_code": 503,
            "key": "remote_addr"
        }
    },
    "upstream": {
        "type": "roundrobin",
        "nodes": {
            "39.97.63.215:80": 1
        }
    }
}'

# create new Route and reference the service by id `200`
curl http://127.0.0.1:9080/apisix/admin/routes/100 -X PUT -d '
{
    "methods": ["GET"],
    "uri": "/index.html",
    "service_id": "200"
}'

curl http://127.0.0.1:9080/apisix/admin/routes/101 -X PUT -d '
{
    "methods": ["GET"],
    "uri": "/foo/index.html",
    "service_id": "200"
}'

当然我们也可以为 Route 指定不同的插件参数或上游,比如下面这个 Route 设置了不同的限流参数,其他部分(比如上游)则继续使用 Service 中的配置参数。

curl http://127.0.0.1:9080/apisix/admin/routes/102 -X PUT -d '
{
    "uri": "/bar/index.html",
    "id": "102",
    "service_id": "200",
    "plugins": {
        "limit-count": {
            "count": 2000,
            "time_window": 60,
            "rejected_code": 503,
            "key": "remote_addr"
        }
    }
}'

注意:当 Route 和 Service 都开启同一个插件时Route 参数的优先级是高于 Service 的。

返回目录

Plugin

Plugin 表示将在 HTTP 请求/响应生命周期期间执行的插件配置。

Plugin 配置可直接绑定在 Route 上,也可以被绑定在 ServiceConsumer上。而对于同一 个插件的配置,只能有一份是有效的,配置选择优先级总是 Consumer > Route > Service

conf/config.yaml 中,可以声明本地 APISIX 节点都支持哪些插件。这是个白名单机制,不在该 白名单的插件配置,都将会被自动忽略。这个特性可用于临时关闭或打开特定插件,应对突发情况非常有效。

插件的配置可以被直接绑定在指定 Route 中,也可以被绑定在 Service 中,不过 Route 中的插件配置 优先级更高。

一个插件在一次请求中只会执行一次,即使被同时绑定到多个不同对象中(比如 Route 或 Service。 插件运行先后顺序是根据插件自身的优先级来决定的,例如:example-plugin

插件配置作为 Route 或 Service 的一部分提交的,放到 plugins 下。它内部是使用插件 名字作为哈希的 key 来保存不同插件的配置项。

{
    ...
    "plugins": {
        "limit-count": {
            "count": 2,
            "time_window": 60,
            "rejected_code": 503,
            "key": "remote_addr"
        },
        "prometheus": {}
    }
}

并不是所有插件都有具体配置项,比如 prometheus 下是没有任何具体配置项,这时候用一个空的对象 标识即可。

查看 APISIX 已支持插件列表

返回目录

Upstream

Upstream 是虚拟主机抽象对给定的多个服务节点按照配置规则进行负载均衡。Upstream 的地址信息可以直接配置到 Route(或 Service) 上,当有 Upstream 有重复时,就需要用“引用”方式避免重复了。

如上图所示,通过创建 Upstream 对象,在 Route 用 ID 方式引用,就可以确保只维护一个对象的值了。

Upstream 的配置可以被直接绑定在指定 Route 中,也可以被绑定在 Service 中,不过 Route 中的配置 优先级更高。这里的优先级行为与 Plugin 非常相似

配置参数

APISIX 的 Upstream 除了基本的复杂均衡算法选择外,还支持对上游做主被动健康检查、重试等逻辑,具体看下面表格。

名字 可选 说明
type 必需 roundrobin 支持权重的负载,chash 一致性哈希,两者是二选一的
nodes 必需 哈希表,内部元素的 key 是上游机器地址列表IP+Port 方式value 则是节点的 weight。无论对于 roundrobin 还是 chash 算法,上游节点的选择都依赖它。特别的,权重值为 0 有特殊含义,通常代表该上游节点失效,永远不希望被选中。
key 必需 该选项只有类型是 chash 才有效。根据 key 来查找对应的 node id,相同的 key 在同一个对象中,永远返回相同 id
checks 可选 配置健康检查的参数,详细可参考health-check
retries 可选 使用底层的 Nginx 重试机制将请求传递给下一个上游,默认不启用重试机制
scheme 可选 转发到上游的 schema 协议,可以是 httphttps,默认 http 协议
uri 可选 转发到上游的新 uri 地址
host 可选 转发到上游的新 host
enable_websocket 可选 是否启用 websocket (布尔值),默认不启用

创建上游对象用例:

curl http://127.0.0.1:9080/apisix/admin/upstreams/1 -X PUT -d '
{
    "type": "roundrobin",
    "nodes": {
        "127.0.0.1:80": 1,
        "127.0.0.2:80": 1,
        "127.0.0.3:80": 1
    }
}'

curl http://127.0.0.1:9080/apisix/admin/upstreams/2 -X PUT -d '
{
    "type": "chash",
    "key": "remote_addr",
    "nodes": {
        "127.0.0.1:80": 1,
        "127.0.0.2:80": 1
    }
}'

上游对象创建后,均可以被具体 RouteService 引用,例如:

curl http://127.0.0.1:9080/apisix/admin/routes/1 -X PUT -d '
{
    "uri": "/index.html",
    "upstream_id": 2
}'

为了方便使用,也可以直接把上游地址直接绑到某个 RouteService ,例如:

curl http://127.0.0.1:9080/apisix/admin/routes/1 -X PUT -d '
{
    "uri": "/index.html",
    "plugins": {
        "limit-count": {
            "count": 2,
            "time_window": 60,
            "rejected_code": 503,
            "key": "remote_addr"
        }
    },
    "upstream": {
        "type": "roundrobin",
        "nodes": {
            "39.97.63.215:80": 1
        }
    }
}'

下面是一个配置了健康检查的示例:

curl http://127.0.0.1:9080/apisix/admin/routes/1 -X PUT -d '
{
    "uri": "/index.html",
    "plugins": {
        "limit-count": {
            "count": 2,
            "time_window": 60,
            "rejected_code": 503,
            "key": "remote_addr"
        }
    },
    "upstream": {
         "nodes": {
            "39.97.63.215:80": 1
        }
        "type": "roundrobin",
        "retries": 2,
        "checks": {
            "active": {
                "http_path": "/status",
                "host": "foo.com",
                "healthy": {
                    "interval": 2,
                    "successes": 1
                },
                "unhealthy": {
                    "interval": 1,
                    "http_failures": 2
                }
            }
        }
    }
}'

更多细节可以参考健康检查的文档

返回目录

Router

APISIX 区别于其他 API 网关的一大特点是允许用户选择不同 Router 来更好匹配自由业务,在性能、自由之间做最适合选择。

在本地配置 conf/config.yaml 中设置最符合自身业务需求的路由。

  • apisix.router.http: HTTP 请求路由。

    • radixtree_uri: (默认)只使用 uri 作为主索引。基于 radix tree 引擎,支持全量和深前缀匹配,更多见 如何使用 router-radixtree
      • 绝对匹配:完整匹配给定的 uri ,比如 /foo/bar/foo/glo
      • 前缀匹配:末尾使用 * 代表给定的 uri 是前缀匹配。比如 /foo*,则允许匹配 /foo//foo/a/foo/b等。
      • 匹配优先级:优先尝试绝对匹配,若无法命中绝对匹配,再尝试前缀匹配。
      • 任意过滤属性:允许指定任何 Ningx 内置变量作为过滤条件,比如 uri 请求参数、请求头、cookie 等。
    • r3_uri: 只使用 uri 作为主索引(基于 r3 引擎)。基于 r3 的 trie tree 是支持正则匹配的,比如 /foo/{:\w+}/{:\w+},更多见 如何使用 router-r3
    • r3_host_uri: 使用 host + uri 作为主索引(基于 r3 引擎),对当前请求会同时匹配 host 和 uri。
  • apisix.router.ssl: SSL 加载匹配路由。

    • radixtree_sni: (默认)使用 SNI (Server Name Indication) 作为主索引(基于 radixtree 引擎)。
    • r3_sni: 使用 SNI (Server Name Indication) 作为主索引(基于 r3 引擎)。

返回目录

Consumer

对于 API 网关通常可以用请求域名、客户端 IP 地址等字段识别到某类请求方, 然后进行插件过滤并转发请求到指定上游,但有时候这个深度不够。

如上图所示,作为 API 网关,需要知道 API Consumer消费方具体是谁这样就可以对不同 API Consumer 配置不同规则。

在 APISIX 中,识别 Consumer 的过程如下图:

  1. 授权认证:比如有 key-authJWT 等。
  2. 获取 consumer_id通过授权认证即可自然获取到对应的 Consumer id,它是 Consumer 对象的唯一识别标识。
  3. 获取 Consumer 上绑定的 Plugin 或 Upstream 信息:完成对不同 Consumer 做不同配置的效果。

概括一下Consumer 是某类服务的消费者,需与用户认证体系配合才能使用。 比如不同的 Consumer 请求同一个 API网关服务根据当前请求用户信息对应不同的 Plugin 或 Upstream 配置。

此外,大家也可以参考 key-auth 认证授权插件的调用逻辑,辅助大家来进一步理解 Consumer 概念和使用。

注意:目前 APISIX 的 Consumer 还不支持绑定插件或上游信息,如果大家对这个功能点感兴趣,欢迎在社区中反馈交流。

返回目录

Debug mode

开启调试模式后,会在请求应答时,输出更多的内部信息,比如加载了哪些插件等。

设置 conf/config.yaml 中的 apisix.enable_debugtrue,即可开启调试模式。

比如对 /hello 开启了 limit-connlimit-count插件,这时候应答头中会有 Apisix-Plugins: limit-conn, limit-count 出现。

$ curl http://127.0.0.1:1984/hello -i
HTTP/1.1 200 OK
Content-Type: text/plain
Transfer-Encoding: chunked
Connection: keep-alive
Apisix-Plugins: limit-conn, limit-count
X-RateLimit-Limit: 2
X-RateLimit-Remaining: 1
Server: openresty

hello world

返回目录