Django学习15-缓存:Memcache

Django 缓存系统

Django是动态网站,每次用户请求页面时,Web服务器都会进行各种计算:从数据库查询到模板呈现再到业务逻辑 ,使得访问者能看到创建的站点的内容。 从处理开销的角度来看,这比从标准的文件服务器读取文本要大得多。对于大多数Web应用程序来说,这种开销并不是什么大问题。 大多数Web应用程序,只是一些中小型网站,访问流量不大。 但对于中高流量站点,必须尽可能减少开销。而且Django还支持共享缓存。

可以通过伪代码了解缓存机制在动态网站是如何进行的。

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也适用于“下游”(downstream)缓存,例如Squid和基于浏览器的缓存。 这些不是直接控制的缓存类型,但是可以提供有关缓存网站部分的提示(通过HTTP标头)以及如何缓存。

CACHES

要在Django使用缓存,需要在setting中设置CACHES并指定BACKEND缓存后端,Django自身缓存后台支持几种机制,

  • Local-memory caching:Django默认使用的缓存系统,数据存储在本地内存中:
  • Dummy caching (for development):开发时使用,只有接口;
  • Filesystem caching:文件缓存,使用文件来缓存数据;
  • Database caching:数据库缓存,使用项目数据库的数据表缓存数据,注意使用了多数据库时的路由设置
  • Memcached:使用Memcached作为缓存;

除了这些之外还可以使用自定义的缓存后端,如使用Redis作为缓存后端

CACHES = {
    # 默认缓存
    'default':{
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
        'LOCATION': 'unique-snowflake',
    },
    # 使用文件缓存
    'filecached': {
        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
        'LOCATION': '/var/tmp/django_cache',
    },
    # 使用memcached做缓存
    'memcached': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': ['127.0.0.1:11211',],
        'TIMEOUT': 60 * 60,
    },
    # 开发时使用的虚拟缓存,只是实现接口,实际不缓存
    'dummycached':{
        'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
    },
    # 使用数据库缓存,使用项目的数据库中的表做缓存
    'dbcached': {
        'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
        'LOCATION': 'my_cache_table',
    },
}

可以在缓存控制后端添加一些额外的参数:

  • TIMEOUT:设置默认的缓存超时时间(秒),这个时间默认是300秒,当为None时代表缓存不会过期,为0时代表不使用缓存。
  • KEY_PREFIX:如果要在服务器之间或生产环境与开发环境之间共享缓存实例,则一台服务器缓存的数据可能会被另一台服务器使用。 如果服务器之间的缓存数据格式不同,这可能会导致一些非常难以诊断的问题。为了防止这种情况,Django提供了为服务器使用的所有缓存键添加前缀的功能。 当保存或检索特定的缓存键时,Django将自动为缓存键添加KEY_PREFIX缓存设置的值。
  • VERSION:Django服务器生成的缓存键的默认版本号。如果程序代码更改后需要清除原有缓存,可以通过VERSION指定缓存的版本号和KEY_PREFIX结合指定新的缓存值。
  • KEY_FUNCTION:指定生成缓存秘钥的函数,需要将keyprefixversion结合起来 ,得到最终的缓存秘钥
  • OPTION:传递给缓存后端的选项,使用第三方支持的缓存后端时,会将这些选项传输给它们。
      MAX_ENTRIES:删除旧值之前缓存中允许的最大条目数。此参数默认为300。
      CULL_FREQUENCY:达到MAX_ENTRIES时剔除的条目部分。实际比率为1 / CULL_FREQUENCY,因此将CULL_FREQUENCY设置为2可在达到MAX_ENTRIES时剔除一半条目。此参数应为整数,默认为3。
      CULL_FREQUENCY的值为0意味着在达到MAX_ENTRIES时将转储整个缓存。在一些后端(特别是数据库)上,这使得剔除速度更快,但代价是更多的缓存未命中。

使用缓存

缓存整个网站

