搞这个博客本身就是当日记写的,也没打算多少访问量多少收入,甚至连一个广告都木有,但是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下。
加油咯,这个不算复杂,搞明白了也挺简单的,我测试的效果还是不错的