django每站点缓存究竟是如何工作的?

django每站点缓存究竟是如何工作的?,django,caching,memcached,Django,Caching,Memcached,我一直认为每个站点的缓存在过期之前不会更新,其他人也一样。然而,在我的网站上做了一些测试之后,我发现了不同的结果,正如你所看到的,这是一个典型的博客 下面是我如何测试它的: 使用memcached-vv启动memcached,这样我就可以看到memcached中发生了什么。 然后做了一些手术: 访问主页->访问主页->更新主页上的文章->访问主页 缓存存储无任何内容缓存存储(奇怪!) 主页在我上次访问时确实更新了 我的缓存过期时间是600秒,因此我可以向您保证,第二个缓存存储操作与缓存过期无关。

我一直认为每个站点的缓存在过期之前不会更新,其他人也一样。然而,在我的网站上做了一些测试之后,我发现了不同的结果,正如你所看到的,这是一个典型的博客

下面是我如何测试它的:

  • 使用
    memcached-vv
    启动memcached,这样我就可以看到memcached中发生了什么。 然后做了一些手术:

  • 访问主页->访问主页->更新主页上的文章->访问主页
    缓存存储无任何内容缓存存储(奇怪!)

  • 主页在我上次访问时确实更新了

    我的缓存过期时间是600秒,因此我可以向您保证,第二个缓存存储操作与缓存过期无关。(事实上,我重复了几次,都给出了相同的结果)


    那么这是什么解释呢?报告没有提供太多信息。还是因为我以错误的方式进行了测试?

    您可以在中间件中查找
    process\u response
    的源代码来找出它:

    def process_response(self, request, response):
        """Sets the cache, if needed."""
        if not self._should_update_cache(request, response):
            # We don't need to update the cache, just return.
            return response
    
        if response.streaming or response.status_code != 200:
            return response
    
        # Don't cache responses that set a user-specific (and maybe security
        # sensitive) cookie in response to a cookie-less request.
        if not request.COOKIES and response.cookies and has_vary_header(response, 'Cookie'):
            return response
    
        # Try to get the timeout from the "max-age" section of the "Cache-
        # Control" header before reverting to using the default cache_timeout
        # length.
        timeout = get_max_age(response)
        if timeout is None:
            timeout = self.cache_timeout
        elif timeout == 0:
            # max-age was set to 0, don't bother caching.
            return response
        patch_response_headers(response, timeout)
        if timeout:
            cache_key = learn_cache_key(request, response, timeout, self.key_prefix, cache=self.cache)
            if hasattr(response, 'render') and callable(response.render):
                response.add_post_render_callback(
                    lambda r: self.cache.set(cache_key, r, timeout)
                )
            else:
                self.cache.set(cache_key, response, timeout)
        return response
    
    首先检查您的博客是否旨在拥有经过身份验证的用户,因为如果不是request.COOKIES和response.COOKIES,它将无法工作,并且具有不同的标题(response,'Cookie')

    如果未通过身份验证,则您必须查看
    学习缓存\u key
    方法,该方法计算视图将在其中缓存的密钥:

    def learn_cache_key(request, response, cache_timeout=None, key_prefix=None, cache=None):
    """
    Learns what headers to take into account for some request URL from the
    response object. It stores those headers in a global URL registry so that
    later access to that URL will know what headers to take into account
    without building the response object itself. The headers are named in the
    Vary header of the response, but we want to prevent response generation.
    
    The list of headers to use for cache key generation is stored in the same
    cache as the pages themselves. If the cache ages some data out of the
    cache, this just means that we have to build the response once to get at
    the Vary header and so at the list of headers to use for the cache key.
    """
    if key_prefix is None:
        key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
    if cache_timeout is None:
        cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS
    cache_key = _generate_cache_header_key(key_prefix, request)
    if cache is None:
        cache = caches[settings.CACHE_MIDDLEWARE_ALIAS]
    if response.has_header('Vary'):
        is_accept_language_redundant = settings.USE_I18N or settings.USE_L10N
        # If i18n or l10n are used, the generated cache key will be suffixed
        # with the current locale. Adding the raw value of Accept-Language is
        # redundant in that case and would result in storing the same content
        # under multiple keys in the cache. See #18191 for details.
        headerlist = []
        for header in cc_delim_re.split(response['Vary']):
            header = header.upper().replace('-', '_')
            if header == 'ACCEPT_LANGUAGE' and is_accept_language_redundant:
                continue
            headerlist.append('HTTP_' + header)
        headerlist.sort()
        cache.set(cache_key, headerlist, cache_timeout)
        return _generate_cache_key(request, request.method, headerlist, key_prefix)
    else:
        # if there is no Vary header, we still need a cache key
        # for the request.build_absolute_uri()
        cache.set(cache_key, [], cache_timeout)
        return _generate_cache_key(request, request.method, [], key_prefix)
    
    请注意,Django将深入
    response['Vary']
    标题,并将其添加到键的变体中

    因此,首先检查您的响应是否添加了
    Vary
    标题,如果是,它有哪个值,如果它与保存条目之前不同,为什么不缓存

    另外请注意,如果多语言被激活,它也会为每种语言生成不同的键

    当Django添加或修改
    Vary
    标题时?

    在这里,您可以看到它何时发生或如何在中发生,以及如何在视图中控制缓存

    最后要考虑的是,如果你在博客上使用第三方应用程序,那么它可能会利用缓存控制机制来刷新缓存,从而改变数据,比如更新条目

    Django版本

    在Django>=1.7中,使用了完全限定的URL,因此如果使用这些版本,还需要考虑主机:

    Django 1.7中的更改: 缓存键使用请求的完全限定URL,而不仅仅是路径和查询字符串


    结果我的测试有问题。当没有其他人访问我的站点时,我再次仔细测试。下面是
    memcached-vv
    的输出:

    # first visit
    
    <30 new auto-negotiating client connection
    30: Client using the ascii protocol
    <30 get :1:views.decorators.cache.cache_header..f384b899ecab7abd6fb0a567608b97b2.en-us.CST
    >30 END
    <30 set :1:views.decorators.cache.cache_header..f384b899ecab7abd6fb0a567608b97b2.en-us.CST 1 600 14
    >30 STORED
    <30 set :1:views.decorators.cache.cache_page..GET.f384b899ecab7abd6fb0a567608b97b2.d41d8cd98f00b204e9800998ecf8427e.en-us.CST 1 600 33215
    >30 STORED
    <30 connection closed.
    
    # second visit
    
    <30 new auto-negotiating client connection
    30: Client using the ascii protocol
    <30 get :1:views.decorators.cache.cache_header..f384b899ecab7abd6fb0a567608b97b2.en-us.CST
    >30 sending key :1:views.decorators.cache.cache_header..f384b899ecab7abd6fb0a567608b97b2.en-us.CST
    >30 END
    <30 get :1:views.decorators.cache.cache_page..GET.f384b899ecab7abd6fb0a567608b97b2.d41d8cd98f00b204e9800998ecf8427e.en-us.CST
    >30 sending key :1:views.decorators.cache.cache_page..GET.f384b899ecab7abd6fb0a567608b97b2.d41d8cd98f00b204e9800998ecf8427e.en-us.CST
    >30 END
    <30 connection closed.
    
    # modified and save
    
    <30 new auto-negotiating client connection
    30: Client using the ascii protocol
    <30 get :1:views.decorators.cache.cache_header..7029e9375fc4657a73dae1f9bddb73e5.en-us.CST
    >30 END
    <30 connection closed.
    
    # visit again
    
    <30 new auto-negotiating client connection
    30: Client using the ascii protocol
    <30 get :1:views.decorators.cache.cache_header..f384b899ecab7abd6fb0a567608b97b2.en-us.CST
    >30 sending key :1:views.decorators.cache.cache_header..f384b899ecab7abd6fb0a567608b97b2.en-us.CST
    >30 END
    <30 get :1:views.decorators.cache.cache_page..GET.f384b899ecab7abd6fb0a567608b97b2.d41d8cd98f00b204e9800998ecf8427e.en-us.CST
    >30 sending key :1:views.decorators.cache.cache_page..GET.f384b899ecab7abd6fb0a567608b97b2.d41d8cd98f00b204e9800998ecf8427e.en-us.CST
    >30 END
    <30 connection closed. 
    
    #首次访问
    
    没有源代码很难回答。可能memcached的-vv在删除密钥时不起作用,所以“更新主页上的文章”会以静默方式重新评估缓存。@SergeyMNikitin,源代码在这里。还请记住,框架将相同的URL和不同的查询参数视为不同的响应,并将分别缓存每个响应。例如,“/blog/?page=1”和“blog/”将获得单独的缓存项,即使内容完全相同。你看到的是同一个缓存键吗?@laike9m我猜你在看到
    memcached-vv
    的输出时可能错过了一些东西,你能分享一下终端的日志吗?@skbly7好的。在我编辑我的问题后,我会让你知道。我没有使用第三方应用程序。问题可能是通过不同的URL(laike9m.com和www.laike9m.com)访问。是的,这是我在文章中给出的原因之一,事实上在Django 1.7中,有一个关于每个站点缓存如何处理URL的警告(从1.7开始,它们是完全限定的)