在万维网的先锋领域,内容是静态的。为了提供服务,一群开发人员创建了一个网络服务器,也就是现在的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提供了几个核心对象。
上游
虚拟主机抽象,根据配置规则在一组给定的服务节点上执行负载平衡
消费者
客户的身份
路由
路由通过定义规则来匹配客户的请求,然后根据匹配结果加载和执行相应的插件,并将请求转发给指定的上游。
服务
一个可重复使用的对象,它同时绑定了一组插件和一个上游。
对象存储在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"
| 1 | Apache APISIX图像 |
| 2 | 技巧是等待etcd完全初始化,而不仅仅是启动。depends_on 属性是不够的 |
| 3 | etcd图像 |
| 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上找到。