Django的缓存框架


本文整理自网络,侵删。

Django的缓存框架

动态网站的基本权衡是动态的。每次用户请求页面时,Web服务器都会进行各种计算-从数据库查询到模板呈现再到业务逻辑-创建站点访问者可以看到的页面。从处理开销的角度来看,这比标准的从文件中读取文件的服务器系统要贵得多。

对于大多数Web应用程序而言,此开销并不大。大多数Web应用程序不是washingtonpost.com或slashdot.org; 它们是流量中等的中小型网站。但是对于中到高流量的站点,必须尽可能减少开销。

那就是缓存的来源。

缓存某些内容是为了保存昂贵的计算结果,因此您下次不必执行计算。以下是一些伪代码,用于说明如何将其应用于动态生成的网页:

given a URL, try finding that page in the cache
if the page is in the cache:
    return the cached page
else:
    generate the page
    save the generated page in the cache (for next time)
    return the generated page

Django带有一个健壮的缓存系统,可让您保存动态页面,因此不必为每个请求都计算它们。为了方便起见,Django提供了不同级别的缓存粒度:您可以缓存特定视图的输出,可以仅缓存难以生成的片段,或者可以缓存整个站点。

Django还可以与“下游”缓存(例如Squid和基于浏览器的缓存)配合使用。这些是您不直接控制的缓存类型,但是您可以向它们提供提示(通过HTTP标头)有关站点的哪些部分以及应该如何缓存的提示。

也可以看看

该缓存框架的设计理念, 解释了一些框架的设计决策。

设置缓存

缓存系统需要少量设置。即,您必须告诉它缓存的数据应该存放在哪里–无论是在数据库中,在文件系统上还是直接在内存中。这是一个影响缓存性能的重要决定。是的,某些缓存类型比其他类型更快。

您的缓存首选项进入CACHES设置文件中的设置。以下是的所有可用值的说明 CACHES。

Memcached

Memcached是Django原生支持的最快,最高效的缓存类型, 是一种完全基于内存的缓存服务器,最初是为处理LiveJournal.com上的高负载而开发的,随后由Danga Interactive开源。Facebook和Wikipedia等网站使用它来减少数据库访问并显着提高网站性能。

Memcached作为守护程序运行,并分配了指定数量的RAM。它所做的只是提供一个用于添加,检索和删除缓存中数据的快速接口。所有数据都直接存储在内存中,因此没有数据库或文件系统使用的开销。

本身安装Memcached后,您需要安装Memcached绑定。有几种可用的Python Memcached绑定。两种最常见的是python-memcached和pylibmc。

要将Memcached与Django结合使用,请执行以下操作:

  • 设置BACKEND为 django.core.cache.backends.memcached.MemcachedCache或 django.core.cache.backends.memcached.PyLibMCCache(取决于您选择的内存缓存绑定)
  • 设置LOCATION为ip:port值,其中ip是Memcached守护程序的IP地址,port是运行Memcached的端口,或者设置为unix:path值,其中 path是Memcached Unix套接字文件的路径。

在此示例中,Memcached使用python-memcached绑定在本地主机(127.0.0.1)端口11211上运行:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': '127.0.0.1:11211',
    }
}

在此示例中,可以/tmp/memcached.sock使用python-memcached绑定通过本地Unix套接字文件使用Memcached :

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': 'unix:/tmp/memcached.sock',
    }
}

使用pylibmc绑定时,请勿包括unix:/前缀:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
        'LOCATION': '/tmp/memcached.sock',
    }
}

Memcached的一项出色功能是能够在多个服务器上共享缓存。这意味着您可以在多台计算机上运行Memcached守护程序,并且该程序会将计算机组视为单个 缓存,而无需在每台计算机上重复缓存值。要利用此功能,请将所有服务器地址包含在中 LOCATION,以分号或逗号分隔的字符串或列表的形式。

在此示例中,缓存在IP地址为172.19.26.240和172.19.26.242且均在端口11211上运行的Memcached实例之间共享:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': [
            '172.19.26.240:11211',
            '172.19.26.242:11211',
        ]
    }
}

