APISIX,一个以Apache方式存在的API网关

239 阅读9分钟

在万维网的先锋领域,内容是静态的。为了提供服务,一群开发人员创建了一个网络服务器,也就是现在的Apache网络服务器

阿帕奇网络服务器是围绕着一个模块架构建立的。开发人员创建了一个模块来运行CGI脚本,以将动态内容添加到该地段。用户用Perl编写早期的CGI脚本。一段时间后,人们发现从头开始生成一个完整的HTML页面并不是最好的方法,模板化--提供一个带有占位符的HTML页面--是一个更好的方法。PHP语言就是这样开始的,它是一个由模块解释的简单模板引擎。

然后,人们开始认为Web服务器的核心职责不是生成内容,而是提供内容。这种关注点的分离将单体的Web服务器分成了两个部分:前台的Web服务器提供静态内容,应用服务器生成动态内容,一般是从数据库中存储的数据。

反向代理

组织保留了这种架构,即使应用服务器可以提供静态内容。我记得在2007年左右,我读了一篇文章,对Apache Web服务器和Apache Tomcat(一种基于Java的应用服务器)的性能进行了基准测试:要提供纯粹的静态内容,后者与前者不相上下,甚至更快一点。

在纸面上,删除网络服务器是有意义的。我甚至曾经向我当时工作的公司的经理主张这样做。组织的惯性减缓了这一举措,然后我就离开了。在当时,我感到很失望。事后看来,这并不是一个明智之举。

原因是,除了直接为内容服务外,网络服务器还必须将请求路由到其他组件。在这方面,他们也成了路由专家,基于一些属性:域名,当然,路径,甚至是HTTP头。因此,网络服务器的责任与其说是服务内容,不如说是进入其他基础设施的单一入口点。

同时,专注于通信的网站演变为成熟的网络交易应用程序。网络应用在公司与其周围的生态系统--潜在客户、客户、供应商等之间的互动中占据了越来越大的份额。当你的业务依赖于一块基础设施时,你需要将其停机时间保持在最低限度:这意味着配置关键组件的冗余,并将请求引导到可用的组件上。路由不再是简单的路由,而是几个相同的服务器之间的负载平衡。

在引入负载平衡后,增加越来越多的功能是很容易的。入口点开始处理跨领域的责任:认证(但不一定是授权)、缓存、IP封锁等。网络服务器成为一个反向代理

API的兴起

随着时间的推移,服务的数量成倍增长,同时它们也需要相互沟通。在同一组织内,长期以来的传统是尽可能少地保留技术栈,具体数量取决于组织的规模。

然而,当服务必须与另一个组织的服务进行通信时,事情就变得一团糟,因为拥有不同技术栈的可能性变得更高。诞生于微软的SOAP,后来成为W3C的标准(或标准的集合),是第一个提出堆栈中立方法的严肃尝试。

尽管它在企业界得到了广泛的应用,但它在自己的重量下崩溃了。在企业中,标准的增加成为一个泥潭。在企业外部,前端开发者(即JavaScript)发现处理HTTP和JSON要容易得多。越多的前端开发者来到市场上,他们就越不愿意和SOAP打交道。

当SOAP的受欢迎程度减弱时,HTTP的受欢迎程度(我不敢写REST)却在上升。HTTP成为在互联网上整合异质信息系统的事实上的标准。公司开始通过HTTP提供对其系统的访问:Web APIs。很快,大多数公司放弃了Web部分,而API随着时间的推移隐含了Web的含义。

考虑到这一点,我们忠实的网络服务器演变成了现在的形式,即API网关。这有很大的意义:网络服务器已经作为反向代理的中心入口点了。现在,我们只需要添加针对API的功能。它们是哪些呢?

对API网关的需求

这里有两个基本的能力,突出了对API的需求,即普通的Web服务器无法提供的东西。

复杂的速率限制

速率限制是一种通用的能力,可以保护自己的信息系统免受DDoS攻击。然而,当你区分消费者时,例如免费与付费,你需要从简单的费率转向更复杂的商业逻辑规则。

计费

如果你支付了订阅费用,你可能会访问一个有常规内容的资源。然而,当你的业务是销售数据时,你可能会根据数量消费来销售它们。虽然服务本身有可能嵌入计费功能,但它阻止了更多的分布式架构,即依靠几个服务来提供所需的数据。在这一点上,只有一个中央接入点可以可靠地测量和收取使用量。

Apache APISIX

最广泛的API网关的一个非详尽列表包括。

  • Apache APISIX
  • Kong网关
  • Tyk
  • Gloo
  • 大使
  • 谷维德
我特意漏掉了云供应商的网关,因为它们将你锁定在他们的生态系统中。

APISIX在智略科技开发后,于2019年6月捐赠给Apache基金会,并于2020年7月成为一个顶级项目。作为ASF择优录取方法的一部分,你必须首先成为一个积极的贡献者,才能获得提交者的权利。

在技术方面,APISIX是基于流行的Nginx网络服务器,上面有一个Lua引擎(OpenResty)和一个插件架构。

APISIX提供了几个核心对象。

上游

虚拟主机抽象,根据配置规则在一组给定的服务节点上执行负载平衡

消费者

客户的身份

路由

路由通过定义规则来匹配客户的请求,然后根据匹配结果加载和执行相应的插件,并将请求转发给指定的上游。

服务

一个可重复使用的对象,它同时绑定了一组插件和一个上游。

