Django缓存系统实现过程解析


Posted in Python onAugust 02, 2019

在动态网站中,用户每次请求一个页面,服务器都会执行以下操作:查询数据库,渲染模板,执行业务逻辑,最后生成用户可查看的页面。

这会消耗大量的资源,当访问用户量非常大时,就要考虑这个问题了。

缓存就是为了防止重复计算,把那些消耗了大量资源的结果保存起来,下次访问时就不用再次计算了。缓存的逻辑:

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也可以和一些”下游”缓存一起协作,例如Squid和基于浏览器的缓存,这些类型的缓存你不直接控制,但是你可以提供给他们站点哪部分应该被缓存和怎样被缓存(通过HTTP headers)。

设置缓存

在settings中的CACHES中设置缓存,下面是几个可用的缓存选项:

Memcached

Django目前原生支持的最快最有效的缓存系统。要使用Memcached,需要下载Memcached支持库,一般是python-memcached或者pylibmc。

然后设置BACKEND为django.core.cache.backends.memcached.MemcachedCache(使用python-memcached时)或者django.core.cache.backends.memcached.PyLibMCCache(使用pylibmc时)。

设置LOCATION为ip:port或者unix:path。例如:

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

或者

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进程,程序将会把这组机器当作一个单独的缓存,而不需要在每台机器上复制缓存值:

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是基于内存的缓存,数据只存储在内存中,如果服务器死机的话数据会丢失,所以不要把内存缓存作为唯一的数据存储方法。

Database caching

Django也可以把缓存数据存储在数据库中。

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

LOCATION为数据库中table的名字,任意起,在数据库中未被使用过即可以。

创建cache table:

python manage.py createcachetable

使用多数据库时,也需要为cache table写Router:

class CacheRouter(object):
 """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

Filesystem caching

也可以使用文件来存储缓存数据。

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

LOCATION为缓存数据存储目录。

windows中:

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

Local-memory caching

Django默认使用的缓存系统,数据存储在本地内存中:

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

Dummy caching (for development)

开发时使用的:

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

Using a custom cache backend

也可以使用其它的缓存系统,比如Redis,django-redis地址https://github.com/niwinz/django-redis 。

下载:pip install django-redis

设置:

CACHES = {
 "default": {
  "BACKEND": "django_redis.cache.RedisCache",
  "LOCATION": "redis://127.0.0.1:6379/1",
  "OPTIONS": {
   "CLIENT_CLASS": "django_redis.client.DefaultClient",
  }
 }
}

Cache arguments

CACHES设置中有几个额外的参数:

TIMEOUT:缓存超时时间,默认为300s,可以设置为None,即永不超时。

OPTIONS : locmem, filesystem和database缓存系统这些有自己的剔除策略的系统有以下的参数:

MAX_ENTRIES : 缓存中存放的最大条目数,大于这个数时,旧的条目将会被删除,默认为300.

CULL_FREQUENCY:当达到MAX_ENTRIES的时候,被接受的访问的比率。实际的比率是1/cull_frequency,所以设置为2就是在达到max_entries时去除一半数量的缓存,设置为0意味着达到max_entries时,缓存将被清空。这个值默认是3。

KEY_PREFIX:一个会自动列入缓存key值的的字符串。

VERSION:缓存key值生成时使用的版本数字。

KEY_FUNCTION:key值最终生成所使用的方法。

缓存网站

要缓存整个网站,首先添加两个中间件:

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

注意update中间件要放在首位,fetch中间件放在最后。

在settings中添加以下值:

  • CACHE_MIDDLEWARE_ALIAS:存储用的缓存别名
  • 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()禁止缓存

缓存页面

使用django.views.decorators.cache.cache_page()来缓存某个页面:

from django.views.decorators.cache import cache_page
 
@cache_page(60 * 15)
def my_view(request):
 ...

60*15是缓存15分钟。

cache参数可以设置使用CACHES中的哪一个cache系统,默认是default:

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

key_prefix参数和CACHE_MIDDLEWARE_KEY_PREFIX设置起得作用相同:

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

可以在url中使用此方法:

from django.views.decorators.cache import cache_page
urlpatterns = [
 url(r'^foo/([0-9]{1,2})/$', cache_page(60 * 15)(my_view)),
]

模板片段缓存

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

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

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

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

CACHE API

根据CACHES设置中的cache别名获取cache系统:

>>> from django.core.cache import caches
>>> cache1 = caches['myalias']
>>> cache2 = caches['myalias']
>>> cache1 is cache2
True

获取默认default的cache:

>>> from django.core.cache import cache

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

>>> cache.set('my_key', 'hello, world!', 30)
>>> cache.get('my_key')
'hello, world!'

key为字符串,value为 picklable的python对象。timeout设置为None时,缓存永不过时,设置为0时不缓存。

设置Vary header

Django默认是使用url地址作为cache的key值的,也就是对相同的url请求会返回相同的缓存。如果想根据不同的请求首部字段(比如cookie, language, user-agent)缓存不同的内容,可以设置Vary首部字段。

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

上述代码会为不同的user-agent设置单独的缓存。也可以传多个headers:

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

上述代码当user-agent和cookie都相同时才会有相同的缓存。

cookie是比较常用的,有单独的装饰器,下面代码是相通的:

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

Cache-Control头部

可以使用cache_control装饰器来设定Cache-Control头部。

设置对特定的用户提供缓存服务:

from django.views.decorators.cache import cache_control
@cache_control(private=True)
def my_view(request):
 ...

设置时间:

from django.views.decorators.cache import cache_control
@cache_control(max_age=3600)
def my_view(request):
 ...

等等,可用的Cache-Control指令(IANA registry)都可使用。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python重新引入被覆盖的自带function
Jul 16 Python
Python脚本暴力破解栅栏密码
Oct 19 Python
Python编程实现删除VC临时文件及Debug目录的方法
Mar 22 Python
Python实现Pig Latin小游戏实例代码
Feb 02 Python
python3.X 抓取火车票信息【修正版】
Jun 19 Python
解决python3读取Python2存储的pickle文件问题
Oct 25 Python
pandas的to_datetime时间转换使用及学习心得
Aug 11 Python
关于阿里云oss获取sts凭证 app直传 python的实例
Aug 20 Python
python中的Elasticsearch操作汇总
Oct 30 Python
python有序查找算法 二分法实例解析
Feb 18 Python
Django配置跨域并开发测试接口
Nov 04 Python
python 实现控制鼠标键盘
Nov 27 Python
tensor和numpy的互相转换的实现示例
Aug 02 #Python
Django文件存储 自己定制存储系统解析
Aug 02 #Python
使用pycharm在本地开发并实时同步到服务器
Aug 02 #Python
Django文件存储 默认存储系统解析
Aug 02 #Python
Django 迁移、操作数据库的方法
Aug 02 #Python
Django用户认证系统 组与权限解析
Aug 02 #Python
python3中eval函数用法使用简介
Aug 02 #Python
You might like
《APMServ 5.1.2》使用图解
2006/10/23 PHP
dedecms系统常用术语汇总
2007/04/03 PHP
10个php函数实用却不常见
2015/10/13 PHP
thinkphp分页实现效果
2016/10/13 PHP
PHP数组基本用法与知识点总结
2020/06/02 PHP
Javascript创建自定义对象 创建Object实例添加属性和方法
2012/06/04 Javascript
在JavaScript中typeof的用途介绍
2013/04/11 Javascript
判断滚动条到底部的JS代码
2013/11/04 Javascript
js整数字符串转换为金额类型数据(示例代码)
2013/12/26 Javascript
JS中判断JSON数据是否存在某字段的方法
2014/03/07 Javascript
jQuery表格排序组件-tablesorter使用示例
2014/05/26 Javascript
JS实现兼容各种浏览器的获取选择文本的方法【测试可用】
2016/06/21 Javascript
分享jQuery封装好的一些常用操作
2016/07/28 Javascript
JS设置CSS样式的方式汇总
2017/01/21 Javascript
基于Vue的文字跑马灯组件(npm 组件包)
2017/05/24 Javascript
JS点击缩略图整屏居中放大图片效果
2017/07/04 Javascript
Vue项目数据动态过滤实践及实现思路
2018/09/11 Javascript
浅谈在vue中使用mint-ui swipe遇到的问题
2018/09/27 Javascript
vue-cli中使用高德地图的方法示例
2019/03/28 Javascript
基于JavaScript实现控制下拉列表
2020/05/08 Javascript
Openlayers绘制聚合标注
2020/09/28 Javascript
JavaScript常用进制转换及位运算实例解析
2020/10/14 Javascript
[03:14]DOTA2斧王 英雄基础教程
2013/11/26 DOTA
Python使用matplotlib和pandas实现的画图操作【经典示例】
2018/06/13 Python
python实现桌面托盘气泡提示
2019/07/29 Python
Python如何输出整数
2020/06/07 Python
TensorFlow保存TensorBoard图像操作
2020/06/23 Python
万得城电器土耳其网站:欧洲第一大电子产品零售商
2016/10/07 全球购物
意大利专业化妆品品牌:KIKO MILANO
2017/02/01 全球购物
Talbots官网:美国成熟女装品牌
2019/11/15 全球购物
戴尔马来西亚官网:Dell Malaysia
2020/05/02 全球购物
相亲活动方案
2014/08/26 职场文书
2014企业领导班子四风对照检查材料思想汇报
2014/09/17 职场文书
英语感谢信范文
2015/01/20 职场文书
碧霞祠导游词
2015/02/09 职场文书
SpringBoot中获取profile的方法详解
2022/04/08 Java/Android