在以下示例中,缓存在运行在IP地址172.19.26.240(端口11211),172.19.26.42(端口11212)和172.19.26.244(端口11213)上的Memcached实例上共享:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': [
            '172.19.26.240:11211',
            '172.19.26.242:11212',
            '172.19.26.244:11213',
        ]
    }
}

关于Memcached的最后一点是基于内存的缓存有一个缺点:由于缓存的数据存储在内存中,因此如果服务器崩溃,数据将丢失。显然,内存不是用于永久性数据存储的,因此不要依赖基于内存的缓存作为唯一的数据存储。毫无疑问,任何 Django缓存后端都不应该用于永久存储-它们都旨在作为缓存而非存储的解决方案-但我们在此指出这一点是因为基于内存的缓存特别临时。

数据库高速缓存

Django可以将其缓存的数据存储在您的数据库中。如果您拥有快速索引良好的数据库服务器,则此方法效果最佳。

要将数据库表用作缓存后端:

  • 设置BACKEND于 django.core.cache.backends.db.DatabaseCache
  • 设置LOCATION为tablename,数据库表的名称。该名称可以是您想要的任何名称,只要它是数据库中尚未使用的有效表名即可。

在此示例中,缓存表的名称为my_cache_table:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
        'LOCATION': 'my_cache_table',
    }
}

创建缓存表

在使用数据库缓存之前,必须使用以下命令创建缓存表:

python manage.py createcachetable

这会在您的数据库中创建一个表,该表的格式与Django的数据库缓存系统期望的格式相同。该表的名称取自 LOCATION。

如果使用多个数据库缓存,请createcachetable为每个缓存创建一个表。

如果您使用多个数据库,请createcachetable遵循allow_migrate()数据库路由器的 方法(请参见下文)。

像一样migrate,createcachetable不会触摸现有表格。它只会创建丢失的表。

要打印将要运行的SQL,而不是运行它,请使用 选项。createcachetable --dry-run

多个数据库

如果将数据库缓存与多个数据库一起使用,则还需要为数据库缓存表设置路由说明。为了进行路由,数据库高速缓存表CacheEntry在名为的应用程序中显示为名为的模型 django_cache。该模型不会出现在模型缓存中,但是可以将模型详细信息用于路由目的。

例如,以下路由器会将所有缓存读取操作定向到cache_replica,并将所有写入操作定向到 cache_primary。缓存表将仅同步到 cache_primary:

class CacheRouter:
    """A router to control all database cache operations"""

    def db_for_read(self, model, **hints):
        "All cache read operations go to the replica"
        if model._meta.app_label == 'django_cache':
            return 'cache_replica'
        return None

    def db_for_write(self, model, **hints):
        "All cache write operations go to primary"
        if model._meta.app_label == 'django_cache':
            return 'cache_primary'
        return None

    def allow_migrate(self, db, app_label, model_name=None, **hints):
        "Only install the cache model on primary"
        if app_label == 'django_cache':
            return db == 'cache_primary'
        return None

如果您没有为数据库缓存模型指定路由方向,则缓存后端将使用default数据库。

当然,如果您不使用数据库缓存后端,则无需担心为数据库缓存模型提供路由说明。

文件系统缓存

基于文件的后端将每个缓存值序列化并存储为单独的文件。要将此后端设置BACKEND为"django.core.cache.backends.filebased.FileBasedCache"并 设置到 LOCATION合适的目录。例如,要在中存储缓存的数据/var/tmp/django_cache,请使用以下设置:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
        'LOCATION': '/var/tmp/django_cache',
    }
}

如果您使用的是Windows,请将驱动器号放在路径的开头,如下所示:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
        'LOCATION': 'c:/foo/bar',
    }
}

目录路径应该是绝对的-也就是说,它应该从文件系统的根目录开始。是否在设置的末尾加斜杠都没关系。

确保此设置指向的目录存在,并且Web服务器在其下运行的系统用户可以读写。继续上面的示例,如果您的服务器以用户身份运行apache,请确保该目录/var/tmp/django_cache存在并且可由用户读取和写入apache。

