Django学习-缓存机制

此章对应于Django2。原文:https://djangobook.com/djangos-cache-framework/

在之前文章中提到了性能优化-缓存机制来实现,可以提高服务器性能,缩短响应时间。

动态网站的问题在于它需要根据每次的请求,动态通过相应业务逻辑根据输入条件获取数据,并进行模版渲染返回浏览器生成最终网页,在这个过程中,响应的快慢对服务器端的性能提出了较高的要求。

缓存的目的是避免重复计算以及资源的获取。从缓存中获取数据比铜鼓磁盘IO获取数据效率要高得多的多。

Django不仅可以在服务器端进行缓存,也可以和浏览器等合作,通过HTTP的头部信息指示浏览器缓存哪些数据,而非直接控制浏览器进行缓存。

启用缓存:

    1.在settings.py中CACHE属性附加对应的缓存设置。

        默认设置:

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

       Django支持服务器内存缓存、本地内存缓存、   数据库缓存、文件系统缓存、假缓存(开发环境用)、自定义缓存后端等

       服务器内存缓存:可使用Memcached高性能的分布式内存对象缓存系统。Memcached作为一个守护进程运行,并分配了特定数量的内存用户缓存数据,它只提供了添加、检索、删除缓存中任意数据的接口,所有数据都直接存储在内存中,可以降低对数据库或文件系统的系统开销。

       1.下载Memcached本身。

       2.下载连接Memcached服务的工具,如python-memcached或者pylibmc等

       3.将BACKEND属性设置为'django.core.cache.backends.memcached.MemcachedCache'或

           者‘django.core.cache.backends.memcached.PyLibMCCache’,依据所使用的连接工具。

       4.在CACHE属性中设置LOCATION属性为ip:port,其中,IP及PORT为Memcached的守护进程运行的主机及端口号。

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

关于Memcached可阅读官网资料http://memcached.org/。另外Memcached还支持分布式缓存能力,可以设置多台服务器为缓存服务器运行Memcached的守护进行,该程序会把这些服务器集群当成单一缓存处理,集群间不进行冗余存储,若要启用缓存服务器集群,需在LOCATION的字符串值中引入所有服务器地址,使用列表来包含。

       本地内存缓存:如果没有设置其他缓存方案,则本地内存缓存是默认配置。在不能使用Memcached情况下又想利用内存缓存的速度优势,可以使用本地内存缓存方案。如果本地内存缓存只有一个,则LOCATION参数可以省略,否则必须至少有一个可以区分的名字。另外,请注意每个进程都将有它自己的私有本地缓存,跨进程的本地内存缓存是不可能的 ,所以对于生产环境来说本地内存缓存可能不是一个最好的选择,尤其是多进程业务,但是对开发阶段是很好的。

       1.设置BACKEND属性为'django.core.cache.backends.locmem.LocMemCache'

       2.设置LOCATION参数为对应的'unique-snowflake'

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

       数据库缓存:在已经建立了一个性能优秀的数据库服务器时,使用数据库缓存的效果将最明显。

       1.设置BACKEND属性为'django.core.cache.backends.db.DatabaseCache'

       2.设置LOCATION参数为对应的cache_table_name,缓存表名,不要与现有表名重复

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

       3.在数据库中创建缓存表,使用python manage.py createcachetable [缓存表名]命令,这条指令会按照Django期望的数据库结构进行创建,创建的数据库缓存表名从LOCATION设置中获取。如果使用多数据库,该指令将为每个数据库创建一张缓存表,该指令不会更改已经存在的表,只会创建未存在的表。关于多数据库的路由设置及原理不在本文展开描述。

        文件系统缓存:会将每个缓存值序列化并单独存储为文件。

       1.设置BACKEND属性为'django.core.cache.backends.filebased.FileBasedCache'

       2.设置LOCATION参数为合适的文件夹绝对路径,从文件系统root根目录起始。(文件做好的斜杠有没有无所谓)。需要确保该文件夹路径存在且启动web服务的用户有读写权限。

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

        虚拟缓存:实现缓存接口但实际上不执行缓存工作,假缓存。可应用于正式生产环境时做了大量缓存而在开发阶段不期望缓存任何数据,就可以使用虚拟缓存。

       1.设置BACKEND属性为'django.core.cache.backends.dummy.DummyCache'

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

        自定义缓存后端:虽然Django已经支持了比较丰富的缓存后端,但是难保不会出现无法满足的情况,这时候就可以自己编写缓存后端提供给Django使用。如果要使用Django默认支持的缓存后端以外的后端,将python导入路径作为参数赋值给BACKEND属性。如果要自己编写后端缓存,可以参考Django默认支持的这些缓存源码,源码路径site-packages/django/core/cache/backends。

       1.设置BACKEND属性为'path.to.backend'

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