使用缓存最简单方法就是设置缓存整个网站,需要在MIDDLEWARE最前面添加django.middleware.cache.UpdateCacheMiddleware,在最后面添加django.middleware.cache.FetchFromCacheMiddleware
settings中添加以下值:

  • CACHE_MIDDLEWARE_ALIAS:存储用的缓存别名(CACHES中设置的值)
  • CACHE_MIDDLEWARE_SECONDS:页面被缓存的时间
  • CACHE_MIDDLEWARE_KEY_PREFIX:当缓存被不同的站点使用时,用来防止缓存key值冲突的,一般设为站点名字。

FetchFromCacheMiddleware中间件用来缓存通过GET和HEAD方法获取的状态码为200的响应。同一个url,带有不同的查询字符串,会当做不同的页面分别缓存。
UpdateCacheMiddleware中间件在响应HttpResponse中设置几个headers:
设置Last-Modified为页面最新的刷新时间,设置Expires为过期时间(现在时间加CACHE_MIDDLEWARE_SECONDS),设置Cache-Control页面最大有效期(CACHE_MIDDLEWARE_SECONDS)。
views逻辑函数也可以自己设置过期时间:
使用django.views.decorators.cache.cache_control()设置缓存过期时间,使用django.views.decorators.cache.never_cache()禁止缓存。

页面缓存

使用一个装饰器@cache_page装饰视图函数来缓存某个页面:

from django.views.decorators.cache import cache_page


@cache_page(60 * 15, cache='memcached')
def index(request):
    context = {'name':'<b>Hello</b>'}
    return render(request, 'index.html', context)

cache_page的第一个参数指定缓存有效时间(秒),cache参数指定使用的是CACHES中的哪一种缓存,key_prefix参数与CACHE_MIDDLEWARE_KEY_PREFIX相同。
除了使用装饰器,也可以在URLconf中就指定使用缓存:

from django.views.decorators.cache import cache_page

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

在模板中使用缓存

{% cache %}模板标签会缓存block内容,至少包括两个参数:缓存时间和缓存片段的name。

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

还可以根据变化的动态数据为一个片段缓存不同的拷贝:

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

Cache API

有时候缓存整个网站或是缓存整个页面都不会有太大好处,反而带来负担。例如,某个视图取决于几个开销很大的查询,其结果会在不同的时间会发生变化。这种情况不适用缓存整个站点或是网页,但仍然想要缓存那些很少改变的数据。这就需要Django提供的low-levelcache API,这样就可以缓存任意能被安全存储的Python对象:字符串、字典表、模型对象等。
获取default的cache:from django.core.cache import cache
通过别名获取自定义的cache:

from django.core.cache import caches
# ...
    cache = caches['memcached']
    cache.get_or_set('key_word', key_word, 60*15)

基本的用法set(key, value, timeout) ,get(key)和add(key, new_value):

>>> cache.set('add_key', 'Initial value')
>>> cache.add('add_key', 'New value')
>>> cache.get('add_key')
'Initial value'

timeout设置为None时,缓存永不过时,设置为0时不缓存。

设置Vary header

Django默认是使用url地址作为cache的key值的,也就是对相同的url请求会返回相同版本的缓存,不论无论用户代理差异如cookie或语言首选项如何。设置Vary首部字段,可以选择不同的缓存。

from django.views.decorators.vary import vary_on_headers
 
@vary_on_headers('User-Agent')
def my_view(request):
    ...

对于不同的User-Agent,my_view都会有不同的缓存。
也可以传多个headers:

@vary_on_headers('User-Agent', 'Cookie')
def my_view(request):
    ...

因为cookie是常用的,所以可以使用django.views.decorators.vary.vary_on_cookie()装饰器

@vary_on_cookie
def my_view(request):
    ...

@vary_on_headers('Cookie')
def my_view(request):
    ...

控制缓存

有关缓存的问题是数据的隐私性以及数据在级联缓存中存储。用户通常面临两种缓存:公共缓存和私有缓存时,Web应用程序需要一种方法来告诉缓存哪些数据是私有的,哪些是公共的。设置对特定的用户提供缓存服务:

from django.views.decorators.cache import cache_control

@cache_control(private=True)
def my_view(request):
    ...

还可以使用never_cache装饰器,控制视图不被浏览器或其他缓存系统缓存。

from django.views.decorators.cache import never_cache

@never_cache
def myview(request):
    ...

Memcached

Memcached是Django支持的最快,最有效的缓存类型,它是一一个自由开源的、高性能的、分布式内存对象缓存系统。本质上,它是一个简洁的key-value存储系统。
Memcached作为守护进程运行,并分配了指定数量的RAM。 它所做的就是提供一个快速接口,用于在缓存中添加,检索和删除数据。 所有数据都直接存储在内存中,因此不会产生数据库或文件系统使用的开销。

安装

Linux系统安装memcached,首先要先安装libevent库。
Debian/Ubuntu: apt-get install libevent-dev
edhat/Centos: yum install libevent-devel
自动安装sudo apt-get install memcached
安装Memcached后,还要安装python相关的依赖库,最常用的python-memcachedpylibmcpip install python-memcachedlpip install pylibmcpylic是使用c语言编写的,需要有gcc和python-dev环境和memcached的依赖,安装方法

Memcached 运行

Memcache 的命令帮助:

ulysses@ulysses:~$ memcached -h

启动选项:

  • -d是启动一个守护进程;
  • -m是分配给Memcache使用的内存数量,单位是MB;
  • -u是运行Memcache的用户;
  • -l是监听的服务器IP地址,可以有多个地址;
  • -p是设置Memcache监听的端口,,最好是1024以上的端口;
  • -c是最大运行的并发连接数,默认是1024;
  • -P是设置保存Memcache的pid文件。
  • -v显示错误或警告,-vv命令或回应信息也显示
    关闭Memcache,使用kill命令结束进程:
    kill `cat /tmp/memcached.pid`,注意使用反引号。
    可以选择
  1. 作为前台程序启动
ulysses@ulysses:~$ memcached -p 11211 -m 64m -vv -P /tmp/memcached.pid
slab class   1: chunk size        96 perslab   10922
slab class   2: chunk size       120 perslab    8738
slab class   3: chunk size       152 perslab    6898
......
slab class  38: chunk size    394840 perslab       2
slab class  39: chunk size    524288 perslab       2
<26 server listening (auto-negotiate)

  1. 作为后台程序运行,使用-d参数
ulysses@ulysses:~$ memcached -p 11211 -m 64m -d -P /tmp/memcached.pid

连接Memcached服务:telnet ip port

ulysses@ulysses:~$ telnet 127.0.0.1 11211
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
stats
STAT pid 31746
STAT uptime 7294
STAT time 1541667313
STAT version 1.5.6 Ubuntu
STAT libevent 2.1.8-stable
STAT pointer_size 64
STAT rusage_user 0.630103
...

使用Memcached作为Django缓存

要在Django使用Memcached,需要在CACHES设置LOCATION.
LOCATION可以使用ip:port的格式,也可以使用unix:path的格式,path就是Memcached Unix socket文件。
Memcached的一个出色功能是它能够在多个服务器上共享缓存。这意味着可以在多台计算机上运行Memcached守护程序,程序会将该组计算机视为单个缓存,而无需在每台计算机上复制缓存值。可以使用一个列表列出这些地址。

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

Memcached的一个出色功能是它能够在多个服务器上共享缓存。这意味着可以在多台计算机上运行Memcached守护程序,程序会将该组计算机视为单个缓存,而无需在每台计算机上复制缓存值。可以使用一个列表列出这些地址。

        'LOCATION': [
            '172.19.26.240:11211',
            '172.19.26.242:11211',
        ]

Memcached的缺点

Memcached的最后一点是基于内存的缓存有一个缺点:因为缓存的数据存储在内存中,如果服务器崩溃,数据将会丢失。 显然,内存不适用于永久数据存储,因此不要依赖基于内存的缓存作为唯一的数据存储。

猜你喜欢

转载自blog.csdn.net/qq_19268039/article/details/83860424