本地内存缓存

如果未在设置文件中指定其他缓存,则这是默认缓存。如果您想要内存中缓存的速度优势,但又不具备运行Memcached的功能,请考虑使用本地内存缓存后端。该缓存是按进程(请参阅下文)并且是线程安全的。要使用它,请设置BACKEND为"django.core.cache.backends.locmem.LocMemCache"。例如:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
        'LOCATION': 'unique-snowflake',
    }
}

高速缓存LOCATION用于标识各个内存存储。如果只有一个locmem缓存,则可以省略 LOCATION; 但是,如果您有多个本地内存缓存,则需要至少为其分配一个名称,以使它们分开。

缓存使用最近最少使用(LRU)淘汰策略。

请注意,每个进程都有其自己的专用缓存实例,这意味着不可能进行跨进程缓存。这显然也意味着本地内存缓存不是特别有效的内存,因此对于生产环境而言,它可能不是一个好选择。这对开发很好。

虚拟缓存(用于开发)

最后,Django附带了一个“虚拟”缓存,该缓存实际上并没有缓存-它只是实现了缓存接口而无所事事。

如果您的生产站点在各个地方都使用了重型缓存,但是在开发/测试环境中却不想缓存并且不想将代码更改为后者的特殊情况,这将非常有用。要激活虚拟缓存,设置BACKEND如下:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
    }
}

使用自定义缓存后端

尽管Django开箱即用地支持许多缓存后端,但有时您可能希望使用自定义的缓存后端。要使用Django的外部缓存后端,使用Python导入路径作为 BACKEND该的CACHES设置,如下所示:

CACHES = {
    'default': {
        'BACKEND': 'path.to.backend',
    }
}

如果要构建自己的后端,则可以将标准缓存后端用作参考实现。您将django/core/cache/backends/在Django源代码的目录中找到代码 。

注意:如果没有真正令人信服的理由,例如不支持它们的主机,则应坚持使用Django随附的缓存后端。他们已经过充分的测试并且有据可查。

缓存参数

可以为每个缓存后端提供其他参数来控制缓存行为。这些参数作为设置中的其他键提供 CACHES。有效参数如下:

  • TIMEOUT:用于缓存的默认超时(以秒为单位)。此参数默认为300秒(5分钟)。您可以设置TIMEOUT为None默认情况下,缓存键永不过期。值的值0使键立即过期(有效地是“不缓存”)。
  • OPTIONS:应传递到缓存后端的所有选项。有效选项的列表将随每个后端而有所不同,并且由第三方库支持的缓存后端会将其选项直接传递给基础缓存库。实现自己的扑杀战略(即缓存后端locmem,filesystem以及database后端)将履行下列选项:MAX_ENTRIES:删除旧值之前,缓存中允许的最大条目数。此参数默认为300。CULL_FREQUENCY:MAX_ENTRIES到达时被剔除的条目分数。实际比例为 ,因此设置为在达到时剔除一半条目。此参数应为整数,默认为。1 / CULL_FREQUENCYCULL_FREQUENCY2MAX_ENTRIES3值0for CULL_FREQUENCY表示MAX_ENTRIES到达时将转储整个缓存。在一些后端(database尤其是)这使得扑杀多 以更高速缓存未命中的代价更快。Memcached后端将OPTIONS as关键字参数的内容传递给客户端构造函数,从而可以更高级地控制客户端行为。有关用法示例,请参见下文。
  • KEY_PREFIX:一个字符串,它将自动包含在Django服务器使用的所有缓存键中(默认为前缀)。有关更多信息,请参见缓存文档。
  • VERSION:Django服务器生成的缓存键的默认版本号。有关更多信息,请参见缓存文档。
  • KEY_FUNCTION 一个字符串,其中包含指向函数的虚线路径,该函数定义了如何将前缀,版本和键组成最终的缓存键。有关 更多信息,请参见缓存文档。

在此示例中,文件系统后端的超时时间为60秒,最大容量为1000:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
        'LOCATION': '/var/tmp/django_cache',
        'TIMEOUT': 60,
        'OPTIONS': {
            'MAX_ENTRIES': 1000
        }
    }
}