缓存设置:

    在settings.py的CACHE属性中可以进行缓存的设置。主要有如下几种设置

  1.TIMEOUT:缓存过期时间,按秒为单位。默认是300秒,设置None表示缓存永不过期,设置0表示马上过期,实际上设置0就表示不缓存了。

  2.OPTIONS:任何需要被传递给缓存后端的操作参数可以通过这个参数设置。不同的缓存后端这个属性的设置内容不太相同。并且由第三方库支持的缓存后端将直接将选项传递到基础缓存库。

        实施各个缓存后端自己策略遵循以下几个参数选项:

        2.1MAX_ECTRIES:最大缓存条目大小。超出部分时会删除最早的缓存条目。默认值为300

        2.2CULL_PREQUENCY:当缓存容量满的时候,一次性删除1/CULL_PREQUENCY的缓存数量条目。默认值为3,设为0表示缓存满的时候清空缓存。在某些缓存模式中(数据库为典型),清空缓存会换来更快的响应速度,但是以牺牲大量数据为前提。

  3.KEY_PREFIX:一个字符串,会被自动包含在Django服务所有缓存密钥中。

  4.VERSION:Django服务生成的缓存密钥的默认版本号

  5.KEY_FUNCTION:一个方法路径,包含点号。该方法定义如何将前缀、版本号、密钥等组合在一起形成最终的缓存密钥。

  以文件系统缓存后端为例,其示例设置如下:

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

缓存分类:

  站点级缓存:

  一旦缓存设置完成,最简单的使用缓存的方式是缓存整个站点内容。

  使用方法:

  1.设置django.middleware.cache.UpdateCacheMiddleware及django.middleware.cache.FetchFromCacheMiddleware中间键至settings.py配置文件的MIDDLEWARE_CLASSES。注意UpdateCacheMiddleware必须是第一个,而Fetch的必须是最后一个。这个涉及到中间件的加载顺序,另文记录。

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

  2.在settings.py中新增三个设置:

      2.1 CACHE_MIDDLEWARE_ALIAS:用于存储的缓存别名,默认为‘default’

      2.2 CACHE_MIDDLEWARE_SECONDS:每页缓存的秒数。

      2.3 CACHE_MIDDLEWARE_KEY_PREFIX:当Django服务集群化时,将缓存所服务的Django站点名称写入,或者其他能唯一标识该站点的字符串。防止密钥冲突。默认为空字符串,如果你不介意的话。

中间件的作用:FetchFromCacheMiddleware中间件缓存那些请求成功的GET及HEAD响应,当然需要这些请求及响应的头部信息允许。对于那些URL相同但是参数不同的请求及其对应的响应,会被认为是同一个页面,并分别进行缓存。这个中间件期望对一个HEAD请求将响应与GET请求相同的响应头部信息,这样就可以对一个HEAD请求响应一个已被缓存的GET响应。此外,UpdateCacheMiddleware中间件将会自动在每一个HttpResponse中增加一些头部信息。增加的头部信息如下:

    1.当一个新的页面请求传递过来时,将头部信息的Last-Modified最后更改时间更新为当前时间

    2.将请求的头部信息中缓存过期时间更新为当前时间+定义的过期秒数时间

    3.将请求的头部信息中关于Cache-control信息,设置一个最大有效期时间,同样这个时间来自于定义的CACHE_MIDDLEWARE_SECONDS。

注:

  1.如果一个视图设置了它自己的缓存有效时间(如在头部cache-control信息中设置了max-age选项),则对应的页面将会被缓存直至过期,而不是按照缓存定义的过期秒数来计算过期时间。可以通过django.views.decorators.cache装饰器来设置视图的缓存获取时间(cache_control_decorators)或者禁用视图的缓存(never_cache decorator)。

  2.如果settings.py中设置了USE_I18N为True,则生成的缓存密钥将包括对应语言的名称,这个机制将使得缓存多语言站点变得非常容易,它不需要用户自己来创建缓存密钥。

  3.如果USE_L10N设为True,缓存密钥包含当前语言名称;如果USE_TZ设为True,则缓存密钥包含当前时区。

视图级缓存:

    Django的缓存框架提供更细粒度的缓存级别,就是对输出的单个视图进行缓存。如上面所说,django.views.decorators.cache定义了一个页面缓存修饰器,它可以帮你自动缓存视图的响应。

  用法:

  1.导入cache_page。

  2.修饰一个视图函数,参数为过期时间。

