搞这个博客本身就是当日记写的,也没打算多少访问量多少收入,甚至连一个广告都木有,但是wordpress在配置较低的vps上真的比较慢,所以最近折腾了好久,下面写一点经验吧。
起初我用的是wp super cache,但是理论上来讲,因为是文件系统缓存,所以这玩意依然需要读写磁盘,而且预缓存我反复测试都无法生效,而回收策略也总是莫名其妙,在没有更新的情况下,有时候几分钟就要重建缓存,有时候几个小时都不会,极其不稳定,所以放弃了。
然后试了一下w3 total cache,第一次用的是disk缓存,效果比较差,因为和super cache一样的,理论上只是减少了读数据库的次数,但读写磁盘依旧;第二次用了memcached做后端存储,效果还可以,但依旧感觉有时候会慢,因为我觉得,道理上来讲,判断是否重建缓存仍然需要跟数据库做对比,所以这两个方案都还差点。
昨天开始换成Super Static Cache,这下明显好得多,首页、单页和文章都会生成物理的html文件,速度飞快,不过感觉好像依然用了php进行过期判断,有时候稍微卡一下,而且一个让我很难受的是,这玩意不会生成目录的页面。
今天测试在Super Static Cache的基础上,在前端增加了varnish,因为这玩意是全内存缓冲,所以彻底解决了这些问题,而且可以将js、css、图片等所有静态文件都缓存起来,如果内存够用的话,可以完全避免读写磁盘了。我用自己的http调试工具反复测试多次,都能够正常缓存,访问速度飞快哦。
贴出我的varnish配置文件,然后我会简单解释一下重点:
# new 4.0 format.
vcl 4.0;
# Default backend definition. Set this to point to your content server.
backend default {
.host = "127.0.0.1";#后端web服务器的ip地址
.port = "8080";#后端web服务器的端口
.connect_timeout = 600s;
.first_byte_timeout = 600s;
.between_bytes_timeout = 600s;
.max_connections = 800;
}
# Only allow purging from specific IPs
#只允许本机进行清除缓存操作
acl purge {
"localhost";
"127.0.0.1";
}
sub vcl_recv {
set req.http.Host = regsub(req.http.Host, ":[0-9]+", "");
#?清除缓存操作的时候需要判断是否允许
if (req.method == "PURGE") {
# If not allowed then a error 405 is returned
if (!client.ip ~ purge) {
return(synth(405, "This IP is not allowed to send PURGE requests."));
}
return (purge);
}
#?http验证和post方法不缓存
if (req.http.Authorization || req.method == "POST") {
return (pass);
}
#?不缓存 RSS feed
if (req.url ~ "/feed") {
return (pass);
}
#?mu-开头的url不缓存
if (req.url ~ "/mu-.*") {
return (pass);
}
#?wordpress的管理页面不缓存
if (req.url ~ "/wp-(login|admin)") {
return (pass);
}
#?不缓存 WooCommerce?页面
### REMOVE IT IF YOU DO NOT USE WOOCOMMERCE ###
if (req.url ~ "/(cart|my-account|checkout|addons|/?add-to-cart=)") {
return (pass);
}
# 删除"has_js" 的cookie
set req.http.Cookie = regsuball(req.http.Cookie, "has_js=[^;]+(; )?", "");
# 删除所有Google Analytics 的cookies
set req.http.Cookie = regsuball(req.http.Cookie, "__utm.=[^;]+(; )?", "");
# 删除Quant Capital 的cookies,一般是插件加进来的
set req.http.Cookie = regsuball(req.http.Cookie, "__qc.=[^;]+(; )?", "");
# 删除wp-settings-1 的cookies
set req.http.Cookie = regsuball(req.http.Cookie, "wp-settings-1=[^;]+(; )?", "");
# 删除wp-settings-time-1 的cookies
set req.http.Cookie = regsuball(req.http.Cookie, "wp-settings-time-1=[^;]+(; )?", "");
# 删除wp test 的cookies
set req.http.Cookie = regsuball(req.http.Cookie, "wordpress_test_cookie=[^;]+(; )?", "");
#允许cookie
if (req.http.cookie ~ "^ *$") {
unset req.http.cookie;
}
#?缓存这些文件名
if (req.url ~ "\.(css|js|png|gif|jp(e)?g|swf|ico)") {
unset req.http.cookie;
}
#这里,因为我所有的文章和分类都在这个目录,所以这一行就够了,如果你有多个,可以多复制几段
if (req.url ~ "/archives") {
unset req.http.cookie;
}
#?对这些文件类型试着进行gzip压缩
if (req.http.Accept-Encoding) {
if (req.url ~ "\.(jpg|png|gif|gz|tgz|bz2|tbz|mp3|ogg)$") {
unset req.http.Accept-Encoding;
} elsif (req.http.Accept-Encoding ~ "gzip") {
set req.http.Accept-Encoding = "gzip";
} elsif (req.http.Accept-Encoding ~ "deflate") {
set req.http.Accept-Encoding = "deflate";
} else {
unset req.http.Accept-Encoding;
}
}
#?检查cookie是不是wp的特别项
if (req.http.Cookie ~ "wordpress_" || req.http.Cookie ~ "comment_") {
return (pass);
}
if (!req.http.cookie) {
unset req.http.cookie;
}
#?所有其他的请求都缓存
return (hash);
}
sub vcl_pipe {
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);
}
# If the client supports compression, keep that in a different cache
if (req.http.Accept-Encoding) {
hash_data(req.http.Accept-Encoding);
}
return (lookup);
}
# This function is used when a request is sent by our backend (Nginx server)
sub vcl_backend_response {
# Remove some headers we never want to see
unset beresp.http.Server;
unset beresp.http.X-Powered-By;
# For static content strip all backend cookies
if (bereq.url ~ "\.(css|js|png|gif|jp(e?)g)|swf|ico") {
unset beresp.http.cookie;
}
# Only allow cookies to be set if we're in admin area
if (beresp.http.Set-Cookie && bereq.url !~ "^/wp-(login|admin)") {
unset beresp.http.Set-Cookie;
}
# don't cache response to posted requests or those with basic auth
if ( bereq.method == "POST" || bereq.http.Authorization ) {
set beresp.uncacheable = true;
set beresp.ttl = 120s;
return (deliver);
}
# don't cache search results
if ( bereq.url ~ "\?s=" ){
set beresp.uncacheable = true;
set beresp.ttl = 120s;
return (deliver);
}
# only cache status ok
if ( beresp.status != 200 ) {
set beresp.uncacheable = true;
set beresp.ttl = 120s;
return (deliver);
}
# 默认为缓存24小时
set beresp.ttl = 24h;
# Define the default grace period to serve cached content
set beresp.grace = 30s;
return (deliver);
}
# The routine when we deliver the HTTP request to the user
# Last chance to modify headers that are sent to the client
sub vcl_deliver {
if (obj.hits > 0) {
set resp.http.X-Cache = "cached";
} else {
set resp.http.x-Cache = "uncached";
}
# Remove some headers: PHP version
unset resp.http.X-Powered-By;
# Remove some headers: Apache version & OS
unset resp.http.Server;
# Remove some heanders: Varnish
unset resp.http.Via;
unset resp.http.X-Varnish;
return (deliver);
}
sub vcl_init {
return (ok);
}
sub vcl_fini {
return (ok);
}
读者有可能修改的地方我都做了中文注释,没必要改的地方最好别动。
根据配置文件的语法来看,未证实的推测是配置文件很接近脚本语言,是串行的,当所有前面的语句处理完以后会进入set beresp.ttl = 24h;这一行生效的地方,我这里设置的是24小时,也就是一天,其实这里设置一年都可以,因为Varnish HTTP Purge这个插件可以在有更新的时候清除对应的缓存,没更新的时候自然缓存了最好。安装上并且启用就可以了。
然后Super Static Cache的设置是direct模式,高级----缓存模式里面设置缓存所有内容。
now,现在的架构就是Super Static Cache根据需要来生成静态页面,由Varnish HTTP Purge在必要的时候通知前端varnish重建对应缓存,然后所有需要缓存的页面、图片等资源都会在前端varnish的内存中,完全内存读取,理论上已经到加速极限了。
完工了,初次访问到的文件是正常速度,以后再访问就是缓存结果了,而且据我测试,这个配置文件会试着对图片和css这些进行gzip压缩,传输速度会更快。
2016.08.14补充:
近期进行了较大调整,下面是完整的新版配置文件,需要静态的页面全缓存,所有动态(搜索、管理、订阅、站点地图)不缓存,一些特定的文件不缓存。
# This is my VCL file for Varnish 4.0.2 & WordPress 4.0 # # ASSUME The builtin VCL is called afterwards. # # Specify VCL new 4.0 format. vcl 4.0; # Imports import std; # Default backend definition. Set this to point to your content server. backend default { .host = "你的服务器IP"; .port = "80"; #你的web服务器端口 } acl aclPurge { # For now, I'll only allow purges coming from localhost "127.0.0.1"; "localhost"; } acl aclBanned { # 禁止一些恶意的IP段,示例,非必需 "172.16.0.0"/16; } sub vcl_recv { ### DOC # https://www.varnish-cache.org/docs/4.0/users-guide/vcl-built-in-subs.html#vcl-recv # http://www.mediawiki.org/wiki/Manual:Varnish_caching#Configuring_Varnish_4.x # - The builtin VCL is always called afterwards. # - Happens before we check if we have this in cache already. # - Typically you clean up the request here, adjusting headers, managing cookies, rewriting the request, etc. ### vmod std: # - std.log(str): Logs a string to the shared memory log, using VSL tag VCL_Log # - varnishlog -i VCL_Log ### ### Allow purging ### # Tip: it only purges the current cache entry (to purge the whole cache: do service restart instead) if (req.method == "PURGE") { if (!client.ip ~ aclPurge) { return (synth(405, "This IP is not allowed to send PURGE requests.")); } return (purge); } ### ### Banning Logic (replacing the WordPress Plugin WP-Ban) ### # # 禁止一些恶意的IP段,示例,非必需 if (client.ip ~ aclBanned) { return (synth(403, "Forbidden")); } ### ### Do not Cache: special cases ### ### Do not Authorized requests. if (req.http.Authorization) { return(pass); // DO NOT CACHE } ### Pass any requests with the "If-None-Match" header directly. if (req.http.If-None-Match) { return(pass); // DO NOT CACHE } ### Do not cache AJAX requests. if (req.http.X-Requested-With == "XMLHttpRequest") { return(pass); // DO NOT CACHE } ### Only cache GET or HEAD requests. This makes sure the POST (and OPTIONS) requests are always passed. if (req.method != "GET" && req.method != "HEAD") { return (pass); // DO NOT CACHE } ### ### Request URL ### # 不缓存这些纯动态域名,如果你不需要,可以屏蔽,多个条件之间用||分割,代表“或”的意思 if (req.http.host == "w2.tingtao.org" || req.http.host == "w3.tingtao.org" ) { return(pass); // DO NOT CACHE } # apache的状态监控地址,如果你没有使用这个插件或者用的不是apache,可以屏蔽 if (req.url ~ "^/server-status") { # do not use the cache return(pass); // DO NOT CACHE } ### Static files: Do not cache PDF, XML, ... files (=static & huge and no use caching them - in all Vary: variations!) if (req.url ~ "\.(doc|mp3|pdf|tif|tiff|xml)(\?.*|)$") { return(pass); // DO NOT CACHE } # WordPress: disable caching for some parts of the backend (mostly admin stuff) # and WP search results. if ( req.url ~ "^/wp-(login|admin)" || req.url ~ "/wp-cron.php" || req.url ~ "preview=true" || req.url ~ "xmlrpc.php" || req.url ~ "\?s=" ) { # do not use the cache return(pass); // DO NOT CACHE } ### ### http header Cookie ### Remove some cookies (if found). ### # https://www.varnish-cache.org/docs/4.0/users-guide/increasing-your-hitrate.html#cookies # Unset the header for static files if (req.url ~ "\.(css|flv|gif|htm|html|ico|jpeg|jpg|js|mp3|mp4|pdf|png|swf|tif|tiff|xml)(\?.*|)$") { unset req.http.Cookie; } if (req.http.cookie) { #这些cookie段根据情况决定去留 # Google Analytics # set req.http.Cookie = regsuball( req.http.Cookie, "(^|;\s*)(__utm[a-z]+)=([^;]*)", ""); # set req.http.Cookie = regsuball( req.http.Cookie, "(^|;\s*)(_ga)=([^;]*)", ""); # Quant Capital # set req.http.Cookie = regsuball( req.http.Cookie, "(^|;\s*)(__qc[a-z]+)=([^;]*)", ""); # __gad __gads # set req.http.Cookie = regsuball( req.http.Cookie, "(^|;\s*)(__gad[a-z]+)=([^;]*)", ""); # Google Cookie consent (client javascript cookie) # set req.http.Cookie = regsuball( req.http.Cookie, "(^|;\s*)(displayCookieConsent)=([^;]*)", ""); # Other known Cookies: remove them (if found). # set req.http.Cookie = regsuball( req.http.Cookie, "(^|;\s*)(__CT_Data)=([^;]*)", ""); # set req.http.Cookie = regsuball( req.http.Cookie, "(^|;\s*)(WRIgnore|WRUID)=([^;]*)", ""); # Remove has_js and CloudFlare/Google Analytics __* cookies. # set req.http.Cookie = regsuball(req.http.Cookie, "(^|;\s*)(_[_a-z]+|has_js)=[^;]*", ""); # Remove a ";" prefix, if present. # set req.http.Cookie = regsub(req.http.Cookie, "^;\s*", ""); # PostAction: Remove (once and if found) a ";" prefix followed by 0..n whitespaces. # INFO \s* = 0..n whitespace characters set req.http.Cookie = regsub( req.http.Cookie, "^;\s*", "" ); # PostAction: Unset the header if it is empty or 0..n whitespaces. if ( req.http.cookie ~ "^\s*$" ) { unset req.http.Cookie; } # Check the cookies for wordpress-specific items if (req.http.Cookie ~ "wordpress_" || req.http.Cookie ~ "comment_") { return (pass); } #unset req.http.cookie; } ### ### Normalize the Accept-Language header ### We do not need a cache for each language-country combination! Just keep en-* and nl-* for future use. ### https://www.varnish-cache.org/docs/4.0/users-guide/increasing-your-hitrate.html#http-vary # if (req.http.Accept-Language) { # if (req.http.Accept-Language ~ "^en") { # set req.http.Accept-Language = "en"; # } elsif (req.http.Accept-Language ~ "^nl") { # set req.http.Accept-Language = "nl"; # } else { # # Unknown language. Set it to English. # set req.http.Accept-Language = "en"; # } # } # 对这些文件类型试着进行gzip压缩 if (req.http.Accept-Encoding) { if (req.url ~ "\.(jpg|png|gif|gz|tgz|bz2|tbz|mp3|ogg)$") { unset req.http.Accept-Encoding; } elsif (req.http.Accept-Encoding ~ "gzip") { set req.http.Accept-Encoding = "gzip"; } elsif (req.http.Accept-Encoding ~ "deflate") { set req.http.Accept-Encoding = "deflate"; } else { unset req.http.Accept-Encoding; } } ### ### Varnish v4: vcl_recv must now return hash instead of lookup return(hash); } sub vcl_backend_response { #unset beresp.http.Server; #unset beresp.http.X-Powered-By; #unset beresp.http.Via; #unset beresp.http.X-Varnish; # 默认为缓存24小时 set beresp.ttl = 24h; # Define the default grace period to serve cached content set beresp.grace = 30s; # set beresp.ttl = 5m; # set beresp.grace = 8h; # set beresp.http.cache-control = "max-age = 259200"; # 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. # main variable = beresp. } sub vcl_deliver { # Happens when we have all the pieces we need, and are about to send the # response to the client. You can do accounting or modifying the final object here. # main variable = resp. # set resp.http.Server = "old.tingtao.org CDN Server"; # set resp.http.X-Powered-By = "electricity"; #去除一些非必需的http头,你可以打开,也可以像上面两行那样修改 unset resp.http.X-Powered-By; unset resp.http.Server; unset resp.http.Via; unset resp.http.X-Varnish; if (obj.hits > 0) { set resp.http.X-Cache = "HIT"; } else { set resp.http.X-Cache = "MISS"; } } sub vcl_pipe { # https://www.varnish-software.com/blog/using-pipe-varnish # Note that only the first request to the backend will have X-Forwarded-For set. # If you use X-Forwarded-For and want to have it set for all requests, # then make sure to use this: set req.http.connection = "close"; # (This code is not necessary if you do not do any request rewriting.) set req.http.connection = "close"; } ###EndOf: .vcl
2016.09.18更新:经近期测试,Varnish HTTP Purge这个插件没用,更新插件看这篇文章: 《WordPress可支持Varnish 4.1的插件》
感觉还是没有使用Nginx fastcgi_cache缓存的快
不可能的,目前我们平民能买到的计算机存储系统里面,内存的效率是最高的,nginx不论如何都不会快于varnish的
不过最佳方案是varnish做http,nginx做https,这样是黄金搭档了
您好,
本人菜鸟,请教一下,按照您的方法,安装Super Static Cache以后,我选择的 Rewrite Mode (Recommend) 这个模式,在网站根目录生成了 Super-Static-Cache文件夹,里面有html文件。
同时,varnish 按照您的最新版本设置的vcl,测试后发现,varnish 并没有缓存到Super-Static-Cache文件夹里的html信息,请问varnish 的 vcl 是不是应该特别设置下呢?如何设置?
谢谢
我这不需要特别设置,连很多文章里提到的acl都没有搞就可以的……你说的没有缓存是怎么个情况?直接透传?还是miss?还是?
按照我的配置文件的话,只要http头有age数值或者是hit状态,那就说明varnish已经缓存了,如果配置策略要求缓存,但实际上没有缓存的话,我知道的只有一个情况,就是内存不足,因为varnish是纯内存缓冲,所以如果系统可用物理内存达不到你给varnish配置的数额,同时过期策略又不允许清理掉较老的内容,那么可能会导致直接透传而不进行缓存,其他情况我还真没遇到过。补充,还有个情况就是任何文件第一次通过varnish都一定不会缓存的。
[…] 之前在《用Varnish+Super Static Cache+Varnish HTTP Purge给WordPress疯狂加速》文中推荐的是Varnish HTTP Purge这个插件,但是据我这几个月测试下来,这玩意根本不会刷新varnish缓存,哪怕是varnish与web server相同机器都不行,本文做一纠正。 […]
老大,我来第一个支持你哈。
我浏览器开了2天还没关闭哈。
我这几天也在折腾varnish 给wordpress加速在centos下。
加油咯,这个不算复杂,搞明白了也挺简单的,我测试的效果还是不错的