这python-memcached是对象大小限制为2MB 的基于后端的示例配置:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': '127.0.0.1:11211',
        'OPTIONS': {
            'server_max_value_length': 1024 * 1024 * 2,
        }
    }
}

这是pylibmc基于基础的后端的示例配置,该配置启用了二进制协议,SASL身份验证和ketama行为模式:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
        'LOCATION': '127.0.0.1:11211',
        'OPTIONS': {
            'binary': True,
            'username': 'user',
            'password': 'pass',
            'behaviors': {
                'ketama': True,
            }
        }
    }
}

每个站点的缓存

一旦设置了缓存,使用缓存的最简单方法就是缓存整个站点。您需要将'django.middleware.cache.UpdateCacheMiddleware'和 添加 'django.middleware.cache.FetchFromCacheMiddleware'到 MIDDLEWARE设置中,如以下示例所示:

MIDDLEWARE = [
    'django.middleware.cache.UpdateCacheMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.cache.FetchFromCacheMiddleware',
]

注意

不,这不是输入错误:“更新”中间件必须位于列表的第一位,“获取”中间件必须位于最后。细节有些晦涩,但是如果您想了解完整的故事,请参阅下面的MIDDLEWARE顺序。

然后,将以下必需设置添加到Django设置文件中:

  • CACHE_MIDDLEWARE_ALIAS –用于存储的缓存别名。
  • CACHE_MIDDLEWARE_SECONDS –每个页面应缓存的秒数。
  • CACHE_MIDDLEWARE_KEY_PREFIX–如果使用同一Django安装在多个站点之间共享缓存,请将其设置为站点名称或该Django实例唯一的其他字符串,以防止按键冲突。如果您不在乎,请使用空字符串。

FetchFromCacheMiddleware缓存状态为200的GET和HEAD响应,其中请求和响应标头允许。对具有不同查询参数的相同URL请求的响应被视为唯一页面,并分别进行缓存。该中间件期望用与相应的GET请求相同的响应头来应答HEAD请求。在这种情况下,它可以为HEAD请求返回缓存的GET响应。

此外,会UpdateCacheMiddleware自动在每个标题中设置一些标题 HttpResponse:

  • 将Expires标题设置为当前日期/时间加上定义的 CACHE_MIDDLEWARE_SECONDS。
  • Cache-Control再次设置,将页眉设置为页面的最长使用期限CACHE_MIDDLEWARE_SECONDS。

有关中间件的更多信息,请参见中间件。

如果视图设置了自己的缓存到期时间(即max-age,其Cache-Control标题中有一个部分),则页面将一直缓存到到期时间,而不是CACHE_MIDDLEWARE_SECONDS。使用装饰器 django.views.decorators.cache可以轻松设置视图的过期时间(使用cache_control()装饰器)或禁用视图的缓存(使用 never_cache()装饰器)。有关这些装饰器的更多信息,请参见“ 使用其他标头”部分。

如果USE_I18N设置为,True则生成的缓存键将包括活动语言的名称-另请参见 Django如何发现语言首选项。这使您可以轻松地缓存多语言站点,而不必自己创建缓存密钥。

缓存键还包括积极的语言时, USE_L10N设置为True与当前时区时USE_TZ被设置为True。

每视图缓存

django.views.decorators.cache.cache_page()

使用缓存框架的更精细的方法是缓存单个视图的输出。django.views.decorators.cache定义一个cache_page 装饰器,该装饰器将自动为您缓存视图的响应:

from django.views.decorators.cache import cache_page

@cache_page(60 * 15)
def my_view(request):
    ...

cache_page有一个参数:缓存超时(以秒为单位)。在上面的示例中,my_view()视图结果将被缓存15分钟。(请注意,我们出于可读性的目的编写了该代码。它将被评估为– 15分钟乘以每分钟60秒。)60 * 1560 * 15900

与每个站点的缓存一样,每个视图的缓存也是从URL键入的。如果多个URL指向同一视图,则每个URL将被分别缓存。继续该my_view示例,如果您的URLconf如下所示:

