搞这个博客本身就是当日记写的,也没打算多少访问量多少收入,甚至连一个广告都木有,但是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的插件

作者 听涛

《用Varnish+Super Static Cache+Varnish HTTP Purge给WordPress疯狂加速》有8条评论
    1. 不可能的,目前我们平民能买到的计算机存储系统里面,内存的效率是最高的,nginx不论如何都不会快于varnish的

    2. 不过最佳方案是varnish做http,nginx做https,这样是黄金搭档了

  1. 您好,

    本人菜鸟,请教一下,按照您的方法,安装Super Static Cache以后,我选择的 Rewrite Mode (Recommend) 这个模式,在网站根目录生成了 Super-Static-Cache文件夹,里面有html文件。

    同时,varnish 按照您的最新版本设置的vcl,测试后发现,varnish 并没有缓存到Super-Static-Cache文件夹里的html信息,请问varnish 的 vcl 是不是应该特别设置下呢?如何设置?

    谢谢

    1. 我这不需要特别设置,连很多文章里提到的acl都没有搞就可以的……你说的没有缓存是怎么个情况?直接透传?还是miss?还是?
      按照我的配置文件的话,只要http头有age数值或者是hit状态,那就说明varnish已经缓存了,如果配置策略要求缓存,但实际上没有缓存的话,我知道的只有一个情况,就是内存不足,因为varnish是纯内存缓冲,所以如果系统可用物理内存达不到你给varnish配置的数额,同时过期策略又不允许清理掉较老的内容,那么可能会导致直接透传而不进行缓存,其他情况我还真没遇到过。补充,还有个情况就是任何文件第一次通过varnish都一定不会缓存的。

  2. […] 之前在《用Varnish+Super Static Cache+Varnish HTTP Purge给WordPress疯狂加速》文中推荐的是Varnish HTTP Purge这个插件,但是据我这几个月测试下来,这玩意根本不会刷新varnish缓存,哪怕是varnish与web server相同机器都不行,本文做一纠正。 […]

  3. 老大,我来第一个支持你哈。
    我浏览器开了2天还没关闭哈。
    我这几天也在折腾varnish 给wordpress加速在centos下。

    1. 加油咯,这个不算复杂,搞明白了也挺简单的,我测试的效果还是不错的

回复 听涛 取消回复

您的电子邮箱地址不会被公开。 必填项已用*标注