这是由Denis Brækhus 和 Espen Braastad 撰写的客座文章, 他们是来自Varnish Software 的 Varnish API Engine 的开发者。Varnish长期用于认证后端,所以让我们来看看他们在做什么。
Varnish Software刚刚放出Varnish API Engine的发布版,它是一个高性能的 HTTP API 网关,用于处理认证、授权和所有基于Varnish Cache之上的调节。Varnish API Engine可以用一个统一访问控制层轻易地扩展你目前的API集。这个统一访问控制层内置了高容量读取操作缓存能力,而且它提供了实时度量。
Varnish API Engine使用了众所周知的组件如memcached、SQLite和最重要的Varnish Cache。管理 API是由Python写成的。该产品的核心部分在Varnish的基础上使用VCL (Varnish Configuration Language)编写成一个应用并使用VMODs (Varnish Modules)提供扩展能力。
我们希望以这篇文章作为一个机会来向您展示怎样在VMODs的协助下使用VCL创建一个您自己的灵活且高性能的应用。
VMODs (Varnish 模块)
VCL是用于配置Varnish Cache的语言。当varnishd加载VCL配置文件时,它将会把这个文件转换成C代码,将之编译并动态加载。因此可以通过在VCL配置文件中直接嵌入C代码来使VCL具有扩展功能,但是从Varnish Cache 3开始,已经变成使用Varnish Modules,或简称VMODs。
在Varnish Cache的一个堆栈中,典型的请求流程入下:
客户端发出的HTTP请求被Varnish Cache接收并处理。Varnish Cache将会检查请求的内容是否在缓存中,最后它可能从后端读取内容。这工作的很好,但我们能做更多。
VCL语言是为性能设计的,因此它本身并不提供循环或外部调用。 VMODs,换句话说,是为了打破这些限制的。这对灵活性来说非常棒,但将确保性能和避免延迟的责任放到了VMOD代码和行为上了。
API Engine用于说明用VCL和自定义的VMOD的组合来开发新应用是多么强大。在Varnish API Engine中,请求流程是:
每个请求匹配一个使用SQLite VMOD的规则集合和使用memcached VMOD的Memcached计数器组。如果任何一个不匹配,请求都将会被拒绝,例如:认证失败或超过了请求限制。
应用示例
下面的例子是 Varnish API Engine 中一些概念的非常简单版本。我们将创建一个用 VCL 写的小应用,它将在一个包含限流规则的数据库中搜索请求 URL,并在每一个 IP 的基础上执行。
由于开发应用程序时的测试和可维护性是至关重要的,我们将用 Varnish 的集成测试工具:varnishtest。Varnishtest 是一个测试 Varnish 缓存所用方面的强大工具。Varnishtest 的简单接口意味着开发者和操作工程师利用它来测试他们的 VCL/VMOD 配置。
Varnishtest 读取一个描述一组模拟服务器、客户端和 varnish 实例的文件。客户端执行通过varnish 到达服务器的请求。Expectations 可以被设置为内容、标题、HTTP 响应代码,或者更多。使用 varnishtest,我们可以快速测试我们的示例应用,并验证我们的请求对每一个定义的expectations是通过还是阻塞。
首先,我们需要一个带着我们限流规则的数据库。使用 sqlite3 命令,我们在 /tmp/rules.db3创建这个数据库并增加两三个规则。
$ sqlite3 /tmp/rules.db3 "CREATE TABLE t (rule text, path text);"
$ sqlite3 /tmp/rules.db3 "INSERT INTO t (rule, path) VALUES ('3r5', '/search');"
$ sqlite3 /tmp/rules.db3 "INSERT INTO t (rule, path) VALUES ('15r3600', '/login');"
这些规则将允许每秒3个请求到 /secarch 和每小时15个请求到 /login。这个想法是在每个 IP 基础上执行这些规则。
为了简单起见,我们将在一个文件中编写测试和 VCL 配置,throttle.vtc。然而,在测试文件中使用包含语句包含单独的 VCL 配置,分离 VCL 配置和不同的测试也是可行的。
这个文件中的第一行是用来设置这个测试的标题或名字。
varnishtest "Simple throttling with SQLite and Memcached"
我们的测试环境由一个调用 s1 的后端构成。我们将首先 expect 一个请求到一个在数据库中没有规则的 URL。
server s1 {
rxreq
expect req.url == "/"
txresp
根据接下来的 expectations,到达后我们再 expect 4个请求到/search。注意,查询参数略有不同,来制作所有这些独特的请求。
rxreq
expect req.url == "/search?id=123&type=1"
expect req.http.path == "/search"
expect req.http.rule == "3r5"
expect req.http.requests == "3"
expect req.http.period == "5"
expect req.http.counter == "1"
txresp
rxreq
expect req.url == "/search?id=123&type=2"
expect req.http.path == "/search"
expect req.http.rule == "3r5"
expect req.http.requests == "3"
expect req.http.period == "5"
expect req.http.counter == "2"
txresp
rxreq
expect req.url == "/search?id=123&type=3"
expect req.http.path == "/search"
expect req.http.rule == "3r5"
expect req.http.requests == "3"
expect req.http.period == "5"
expect req.http.counter == "3"
txresp
rxreq
expect req.url == "/search?id=123&type=4"
expect req.http.path == "/search"
expect req.http.rule == "3r5"
expect req.http.requests == "3"
expect req.http.period == "5"
expect req.http.counter == "1"
txresp
} -start
现在是时候写一个VCL的迷你程序了。我们的测试环境由一个varnish的实例v1组成。首先,加入vaernish版本和VMOD imports。
varnish v1 -vcl+backend {
vcl 4.0;
import std;
import sqlite3;
import memcached;