urlpatterns = [
    path('foo/<int:code>/', my_view),
]

然后,您所期望的/foo/1/和的请求/foo/23/将分别进行缓存。但是,一旦/foo/23/请求了特定的URL(例如),则对该URL的后续请求将使用缓存。

cache_page也可以采用可选的关键字参数,cache该参数指示装饰器CACHES在缓存视图结果时使用特定的缓存(来自您的 设置)。默认情况下, default将使用缓存,但是您可以指定所需的任何缓存:

@cache_page(60 * 15, cache="special_cache")
def my_view(request):
    ...

您还可以基于每个视图覆盖缓存前缀。cache_page 带有一个可选的关键字参数,key_prefix其工作方式CACHE_MIDDLEWARE_KEY_PREFIX 与中间件的设置相同。可以这样使用:

@cache_page(60 * 15, key_prefix="site1")
def my_view(request):
    ...

的key_prefix和cache参数可以被同时指定。该 key_prefix参数和KEY_PREFIX 规定下,CACHES将串联。

在URLconf中指定每个视图的缓存

上一节中的示例已经硬编码了缓存视图的事实,因为该视图cache_page改变了my_view功能。这种方法将您的视图耦合到高速缓存系统,由于多种原因,这种方法并不理想。例如,您可能想在另一个无缓存的站点上重用视图功能,或者可能希望将视图分发给可能希望在不被缓存的情况下使用它们的人。这些问题的解决方案是在URLconf中指定每个视图的缓存,而不是在视图函数本身旁边。

您可以通过cache_page在URLconf中引用视图函数时将其包装在一起来实现。这是之前的旧版URLconf:

urlpatterns = [
    path('foo/<int:code>/', my_view),
]

这是同一件事,my_view包裹在其中cache_page:

from django.views.decorators.cache import cache_page

urlpatterns = [
    path('foo/<int:code>/', cache_page(60 * 15)(my_view)),
]

模板片段缓存

如果您希望获得更多控制权,则还可以使用cachetemplate标签缓存模板片段。要让您的模板访问此标签,请放在 模板顶部附近。{% load cache %}

该模板标签缓存块中的内容给定的时间量。它至少需要两个参数:高速缓存超时(以秒为单位)和提供高速缓存片段的名称。如果超时为,则片段将永远被缓存。名称将按原样使用,请勿使用变量。例如:{% cache %}None

{% load cache %}
{% cache 500 sidebar %}
    .. sidebar ..
{% endcache %}

有时,您可能希望根据片段内显示的一些动态数据来缓存片段的多个副本。例如,您可能想要为站点中的每个用户提供上一个示例中使用的侧边栏的单独的缓存副本。为此,请将一个或多个其他参数(可以是带或不带过滤器的变量)传递给模板标记,以唯一地标识缓存片段:{% cache %}

{% load cache %}
{% cache 500 sidebar request.user.username %}
    .. sidebar for logged in user ..
{% endcache %}

如果USE_I18N将设置为True每个站点,则中间件缓存将 尊重活动语言。对于cache模板标记,您可以使用模板中可用的特定于 翻译的变量之一来获得相同的结果:

{% load i18n %}
{% load cache %}

{% get_current_language as LANGUAGE_CODE %}

{% cache 600 welcome LANGUAGE_CODE %}
    {% trans "Welcome to example.com" %}
{% endcache %}

缓存超时可以是模板变量,只要模板变量解析为整数值即可。例如,如果将模板变量 my_timeout设置为value 600,那么以下两个示例是等效的:

{% cache 600 sidebar %} ... {% endcache %}
{% cache my_timeout sidebar %} ... {% endcache %}

此功能有助于避免模板中的重复。您可以在一个位置的变量中设置超时,然后重用该值。

阅读剩余部分

相关阅读 >>

使用asgi进行部署

Django 简介

Django 教程介绍

Django 模板

基于类的视图

Django的缓存框架

使用wsgi进行部署

Django 使用表单模板

Django 安装

Django 创建第一个项目

更多相关阅读请进入《Django》频道 >>




打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...