Apache APISIX common objects

对象存储在etcd中,这是一个分布式键值存储,也被Kubernetes使用。Apache APISIX暴露了一个REST API,这样你就可以以一种技术无关的方式访问配置。在这里,我们请求所有现有的路由。

curl http://apisix:9080/apisix/admin/routes -H 'X-API-KEY: xyz'    (1)
1配置访问默认是受保护的。人们需要传递API密钥。

使用其他对象的对象可以定义它们或指向现有的参考。例如,人们可以把一个独立的Route 定义为。

curl http://apisix:9080/apisix/admin/routes/1 -H 'X-API-KEY: xyz' -X PUT -d '
{
  "uri": "/foo",
  "upstream": {
    "type": "roundrobin",
    "nodes": {
      "127.0.0.1:8080": 1
    }
  }
}'

或者,首先,定义一个Upstream

curl http://apisix:9080/apisix/admin/upstreams/1 -H 'X-API-KEY: xyz' -X PUT -d '
{
  "type": "roundrobin",
  "nodes": {
    "127.0.0.1:8080": 1
  }
}'

现在我们可以在一个新的Route 中引用新创建的Upstream

curl http://apisix:9080/apisix/admin/routes/2 -H 'X-API-KEY: xyz' -X PUT -d '
{
  "uri": "/bar",
  "upstream_id": 1
}'

让你的脚踏实地

尝试Apache APISIX的最快捷方式是通过Docker。Apache APISIX的配置依赖于etcd,所以让我们使用Docker Compose。

version: "3"

services:
  apisix:
    image: apache/apisix:2.12.1-alpine                                      (1)
    command: sh -c "/opt/util/wait-for etcd:2397 -- /usr/bin/apisix init && /usr/bin/apisix init_etcd && /usr/local/openresty/bin/openresty -p /usr/local/apisix -g 'daemon off;'" (2)
    volumes:
      - ./apisix_log:/usr/local/apisix/logs
      - ./apisix_conf/config.yaml:/usr/local/apisix/conf/config.yaml:ro
      - ./util:/opt/util:ro                                                 (2)
    ports:
      - "9080:9080"
      - "9091:9091"
      - "9443:9443"
    depends_on:
      - etcd
  etcd:
    image: bitnami/etcd:3.5.2                                               (3)
    environment:
      ETCD_ENABLE_V2: "true"
      ALLOW_NONE_AUTHENTICATION: "yes"
      ETCD_ADVERTISE_CLIENT_URLS: "http://0.0.0.0:2397"                     (4)
      ETCD_LISTEN_CLIENT_URLS: "http://0.0.0.0:2397"                        (4)
    ports:
      - "2397:2397"
1Apache APISIX图像
2技巧是等待etcd完全初始化,而不仅仅是启动。depends_on 属性是不够的
3etcd图像
4如果你激活了Kubernetes,Docker Desktop会启动自己的etcd。为了避免端口冲突,让我们改变默认端口。

我们在config.yaml 文件中配置Apache APISIX。一个最小的配置文件看起来像这样。

apisix:
  node_listen: 9080
  allow_admin:
    - 0.0.0.0/0
  admin_key:
    - name: "admin"
      key: edd1c9f034335f136f87ad84b625c8f1
      role: admin
etcd:
  host:
    - "http://etcd:2397"
  prefix: "/apisix"
  timeout: 30

我们现在可以创建一个简单的路由。我们将代理httpbin.org服务。

#!/bin/sh
curl http://localhost:9080/apisix/admin/routes -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X POST -d '
{
  "name": "Route to httpbin",
  "uris": ["/*"],
  "upstream": {
    "type": "roundrobin",
    "nodes": {
      "httpbin.org": 1
    }
  }
}'

我们现在可以测试这个路由了。httpbin 提供了几个端点。命名恰当的/anything 端点返回请求数据中传递的任何内容。我们可以使用这个端点来检查所有的工作是否符合预期。

curl 'localhost:9080/anything?foo=bar&baz' -X POST -d '{ "hello": "world" }' -H 'Content-Type: application/json'

输出结果应该与以下内容非常相似。

{
  "args": {
    "baz": "",
    "foo": "bar"
  },
  "data": "{ \"hello\": \"world\" }",
  "files": {},
  "form": {},
  "headers": {
    "Accept": "*/*",
    "Content-Length": "20",
    "Content-Type": "application/json",
    "Host": "localhost",
    "User-Agent": "curl/7.79.1",
    "X-Amzn-Trace-Id": "Root=1-6239ae8e-633a33fb0d5fe44e354c9149",
    "X-Forwarded-Host": "localhost"
  },
  "json": {
    "hello": "world"
  },
  "method": "POST",
  "origin": "172.21.0.1, 176.153.7.175",
  "url": "http://localhost/anything?foo=bar&baz"
}

结论

在这篇文章中,我已经解释了网络服务器的演变。一开始,它们的唯一责任是提供静态内容。然后,它们增加了路由和负载平衡能力,成为反向代理。在这一点上,增加额外的交叉功能是一个很容易的步骤。

在API时代,网络服务器已经达到了另一个阶段。API网关。Apache APISIX就是这样一个网关。它不仅具有友好的Apache v2许可证,而且是Apache基金会组合的一部分。

使用Apache APISIX很容易。使用Docker,加上APISIX和etcd镜像,就可以开始了。

本文章的完整源代码可以在Github上找到。

要进一步了解。

关注@nicolas_frankel