from django.views.decorators.cache import cache_page

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

说明:

  1.与站点级缓存一样,每个视图都是缓存都是从URL传入的,如果多个URL指向同一个视图函数,则每个URL都将被分别缓存。如通过正则表达式捕获的URL。对foo/10/和foo/11/的请求,将会被分别缓存,但是一旦请求了foo/11/,则后面的foo/11/的请求都将会使用该缓存。

urlpatterns = [
    url(r'^foo/([0-9]{1,2})/$', my_view),
]

  2.页面缓存也可以接受一个参数“cache”,该参数可以指定修饰器在缓存视图响应时使用一个特定的缓存后端(setting.py中设置的)

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

  3.cache_page也可以在每个视图基础上重写缓存前缀,使用可选参数“key_prefix”,其工作方式与中间件的CACHH_MIDDLEWARE_KEY_PREFIX设置相同。

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

可以将cache可选参数和key_prefix可选参数一起指定。

  在URL中指定视图缓存:

  上面讲的都是在视图中通过硬编码方式实现视图缓存,但是如果我们想要将该视图函数重用给那些不需要进行缓存的功能时,那就显得不友好了,因为缓存和视图耦合在了一起。所以我们可以通过在URL中来配置视图缓存的方式来实现缓存与视图分离。

  用法:

  1.URL模块中导入cache_page

  2.在URL路由配置时,对视图函数使用cache_page()封装,将视图函数当作参数传给cache_page

from django.views.decorators.cache import cache_page

urlpatterns = [
    url(r'^foo/([0-9]{1,2})/$', cache_page(60 * 15)(my_view)),
]

模版碎片缓存:

你同样可以使用{% cache %}模版标签来缓存模块碎片数据。为了让模版可以使用这个模版标签,需要在模版顶部导入{% cache %},这个cache模版标签通过输入一定的缓存过去时间来缓存相应的内容数据。

用法:

  1.传入两个参数,一个是过期时间,按秒计;另一个是赋给这个缓存的名称(不要使用变量名)。

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

说明:

  1.可以通过设置额外的cache模版标签属性,来根据碎片内数据动态缓存不同版本的信息。

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

  2.可以将使用模版变量来表示过期时间,只要这个模版变量是一个整形类型数据就可以。下面两个等价。

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

手动设置缓存:

  通常情况下,站点级缓存、视图级缓存等不会有很大的改善。尤其对于结果数据经常变化,而查询效率低下的操作,更会因频繁缓存而用不上缓存而浪费性能。

Django提供了更底层的手动缓存API,自由度更大,可以自己根据需要来缓存想缓存的数据(该数据必须是可序列化的)。

from django.core.cache import cache
cache.set('my_key', 'hello, world!', 30) # 设置缓存,参数依次为索引键、值、过期时间(秒)
cache.get('my_key', [默认值])  # 根据索引键获取值。若存在对应缓存,则返回值,否则返回None,若设置了可选参数默认值,则当未搜索到对应缓存值时,返回默认值

cache.add('add_key', 'New value') # 新增一个原来没有的键值,若已存在,则不更新。该方法若成功添加,则返回True,否则返回False

ache.get_many(['a', 'b', 'c'])  # 根据参数里的列表数据,列表数据表示索引键列表,返回缓存值或存在的对应数据,返回为字典键值类型数据
cache.delete('a') # 手动删除索引键对应的键值记录
cache.incr('num', 10) # 增加已经存在的键值的值,如原来'num'对应为数字1,则执行此命令后,'num'对应为11。注需要值类型为数字
cache.decr('num', 4) # 与incr相反

# 注incr及decr不是原子级操作,只有在支持原子增减操作的缓存后端上,增减操作才是原子的

课外链接:

上游缓存:

  1.ISP互联网服务商缓存。ISP可能对特定的页面进行缓存,倒置请求还未到达web站点,ISP就帮你把页面响应给请求了。web开发人员无从得知这种缓存。

  2.Django部署在某个代理缓存之后,该缓存为提高性能而对页面进行缓存,这样会导致每个请求首先由代理服务器进行处理,仅在需要时传递至Django服务器。Nignx反向代理。

  3.浏览器对页面进行了缓存。

HTTP协议中,通过一些头部参数来指引上游缓存区分缓存内容,并通知缓存机制不对特定页面内容进行缓存。

1.vary参数:Django通过vary_on_headers对视图进行修饰,添加头部信息。

2.使用其他参数。通过cache_control视图修饰器来告诉缓存哪些数据是私有的,避免隐私数据被当成公有数据造成泄密。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值