1. 使用Varnish缓存静态内容
1.1 描述Varnish
流量大的Web服务器通常需要卸载部分工作负载以维持其命中率并为客户提供可接受的响应时间。
Varnish缓存是一个网络加速器,你部署在这样的网络服务器前。而不是直接访问web服务器,web客户端联系Varnish。Varnish代表这些客户端从后端web服务器检索并返回所请求的对象。Varnish还缓存这些对象,这样它就可以为相同对象的请求提供服务,而不必联系web服务器。这样,web服务器就有更多可用的系统资源来管理它的工作负载。
下图说明了客户端第一次请求对象时Varnish如何从后端Web服务器检索对象。该操作是缓存未命中,因为对象最初不在缓存中。
1. Web 客户端请求对象。对于客户端,Varnish 的行为方式同web 服务器
2. Varnish 确定对象是否已在其缓存中
3. 在本例中,对象不在缓存中。Varnish 从后端 web 服务器请求对象
4. Web 服务器将对象发到 Varnish
5. Varnish 将对象存储在其缓存中
6. Varnish 给客户端的回复中包含对象
下图显示了当一个对象在缓存中时,Varnish在不接触后端web服务器的情况下为该对象提供服务。这种行为称为缓存命中。
1. Web 客户端从 Varnish 请求对象
2. Varnish 确定对象是否已在缓存中且未过期
3. 对象位于缓存中,Varnish 将其发回到客户端,而无需联系后端 web 服务器
注意,web客户端不再直接访问web服务器,而是查询Varnish。通常,您需要配置您的DNS服务器,以便url的主机部分指向Varnish服务器,
1.1.1 解释缓存行为
为了获得最大的性能,Varnish将对象缓存在内存中。因此,Varnish服务的重新启动将清除缓存。
#注意:Varnish提供了一个持久性存储插件,将对象存储在磁盘上,但是Varnish开发人员已经不建议使用该插件。
Varnish 默认会缓存⼀切内容: HTML、CSS 和 JavaScript 文件;镜像和动态内容(如 PHP 程序)。但也有一些例外情况:
- Varnish从不缓存设置HTTP cookie的响应。cookie通常存储特定于客户端的信息,比如会话id, Varnish不能为多个客户端提供这些响应。
- Varnish不缓存HTTP PUT或POST请求。
- Varnish在响应中识别Cache-Control HTTP报头。运行在后端web服务器上的web应用程序可以设置这个头来指示Varnish缓存应答多长时间(使用max-age值),或者不缓存它(使用no-cache或no-store值)。下面的示例使用curl命令和–head(或-I)选项来显示来自web应用程序的应答头:
[user@host ~]$ curl -I http://www.example.com/auth.php
HTTP/1.1 200 OK
Date: Fri, 17 Apr 2020 13:04:02 GMT
Server: Apache/2.4.37 (Red Hat Enterprise Linux)
X-Powered-By: PHP/7.2.11
Cache-Control: no-store
Set-Cookie: SESSIONID=8e8c5b64-f79b-4e15-b1ff-02c2c79b927b; expires=Sun, 17-
May-2020 13:03:23 GMT; Max-
Age=2592000; path=/
Content-Type: text/html; charset=UTF-8
可以使用Varnish configuration language (VCL)调优和调整Varnish的默认行为以满足需求。通过在VCL中开发,可以完全控制Varnish cachino机制。使用VCL配置缓存行为一节提供了关于VCL的更多详细信息。
1.1.2 解释TTL和清除机制
Varnish将对象保存在其缓存中一个特定的持续时间,称为生存时间(TTL)。当Varnish接收到对缓存中的对象的请求时,它首先确定对象的TTL值。如果对象已经过期,Varnish将丢弃它的副本,并从后端web服务器获取一个新版本。这种机制可以防止Varnish无限期地从其缓存中提供陈旧的内容。
缓存中的每个对象都有一个TTL值。当一个来自后端web服务器的回复包含一个特定TTL的Cache-control报头时,Varnish会为对象使用这个TTL。否则,Varnish将对象TTL设置为默认值2分钟。
可以通过Varnish配置更改默认TTL值。主要提供静态内容的Web服务器,如不经常更改的静态HTML页面和图像,可以受益于较高的TTL。
一些web应用程序和内容管理系统(CMS),如WordPress或MediaWiki,可以直接指示Varnish从其缓存中清除对象。例如,当用户修改Wiki页面时,MediaWiki向Varnish发送该页面的清除请求。对于这些应用程序,将TTL设置为一个非常高的值,例如一周,然后让应用程序控制Varnish缓存。
1.1.3 向Web应用程序提供客户端IP地址
一些web应用程序使用传入请求的源IP地址来识别它们的客户端。然而,如果Varnish位于web服务器前面,应用程序将看到来自Varnish服务器的请求,而不是来自单个客户端。
为了解决这个问题,Varnish自动将X-Forwarded-For HTTP头添加到它转发到后端web服务器的所有请求中。该头包含来自原始请求的客户端系统的IP地址:
...output omitted...
X-Forwarded-For: 172.25.250.9
...output omitted...
大多数web应用程序首先使用该头来识别客户端系统。
1.2 部署Varnish
安装 varnish 软件包
[root@host ~]# yum install varnish
启用并启动varnish systemd服务。
[root@host ~]# systemctl enable --now varnish
1.3 配置Varnish
Varnish将其配置划分为两个位置:
- varnishd守护进程命令行参数
- /etc/varnish/default.vcl实现方式文件
1.3.1 设置Varnish Daemon命令行参数
varnishd(1)手册页列出了您定义为varnishd守护进程的命令行选项的所有配置参数。这些参数控制进程的一般行为,如监听的网络端口、守护进程的Linux用户帐户或存储后端参数。
因为varnish systemd服务启动了varnishd守护进程,所以需要修改该服务来更改或添加命令行选项。
使用systemctl cat varnish命令显示当前服务详细信息。
[root@host ~]# systemctl cat varnish
# /usr/lib/systemd/system/varnish.service
[Unit]
Description=Varnish Cache, a high-performance HTTP accelerator
After=network-online.target
[Service]
...output omitted...
ExecStart=/usr/sbin/varnishd -a :6081 -f /etc/varnish/default.vcl -s malloc,256m
...output omitted...
在前面的输出中,systemd定义了使用Execstart参数运行的命令。
-a [IP]: PORT选项指定Varnish监听传入客户端请求的TCP端口。选项的IP部分是要使用的网络接口的IP地址。如果没有设置,varnishd将监听所有服务器接口。可以为Varnish重复-a选项,以便在多个端口上侦听。
-s选项指定对象缓存的存储后端。malloc参数指示Varnish将对象缓存到内存中。上面输出的size(256)表示Varnish可以用于缓存的最大内存大小。当内存满的时候。Varnish可以清除旧对象。在一个专用于Varnish服务器的系统上,可能希望将缓存大小设置为系统物理内存的很大一部分。
1.3.2 配置网口
默认情况下,Varnish监听端口6081。因为web客户端通过Varnish访问你的web应用程序,通常配置Varnish监听端口80,默认的HTTP端口。
为此,修改varnish systemd服务如下:
- 为varnish服务创建systemd drop-in目录。Drop-in目录用于添加或覆盖个别设置,而不修改/usr/lib/systemd/中的原始单元配置。永远不要修改/usr/lib/systemd/中的文件,因为包升级将覆盖您的自定义配置。相反,在/etc/systemd/ system/中创建一个子目录,使用原来的单元名,并添加.d。该目录下的插入配置文件必须以.conf结尾。
[root@host ~]# mkdir /etc/systemd/system/varnish.service.d/
- 要覆盖 [Service] 部分中的Execstart参数,请为该服务创建systemd配置文件。文件的名称必须以.conf扩展名结尾。设置varnishd -a选项为 :80
[root@host ~]# cat /etc/systemd/system/varnish.service.d/httpport.conf
[Service]
ExecStart=
ExecStart=/usr/sbin/varnishd -a :80 -f /etc/varnish/default.vcl -s malloc,256m
第一个没有值的Execstart参数清除默认配置定义的命令。否则,systemd会依次执行所有Execstart命令。
- 强制systemd重新加载其配置。
[root@host ~]# systemctl daemon-reload
- 重新启动varnish服务。
[root@host ~]# systemctl restart varnish
- 打开防火墙端口。
[root@host ~]# firewall-cmd --permanent --add-service=http
[root@host ~]# firewall-cmd --reload
SELinux允许Varnish绑定到varnishd_port_t、http_cache_port_t和http_port_t端口类型。可以使用semanage port -l命令列出相关联的端口号。
[root@host ~]# semanage port -l | grep -w -e varnishd_port_t -e http_cache_port_t -e http_port_t | grep tcp
http_cache_port_t tcp 8080, 8118, 8123, 10001-10010
http_port_t tcp 80, 81, 443, 488, 8008, 8009, 8443, 9000
varnishd_port_t tcp 6081-6082
为了让Varnish监听任何其他端口,将varnishd_connect_any SELinux Boolean设置为on。
[root@host ~]# setsebool -P varnishd_connect_any on
1.3.3 使用VCL配置缓存行为
/etc/varnish/default.vcl配置文件控制对象缓存行为。在Varnish configuration language (VCL)中编写该配置文件。当Varnish启动时,它将该文件转换为二进制格式,然后加载并执行产生的代码。
1.3.4 介绍内置子例程
Varnish通过一系列内置子例程处理传入请求和后端响应。在/etc/varnish/default.vcl文件,可以重新定义这些子例程来修改默认行为。
例如,vcl_recv子例程处理来自web客户端的请求。在该子例程中,您通过req对象访问传入的请求细节。以/etc/varnish/default.vcl文件,指示Varnish跳过文件扩展名为.mp3或.oqg的文件的缓存
sub vcl_recv {
if (req.url ~ ".(mp3|ogg)$") { #①
return (pass); #②
}
}
#①req对象的url属性包含请求url,例如/index.html或/sound.mp3操作符根据正则表达式测试url属性。
#②如果测试成功(即,URL 以 .mp3 或 .ogg 结尾),则子例程返回 pass 关键字。关键字指示 Varnish 跳过缓存,将请求直接传递到后端 web 服务器
vcl(7) man page 列出了所有可用的 req 对象属性和所有可用的运算符
vcl_backend_response子例程处理来自后端web服务的回复。Varnish通过beresp对象提供回复详细信息。当后端web服务尝试将对象TTL强制设为超过⼀天时,下例可将该时间缩减为两小时
sub vcl_backend_response {
if (beresp.ttl > 1d) { #①
set beresp.ttl = 2h; #②
}
}
#①beresp对象的ttl属性包含对象TTL。测试可确定该TTL是否超过⼀天。在进入该vcl_backend_response子例程时,Varnish将beresp.ttl属性设置为两分钟的默认值。但如果后端web服务器的回复包括Cache-Control HTTP标头,则Varnish将从该标头设置ttl属性
#②子例程将TTL减少到仅为两个小时
Varnish定义并使用其他内置子例程。更多细节请参考Varnish文档。
1.3.5 声明访问控制列表并配置清除请求
/etc/varnish/default.vcl文件还可以包含访问控制列表(ACL)声明。这些声明定义了可以在子例程中使用的主机或IP地址列表。下面的示例定义了purge_allowed ACL,然后在vcl_recv子例程中使用该ACL。
acl purge_allowed { #①
"localhost";
"172.25.250.12";
"192.168.0.12";
}
sub vcl_recv {
if (req.method == "PURGE") { #②
if (!client.ip ~ purge_allowed) { #③
return(synth(405, "This address is not allowed to send PURGE requests."));
}
return (purge); #④
}
}
#①acl声明定义了三个主机列表
#②req对象的method属性包含请求HTTP方法,如GET、PUT或POST。该测试将验证传入的请求是否使用PURGE HTTP方法。
#③client对象提供客户端详细信息,如其IP地址。该测试将检查请求是否来自purge_allowed ACL中列出的客户端。该测试使用了求反运算符,!,因此如果客户端的IP地址不在列表中,则Varnish会将405 HTTP错误代码返回给客户端
#④子例程返回purge关键字。关键字指示Varnish从其缓存中清除对象。Varnish在req.url中从请求URL识别对象,并在req.http.host中识别请求的主机部分
前面的例子展示了如何配置Varnish来接受来自web应用程序的请求,从而从缓存中清除对象。您在ACL中提供的IP地址就是那些web应用程序的地址。
1.3.6 验证VCL语法
在重新启动varnish systemd服务之前,使用varnishd -C -f /etc/varnish/default.vcl命令测试您的配置。该命令编译VCL文件并显示生成的C代码。最重要的是,当检测到错误时,该命令返回一个非零值。
[root@host ~]# varnishd -C -f /etc/varnish/default.vcl
...output omitted...
[root@host ~]# echo $?
0
1.3.7 访问Varnish文档
varnish-docs包在/usr/share/doc/varnish-docs/html/目录下提供Varnish文档。该软件包不依赖于varnish软件包。您可以将其部署在您的工作站上,然后使用Web浏览器访问/usr/share/doc/varnish-docs/html/index.html文件。
1.4 故障排除和管理Varnish
为了获得最佳性能,varnishd守护进程不会写日志文件。取而代之,它将日志消息写入共享内存中的缓冲区中可选的varnishncsa服务将监控该缓冲区,并将日志消息写入到/var/log/varnish/varnishncsa.log日志文件
日志文件与来自Apache的access_log文件类似:
[root@host ~]# cat /var/log/varnish/varnishncsa.log
172.25.250.9 - - [27/Apr/2020:07:06:31 -0400] "GET http://www.example.com/index.html HTTP/1.1" 200 32 "-" "curl/7.61.1"
172.25.250.9 - - [27/Apr/2020:07:12:26 -0400] "GET http://www.example.com/favicon.ico HTTP/1.1" 404 209 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:68.0)
Gecko/20100101 Firefox/68.0"
172.25.250.9 - - [27/Apr/2020:07:12:27 -0400] "GET http://www.example.com/HTTP/1.1" 200 32 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101
Firefox/68.0"
启用并启动varnishncsa可选服务systemd,方法如下:
[root@host ~]# systemctl enable --now varnishncsa
1.4.1 从命令行管理Varnish
使用varnishadm命令行工具,您可以监视和重新配置Varnish,而不需要重新启动守护进程。使用该工具执行的修改不会在服务重新启动时持久,而是允许您临时修改活动配置
varnishadm命令接受子命令作为其第一个参数。如果不提供该子命令,varnishadm将启动交互式会话。下面的示例以非交互式和交互式的方式展示了status子命令的使用。status子命令显示varnishd守护进程的状态。
[root@host ~]# varnishadm status
Child in state running
[root@host ~]# varnishadm
200
-----------------------------
Varnish Cache CLI 1.0
-----------------------------
Linux,4.18.0-147.el8.x86_64,x86_64,-ju.nix,-smalloc,-sdefault,-hcritbit
varnish-6.0.2 revision 0458b54db26cfbea79af45ca5c4767c7c2925a91
Type 'help' for command list.
Type 'quit' to close CLI session.
varnish> status
200
Child in state running
varnish> quit
500
Closing CLI connection
[root@host ~]#
运行varnishadm帮助命令获取子命令列表。可以通过varnishadm帮助子命令或varnish-cli(7)手册页获得关于特定子命令的详细信息
下面的列表描述了其中的一些子命令。
- varnishadm ban '*expression*'
ban子命令从缓存中清除对象。当后端web服务器有新内容时,该子命令非常有用,并且您希望Varnish在不等待TTL的情况下提供新内容。下面的命令清除URL部分为/的所有对象/index.html。
[root@host ~]# varnishadm 'ban req.url == /index.html’
还可以使用正则表达式和~操作符来清除多个对象。下面的例子清除了所有的PNG图像。
[root@host ~]# varnishadm ban 'req.url ~ .*.png’
需要在正则表达式中使用另一个 字符来转义 字符
- varnishadm param.show *parameter*
param.show子命令显示Varnish参数的值。可以从varnishd(1)手册页获得所有这些参数的列表。下面的命令显示缺省TTL值。
[root@host ~]# varnishadm param.show default_ttl
default_ttl
Value is: 120.000 [seconds] (default)
Minimum is: 0.000
The TTL assigned to objects if neither the backend nor the VCL
code assigns one.
NB: This parameter is evaluated only when objects are created.
To change it for all objects, restart or ban everything.
- varnishadm param.set *parameter value*
param.set子命令更改Varnish参数的值。这种更改不会在服务重新启动时持久存在。如果您想让这个更改持久,请更新varnish systemd服务配置,向varnishd守护进程添加-p选项。下面的命令将缺省TTL设置为12小时(43200秒)。
[root@host ~]# varnishadm param.set default_ttl 43200
- varnishadm vcl.show boot
带有 boot 参数的 vcl.show 子命令将显示活动的 VCL
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net
这篇文章是实战性质的,也就是说原理部分较少,属于经验总结,rust对于模块的例子太少了。rust特性比较多(悲),本文的内容可能只是一部分,实现方式也不一定是这一种。 关于 rust 模块的相关内容,准确来说:怎么在源码中引用其他模块的内容。 关于 mod、 …