清漆:开机自检数据后清除缓存



我有一个位于Varnish后面的Plone网站。除了一件事外,一切都正常。

这是一个动态网站,因此会不时有新内容。场景如下:

我有一个显示项目列表的页面。此页面已被缓存。所以我通过某种表单添加了另一个项目,并返回到同一页面,但没有显示新项目。这是因为显示的页面来自缓存,并且仍在其 TTL 中。

如何确保在提交新项目时,该页面将从缓存中清除,并且将显示后端服务器中包含新项目的新页面?

我的简单VCL如下所示:

backend default { 
    .host = "127.0.0.1"; 
    .port = "8080"; 
} 
sub vcl_recv { 
    if (req.request != "GET" && req.request != "HEAD") {
        # We only deal with GET and HEAD by default
        return (pass);
    }
    # remove unnecessary cookies 
    if (req.http.cookie ~ "wc.cookiecredentials|Path|Domain") { 
        # found wc.cookiecredentials in request, passing to backend server 
        return (lookup); 
    } else { 
        unset req.http.cookie; 
    } 
} 
sub vcl_fetch { 
    #unset beresp.http.Set-Cookie; 
    set beresp.ttl = 12h; 
    return(deliver); 
} 
# Routine used to determine the cache key if storing/retrieving a cached page. 
sub vcl_hash { 
    # Do NOT use this unless you want to store per-user caches. 
    if (req.http.Cookie) { 
        set req.hash += req.http.Cookie; 
    } 
} 
sub vcl_deliver { 
    # send some handy statistics back, useful for checking cache 
    if (obj.hits > 0) { 
        set resp.http.X-Cache-Action = "HIT"; 
        set resp.http.X-Cache-Hits = obj.hits; 
    } else { 
        set resp.http.X-Cache-Action = "MISS"; 
    } 
} 

或者说白了,每当我收到 POST 请求时,如何清除或清除域的整个缓存?

为此,

您需要自定义 Varnish VCL 以处理PURGE请求和 Plone CMS,以便在内容更改时向 Varnish 发出清除请求。

Plone

开发者文档有关于将 Varnish 与 Plone 一起使用的相当好和全面的文档。您可以根据自己的特定需求进行调整。

文档中的示例解释了如何在 VCL 中创建自定义 ACL 和正则表达式清除处理,以及如何在 Plone 中使用它来清除整个缓存。我已经从这里的例子中复制了VCL和Plone视图,以防它们在将来的某个时候从Plone站点中删除:

acl purge {
        "localhost";
        # XXX: Add your local computer public IP here if you
        # want to test the code against the production server
        # from the development instance
}
...
sub vcl_recv {
        ...
        # Allow PURGE requests clearing everything
        if (req.request == "PURGE") {
                if (!client.ip ~ purge) {
                        error 405 "Not allowed.";
                }
                # Purge for the current host using reg-ex from X-Purge-Regex header
                purge("req.http.host == " req.http.host " && req.url ~ " req.http.X-Purge-Regex);
                error 200 "Purged.";
        }
}

然后,对于 Plone,您可以创建一个自定义视图,用于向 Varnish 发出PURGE请求:

import requests
from Products.CMFCore.interfaces import ISiteRoot
from five import grok
from requests.models import Request
class Purge(grok.CodeView):
    """
    Purge upstream cache from all entries.
    This is ideal to hook up for admins e.g. through portal_actions menu.
    You can access it as admin::
        http://site.com/@@purge
    """
    grok.context(ISiteRoot)
    # Onlyl site admins can use this
    grok.require("cmf.ManagePortal")
    def render(self):
        """
        Call the parent cache using Requets Python library and issue PURGE command for all URLs.
        Pipe through the response as is.
        """
        # This is the root URL which will be purged
        # - you might want to have different value here if
        # your site has different URLs for manage and themed versions
        site_url = self.context.portal_url() + "/"
        headers = {
                   # Match all pages
                   "X-Purge-Regex" : ".*"
        }
        resp = requests.request("PURGE", site_url + "*", headers=headers)
        self.request.response["Content-type"] = "text/plain"
        text = []
        text.append("HTTP " + str(resp.status_code))
        # Dump response headers as is to the Plone user,
        # so he/she can diagnose the problem
        for key, value in resp.headers.items():
            text.append(str(key) + ": " + str(value))
        # Add payload message from the server (if any)
        if hasattr(resp, "body"):
                text.append(str(resp.body))

如前所述,这只是按需清除整个缓存。我不是 Plone 的专家,所以我无法就如何使其适应清除特定内容给出详细的答案。基本上,您需要确定在特定情况下需要清除哪些页面,然后调整上面的示例,以便在 Plone 中处理POST请求时自动向 Varnish 发出PURGE请求。

仅在VCL中处理清除(即检测开机自检呼叫并基于这些呼叫清除内容)非常复杂。我相信在 Plone 中处理逻辑和清除会更有效。

更新:

如果您希望清除每个POST上的整个缓存,可以按如下方式完成。

sub vcl_recv {
    if ( req.request == "POST") {
        ban("req.http.host == " + req.http.Host);
        return(pass);
    }
}

现在,每个POST请求都会导致从缓存中清除以相同主机名缓存的所有页面。不过,我建议从长远来看研究较早的解决方案。在发生POST时,仅清除实际需要清除的页面要高效得多。

最新更新