Varnish4.1.2配合FastDFS构建内存缓存

时间:2022-02-27 18:17:37

Varnish是什么

Varnish是一款高性能的开源HTTP加速器,挪威最大的在线报纸 Verdens Gang (http://www.vg.no) 使用3台Varnish代替了原来的12台squid,性能居然比以前更好。

Varnish 的作者Poul-Henning Kamp是FreeBSD的内核开发者之一,他认为现在的计算机比起1975年已经复杂许多。在1975年时,储存媒介只有两种:内存与硬盘。但现在计算 机系统的内存除了主存外,还包括了cpu内的L1、L2,甚至有L3快取。硬盘上也有自己的快取装置,因此squid cache自行处理物件替换的架构不可能得知这些情况而做到最佳化,但操作系统可以得知这些情况,所以这部份的工作应该交给操作系统处理,这就是 Varnish cache设计架构。
【以上摘自http://www.oschina.net/p/varnish

开始

废话说完了,接下来就是怎么使用它了。本文描述的内容基于Varnish 4.1.2版本。

安装Varnish:

(1)源码安装
下面这个是Varnish的官网:https://www.varnish-cache.org/
github的地址:https://github.com/varnishcache/varnish-cache
下载下来源码包,进行编译安装。
(2)命令安装
在官网上可以看到说明:
https://www.varnish-cache.org/releases/install_ubuntu.html#install-ubuntu

apt-get install apt-transport-https
curl https://repo.varnish-cache.org/GPG-key.txt | apt-key add -
echo "deb https://repo.varnish-cache.org/ubuntu/ trusty varnish-4.1" \
>> /etc/apt/sources.list.d/varnish-cache.list
apt-get update
apt-get install varnish

可以看到,通过命令行直接安装比较方便。

配置Varnish

这一点还是值得注意的,我在配置的时候,发现网上大部分文档都是之前的版本,但是在4.x版本之后,配置方式发生了变化,也折腾了些时间,所以,希望能帮助你跳过坑。

Varnish运行参数配置

默认的端口是监听6081,你怎么知道?
看这个文件:

vi /etc/default/varnish
tfxiaozi@server:~$ cat /etc/default/varnish
# Configuration file for Varnish Cache.
#
# /etc/init.d/varnish expects the variables $DAEMON_OPTS, $NFILES and $MEMLOCK
# to be set from this shell script fragment.
#
# Note: If systemd is installed, this file is obsolete and ignored. You will
# need to copy /lib/systemd/system/varnish.service to /etc/systemd/system/ and
# edit that file.

# Should we start varnishd at boot? Set to "no" to disable.
START=yes

# Maximum number of open files (for ulimit -n)
NFILES=131072

# Maximum locked memory size (for ulimit -l)
# Used for locking the shared memory log in memory. If you increase log size,
# you need to increase this number as well
MEMLOCK=82000
DAEMON_OPTS="-a :6081 \
-T localhost:6082 \
-f /etc/varnish/default.vcl \
-S /etc/varnish/secret \
-s malloc,24G"

tfxiaozi@server:~$

没错啦,就是这里,Varnish运行时占用了6081端口,6082用作管理。

-a 如果希望使用80端口直接访问,修改成80即可 
-s 使用的内存大小
-S 认证的密钥文件 varnishadm -T localhost:6082 -S secret
-f 指定了Varnish运行起来时需要加载的配置文件,用来管理后端服务器

Varnish 密钥文件

在上面的配置中可以看到,密钥文件在/etc/varnish下。

访问http://varnish_VPS_public_IP:6081,前面是Varnish安装的机器ip,此时会出现503访问错误,原因是没有配置后端要cache的服务器。

配置后端web服务器

这里以后端FastDFS存储集群机器为例进行配置,目的是让Varnish对FastDFS的Storage节点进行缓存,以降低直接访问Storage节点造成的压力。
Storage1: 10.10.10.81;
Storage2: 10.10.10.82.
给出详细的配置文件:

root@server:/etc/varnish# cat default.vcl 
#
# This is an example VCL file for Varnish.
#
# It does not do anything by default, delegating control to the
# builtin VCL. The builtin VCL is called when there is no explicit
# return statement.
#
# See the VCL chapters in the Users Guide at https://www.varnish-cache.org/docs/
# and https://www.varnish-cache.org/trac/wiki/VCLExamples for more examples.

# Marker to tell the VCL compiler that this VCL has been adapted to the
# new 4.0 format.
vcl 4.0;

import std;
import directors;
# Default backend definition. Set this to point to your content server.
#backend default {
# .host = "127.0.0.1";
# .port = "8080";
#}

#probe healthcheck {
# .url = "/";
# .interval = 6s;
# .timeout = 1s;
# .window = 5;
# .threshold = 3;
#}

backend fdfs_g1_s1 {
.host = "10.10.10.81";
.port = "10000";
# .probe = healthcheck; #健康状态检测
}

backend fdfs_g1_s2 {
.host = "10.10.10.82";
.port = "10000";
# .probe = healthcheck; #健康状态检测
}

acl purgers {
"localhost";
"127.0.0.1";
}

sub vcl_init {
new vdir = directors.round_robin();
vdir.add_backend(fdfs_g1_s1);
vdir.add_backend(fdfs_g1_s2);
return (ok);
}


sub vcl_recv {
# Happens before we check if we have this in cache already.
#
# Typically you clean up the request here, removing cookies you don't need,
# rewriting the request, etc.
set req.backend_hint = vdir.backend();
if (req.http.x-forwarded-for) {
set req.http.X-Forwarded-For = req.http.X-Forwarded-For + ", " + client.ip;
} else {
set req.http.X-Forwarded-For = client.ip;
}

if (req.method == "PURGE") { # PURGE请求的处理
if (!client.ip ~ purgers) {
return(synth(405,"Method not allowed"));
}
#清理缓存
return (purge);
}
# 禁止缓存的文件
if (req.url ~ "\.(php|jsp|do)($|\?|#)") {
return (pass);
}

if (req.method == "PRI") {
#/* We do not support SPDY or HTTP/2.0 */
return (synth(405));
}
if (req.method != "GET" &&
req.method != "HEAD" &&
req.method != "PUT" &&
req.method != "POST" &&
req.method != "TRACE" &&
req.method != "OPTIONS" &&
req.method != "DELETE") {
#/* Non-RFC2616 or CONNECT which is weird. */
return (pipe);
}

if (req.method != "GET" && req.method != "HEAD") {
#/* We only deal with GET and HEAD by default */
return (pass);
}
if (req.http.Authorization || req.http.Cookie) {
#/* Not cacheable by default */
return (pass);
}
return (hash);
}

sub vcl_backend_response {
# Happens after we have read the response headers from the backend.
#
# Here you clean the response headers, removing silly Set-Cookie headers
# and other mistakes your backend does.
if (bereq.url ~ "^[^?]*\.(7z|avi|bmp|bz2|css|csv|doc|docx|eot|flac|flv|gif|gz|ico|jpeg|jpg|js|less|mka|mkv|mov|mp3|mp4|mpeg|mpg|odt|otf|ogg|ogm|opus|pdf|png|ppt|pptx|rar|rtf|svg|svgz|swf|tar|tbz|tgz|ttf|txt|txz|wav|webm|webp|woff|woff2|xls|xlsx|xml|xz|zip)(\?.*)?$") {
unset beresp.http.set-cookie;
}
# Large static files are delivered directly to the end-user without
# waiting for Varnish to fully read the file first.
# Varnish 4 fully supports Streaming, so use streaming here to avoid locking.
if (bereq.url ~ "^[^?]*\.(7z|avi|bz2|flac|flv|gz|mka|mkv|mov|mp3|mp4|mpeg|mpg|ogg|ogm|opus|rar|tar|tgz|tbz|txz|wav|webm|xz|zip)(\?.*)?$") {
unset beresp.http.set-cookie;
set beresp.do_stream = true; # Check memory usage it'll grow in fetch_chunksize blocks (128k by default) if the backend doesn't send a Content-Length header, so only enable it for big objects
set beresp.do_gzip = false; # Don't try to compress it for storage
}
# Set 2min cache if unset for static files
if (beresp.ttl <= 0s || beresp.http.Set-Cookie || beresp.http.Vary == "*") {
set beresp.ttl = 120s; # Important, you shouldn't rely on this, SET YOUR HEADERS in the backend
set beresp.uncacheable = true;
return (deliver);
}
# Allow stale content, in case the backend goes down.
# make Varnish keep all objects for 6 hours beyond their TTL
set beresp.grace = 6h;

return (deliver);
}


sub vcl_backend_fetch {
return (fetch);
}

sub vcl_pipe {
# By default Connection: close is set on all piped requests, to stop
# connection reuse from sending future requests directly to the
# (potentially) wrong backend. If you do want this to happen, you can undo
# it here.
# unset bereq.http.connection;
return (pipe);
}

sub vcl_pass {
return (fetch);
}

sub vcl_hash {
hash_data(req.url);
if (req.http.host) {
hash_data(req.http.host);
} else {
hash_data(server.ip);
}
return (lookup);
}

sub vcl_purge {
return (synth(200, "Purged"));
}

sub vcl_hit {
if (obj.ttl >= 0s) {
#// A pure unadultered hit, deliver it
return (deliver);
}
if (obj.ttl + obj.grace > 0s) {
#// Object is in grace, deliver it
#// Automatically triggers a background fetch
return (deliver);
}
#// fetch & deliver once we get the result
return (miss);
}

sub vcl_miss {
return (fetch);
}

sub vcl_deliver {
set resp.http.x-hits = obj.hits;
if (obj.hits > 0) {
set resp.http.X-Cache = "Hit varnish cache";
}else {
set resp.http.X-Cache = "Miss varnish cache";
}
return (deliver);
}

sub vcl_synth {
set resp.http.Content-Type = "text/html; charset=utf-8";
set resp.http.Retry-After = "5";
synthetic( {"<!DOCTYPE html>
<html>
<head>
<title>"
} + resp.status + " " + resp.reason + {"</title>
</head>
<body>
<h1>Error "
} + resp.status + " " + resp.reason + {"</h1>
<p>"
} + resp.reason + {"</p>
<h3>Guru Meditation:</h3>
<p>XID: "
} + req.xid + {"</p>
<hr>
<p>Varnish cache server</p>
</body>
</html>
"
} );
return (deliver);
}


sub vcl_backend_error {
set beresp.http.Content-Type = "text/html; charset=utf-8";
set beresp.http.Retry-After = "5";
synthetic( {"<!DOCTYPE html>
<html>
<head>
<title>"
} + beresp.status + " " + beresp.reason + {"</title>
</head>
<body>
<h1>Error "
} + beresp.status + " " + beresp.reason + {"</h1>
<p>"
} + beresp.reason + {"</p>
<h3>Guru Meditation:</h3>
<p>XID: "
} + bereq.xid + {"</p>
<hr>
<p>Varnish cache server</p>
</body>
</html>
"
} );
return (deliver);
}

sub vcl_fini {
return (ok);
}

默认情况下,如果只有一台机器做web server,使用backend default进行配置即可。如果是多台机器提供相同的内容服务,那么可以将多个web server进行组管理,通过robin轮询或者random提供服务,具体要注意的细节:
①自定义后台server

backend fdfs_g1_s1 {
.host = "10.10.10.81";
.port = "10000";
# .probe = healthcheck; #健康状态检测
}

backend fdfs_g1_s2 {
.host = "10.10.10.82";
.port = "10000";
# .probe = healthcheck; #健康状态检测
}

②初始化

sub vcl_init {
new vdir = directors.round_robin();
vdir.add_backend(fdfs_g1_s1);
vdir.add_backend(fdfs_g1_s2);

return (ok);
}

初始化操作放到init中即可。
③然后,需要在vcl_recv中进行设置当前使用的backend,

set req.backend_hint = vdir.backend();

做完这三步,varnish就配置好了,当然还可以根据需要配置节点健康检查。

启动Varnish

执行如下命令:

service varnish start

可以通过netstat -unltp | grep varnish 查看当前端口是否被varnish占用:

root@server:/etc/varnish# netstat -unltp | grep varnish
tcp 0 0 0.0.0.0:6081 0.0.0.0:* LISTEN 26565/varnishd
tcp 0 0 127.0.0.1:6082 0.0.0.0:* LISTEN 26565/varnishd
tcp6 0 0 :::6081 :::* LISTEN 26565/varnishd
tcp6 0 0 ::1:6082 :::* LISTEN 26565/varnishd

测试

既然配置好了,那么就改测试一下,看看效果怎么样了。
Storage1: 10.10.10.81;
Storage2: 10.10.10.82;
我这里varnish装在192.168.165.21机器上,配置了双网卡。
Varnish4.1.2配合FastDFS构建内存缓存
可以看到,当访问6081端口时,出现了nginx的界面,这是因为在FastDFS配置了Storage使用Nginx提供http服务,也就是说当前配置到后端服务器是OK了。

下面来测试一下缓存到底有没有起作用?
第一次:

Request URL:http://192.168.165.21:6081/group1/M00/00/00/CgoK0ldybhOAYFAfAAAOelbujmQ479.png
Request Method:GET
Status Code:200 OK
Remote Address:192.168.165.21:6081
Response Headers
view source
Accept-Ranges:bytes
Age:0
Connection:keep-alive
Content-Length:3706
Content-Type:image/png
Date:Tue, 28 Jun 2016 12:31:56 GMT
Last-Modified:Tue, 28 Jun 2016 12:31:15 GMT
Server:nginx/1.8.1
Via:1.1 varnish-v4
X-Cache:Miss varnish cache
x-hits:0
X-Varnish:98311
Request Headers
view source
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip, deflate, sdch
Accept-Language:zh-CN,zh;q=0.8
Connection:keep-alive
DNT:1
Host:192.168.165.21:6081
Upgrade-Insecure-Requests:1
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.109 Safari/537.36

可以看到,第一次没有再缓存中命中:X-Cache:Miss varnish cache

第二次:

Request URL:http://192.168.165.21:6081/group1/M00/00/00/CgoK0ldybhOAYFAfAAAOelbujmQ479.png
Request Method:GET
Status Code:200 OK
Remote Address:192.168.165.21:6081
Response Headers
view source
Accept-Ranges:bytes
Age:16
Connection:keep-alive
Content-Length:3706
Content-Type:image/png
Date:Tue, 28 Jun 2016 12:31:56 GMT
Last-Modified:Tue, 28 Jun 2016 12:31:15 GMT
Server:nginx/1.8.1
Via:1.1 varnish-v4
X-Cache:Hit varnish cache
x-hits:1
X-Varnish:13 98312
Request Headers
view source
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip, deflate, sdch
Accept-Language:zh-CN,zh;q=0.8
Cache-Control:max-age=0
Connection:keep-alive
DNT:1
Host:192.168.165.21:6081
If-Modified-Since:Tue, 28 Jun 2016 12:31:15 GMT
Upgrade-Insecure-Requests:1
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.109 Safari/537.36

可以看到,第二次命中:X-Cache:Hit varnish cache。

清理缓存

配置文件指定了PURGE和IP 就可以用curl 清理缓存

root@server:/etc/varnish# curl -X PURGE http://127.0.0.1:6081/group1/M00/00/00/CgoK0ldybhOAYFAfAAAOelbujmQ479.png     
<!DOCTYPE html>
<html>
<head>
<title>200 Purged</title>
</head>
<body>
<h1>Error 200 Purged</h1>
<p>Purged</p>
<h3>Guru Meditation:</h3>
<p>XID: 98320</p>
<hr>
<p>Varnish cache server</p>
</body>
</html>
root@server:/etc/varnish#

一些命令

①varnishstat
可以查看缓存命中率
缓存命中率的高低,直接反映Varnish的运行状态,以下通过varnishstat命令查看状态信息:
Varnish4.1.2配合FastDFS构建内存缓存
Hitrate n 第一个数字范围0-10,第二个数字范围0-100,第三个数字范围0-1000。分别表示过去N秒内的
avg(n) 里的内容是命中率,需要乘以100转换成百分比。
②varnishlog
可以查看实时日志。

附录

一篇英文文档
https://www.digitalocean.com/community/tutorials/how-to-configure-varnish-cache-4-0-with-ssl-termination-on-ubuntu-14-04
github上一篇关于4.0的详细配置模板:
https://github.com/mattiasgeniar/varnish-4.0-configuration-templates/blob/master/default.vcl
一篇关于之前低版本的配置,里面讲了关于Varnish性能优化和varnishadm 命令。
http://xiaodong88.blog.51cto.com/1492564/1304988