cache 的使用及配置详情
cache缓存定义
缓存是一类可以更快的读取数据的介质统称, 也指其他可以加快数据读取的存储方式, 一般用来存储临时数据, 常用介质的是读取速度很快的内存, 一般来说从数据库多次吧所需要的的数据提取出来, 要比从内存或者硬盘等一次读出来付出的成本大很多, 对于中大型网站而言, 使用缓存减少对数据库的访问次数是提升网站性能的关键之一
为什么使用缓存cache
在Django中, 当用户请求到达视图后, 视图会先从数据库提取数据放到模板中进行动态渲染, 渲染到的结果就是用户看到的网页, 如果用户每次请求都从数据库提取数据并渲染, 将极大降低性能, 不仅服务器压力大, 而且客户端也无法及时获得相应, 如果能将渲染后的结果放到速度更快的缓存中, 每次有请求过来, 先检查缓存中是否有对应的资源, 如果有, 直接从缓存中取出来返回响应, 节省取数据和渲染的时间, 不仅能大大提高系统性能, 还能提高用户体验
例:
每当我们访问首页时, 下面视图都会从数据库中提取文章列表, 并渲染到模板里去, 大多数情况下, 我们的博客不会更新的那么频繁, 所以文章列表是不会变的, 这样用户在一定时间内多次访问首页时都从数据库重新读取同样的数据是一种极大的浪费
from django.shortcuts import render
def index(request):
# 读取数据库并渲染到网页
article_list = Article.object.all()
return render(request, 'index.html', {'article_list': article_list})
使用缓存cache就可以帮我们解决这个问题, 当用户首次访问博客首页时, 我们从数据库中提取文章列表, 并将其存储到缓存里(常用的内存, 这取决于你的设置), 当用户在单位时间内再次访问首页时, Django先检查缓存是否过期(本例时15分钟), 再检查缓存里文章列表资源是否存在, 如果存在, 直接从缓存中读取数据, 并渲染模板
from django.shortcuts import render
from django.views.decotators.cache import cache_page
@cache_page(60 * 15) # 秒数, 表示缓存15分钟, 不直接写900是为了更好的可读性
def index(request):
article_list = Article.object.all()
return render(request, 'index.html', {'article_list': article_list})
缓存cache的应用场景
缓存只要适用于对于页面实时性要求不高的页面, 存放在缓存的数据, 通常是频繁访问而不会修改的数据, 例如:
- 博客文章, 假设用户一天更新一篇文章, 那么可以为博客设置一天的缓存, 一天后会刷新
- 购物网站, 商品的描述信息基本不会变化, 而商品的购买数量需要根据用户情况实时更新, 我们可以只选择缓存商品描述信息
- 缓存网页片段, 比如缓存网页导航菜单和脚部(Footer)
Django缓存设置
Django中提供了多种缓存方式, 如果要使用缓存, 需要先在settings.py中进行配置, 然后应用, 根据缓存介质的不同, 你需要设置不同的缓存后台Backend
Memcached缓存
Memcached是基于内存的缓存, django原生支持的最快最有效的缓存系统, 对于大多数应用场景, 推荐使用Memcached, 数据缓存在服务器端, 使用前需要通过pip安装memcached的插件python-memcached和pylibmc, 可以同时支持多个服务器上边的mecached
使用python-memcached的设置
# localhost
CACHE = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
}
}
# unix soket
CACHE = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': 'unix:/tmp/memcached.scok',
}
}
CACHES = {
'default': {
'BACKEND': 'dajngo.core.cache.backends.memcached.MemcachedCache',
'LOCATION': [
'172.19.26.240:11211',
'172.19.26.242:11211',
]
# 我们也可以给缓存机器加权重, 权重高的承担更多的请求, 如下
'LOCATION': [
('172.19.26.240:11211', 5),
('172.19.26.242:11211', 1),
]
}
}
数据库缓存
CACHE = {
'default': {
'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
'LOCATION': 'my_cache_table',
}
}
LOCAL 为数据库中table的名字, 在数据库中未被使用国际客
创建cache table:
python manage.py createcachetable
文件系统缓存
CACHE = {
'default': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': '/var/tmp/django_cache', # 文件夹的路径
# 'LOCATION': 'c:\foo\bar', # windows下的示例
}
}
本地内存缓存
CACHE = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'LOCATION': 'unique-snowflake',
}
}
django代码中如何使用cache
在做好cache的设置后, 在代码中有三种方式使用cache
- 在视图view中使用
- 在路由URLConf中使用
- 在模板中使用
在视图view中使用cache
from django.views.decorators.cache import cache_page
@cache_page(60 * 15)
def my_view(request):
...
在路由URLConf中使用cache, 不用修改负责逻辑部分的view
from django.views.decorators.cache import cache_page
urlpatterns = [
path('foo/<int:code>/', cache_page(60 * 15)(my_view)),
]
在模板中使用cache
{% load cache %}
{% cache 500 sidebar request.user.username %}
..sidebar for logged in user..
{% endcache %}
Django中使用cache的高级技巧
使用cache_control
通常用户将会面对两种缓存: 他或他自己的浏览器缓存(私有缓存)以及他或她的提供者缓存(公共缓存), 公共缓存由多个用户使用, 而受其他人的控制, 这就产生了敏感数据的问题, 比如银行账号被存储在公共缓存中, 因此web应用程序需要以某种方式告诉缓存那些数据是私有的, 哪些是公共的
解决方案就是标示初某个页面缓存应当是私有的, 要在django中完成此项目, 可使用cache_control 视图装饰器
from django.views.decorators.cache import cache_control
@cache_control(privite=True)
def my_view(request):
...
该装饰器负责在后台发送相应的HTTP头部
还有一些其他方法可以控制缓存参数, 例如HTTP允许应用程序执行如下操作
- 定义页面可以被缓存的最大时间
- 指定某个缓存是否总是检查较新版本, 仅当无更新是才传递所缓存内容
在django中, 可使用cache_control视图修饰器指定这些缓存参数, 在下例中,cache_control告诉缓存对每次访问都重新验证缓存并在最长3600秒内保存所缓存版本
from django.views.decorators.cache import cachecontrol
@cache_control(must_revalidate=True, max_age=3600)
def my_view(request):
...
在cache_control()
中, 任何合法的Cache-Control
HTTP指令都是有效的, 下面是完整列表
public=True
表明响应可以被任何对象(包括:发送请求的客户端,代理服务器,等等)缓存,即使是通常不可缓存的内容。(例如:1.该响应没有max-age
指令或Expires
消息头;2. 该响应对应的请求方法是 POST )
private=True
表明响应只能被单个用户缓存,不能作为共享缓存(即代理服务器不能缓存它)。私有缓存可以缓存响应内容,比如:对应用户的本地浏览器
no_cache=True
在发布缓存副本之前,强制要求缓存把请求提交给原始服务器进行验证(协商缓存验证)
no_transfrom=True
不得对资源进行转换或转变, Content-Encoding
、Content-Range
、Content-Type
等HTTP头不能由代理修改, 例如,非透明代理或者如Google’s Light Mode可能对图像格式进行转换,以便节省缓存空间或者减少缓慢链路上的流量,no-transform
指令不允许这样做
must_revalidata=True
一旦资源过期(比如已经超过max-age
),在成功向原始服务器验证之前,缓存不能用该资源响应后续请求
proxy_revalidate=True
与must-revalidate作用相同,但它仅适用于共享缓存(例如代理),并被私有缓存忽略
max_age=num_seconds
设置缓存存储的最大周期,超过这个时间缓存被认为过期(单位秒)。与Expires
相反,时间是相对于请求的时间
s_maxage=num_seconds
覆盖max-age
或者Expires
头,但是仅适用于共享缓存(比如各个代理),私有缓存会忽略它
使用vary_on_headers
缺省情况下, django的缓存系统使用所请求的路径(如blog/article/1)来创建其缓存, 这意味着不同用户请求同样路径都会得到同样的缓存版本, 不考虑客户端user-agent, cookie和语言配置的不同, 除非你使用Vary头部通知缓存机制需要考虑请求头里的cookie和语言的不同
要在Django完成这项工作, 可使用便利的vary_on_headers视图装饰器, 例如下面代码告诉Django读取缓存数据时需要考虑user-agent和cookie的不同
from django.views.decorators.vary import vary_on_headers
@vary_on_headers('User-Agent', 'Cookie')
def my_view(request):
...
使用never_cache禁用缓存
如果你想用头部完全禁掉缓存, 你可以使用django.views.decorators.cache.never_cache装饰器, 如果不在视图中使用缓存, 服务器端肯定不会缓存的, 然而用户的客户端如浏览器还是会缓存一些数据, 这时可以用never_cache禁用掉客户端的缓存
from django.views.decorators.cache import never_cache
@never_cache
def my_view(request):
...
django缓存优缺点
优点: 把一些经常访问的页面放入缓存当中,请求来了,直接到缓存中拿数据
缺点: 缓存的数据不能实时更新