一、服务器缓存策略
缓存定义:缓存是一类可以更快的读取数据的介质统称,也指其他可以加快数据读取的存储方式。一般用来存储临时数据,常用介质的是读取速度很快的内存
意义:视图渲染有一定的成本,数据库的频繁查询过高,所以对低频变动的页面可以考虑使用缓存技术,减少实际渲染次数,用户拿到响应的时间成本会更低
缓存利用场景:
(1)博客列表页
(2)电商商品详情页
场景特点:缓存的地方,数据变动频率较少
1、多种级别的缓存
(1)数据库级别的缓存
在Django中settings.py中进行配置,设置缓存
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
'LOCATION': 'my_cache_table',
'TIMEOUT': 300,
'OPTIONS': {
'MAX_ENTRIES': 300,
'CULL_FREQUENCY': 2,
}
}
}
(2)将数据缓存到服务器内存中
CACHE = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'LOCATION': 'unique-snowflake'
}
}
上面测试使用,一般内存级别的缓存可以使用内存级别用作缓存的数据库redis
(3)文件系统级的缓存
把缓存存到系统下的某个文件里,但是这种方式一般也不怎么使用
CACHE = {
'default': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': '/var/tmp/django_cache',
}
}
2、以数据库级缓存为例进行测试
(1)创建缓存表
在Django中的setttings.py文件中,添加配置,然后在项目目录执行
python3 managy.py createcachetable
然后在数据库可以查看到出来一个my_cache_table这张表
mysql> desc my_cache_table;
+
| Field | Type | Null | Key | Default | Extra |
+
| cache_key | varchar(255) | NO | PRI | NULL | |
| value | longtext | NO | | NULL | |
| expires | datetime(6) | NO | MUL | NULL | |
+
3 rows in set (0.01 sec)
mysql>
(2)Django中对缓存表的使用
使用cache_page函数,这个cache_page函数相当于在执行视图函数之前先看缓存里面有没有要查的数据,如果有直接读缓存,如果没有就继续往下走视图函数,视图函数走完,再往缓存里视图函数返回的数据
方式一:使用装饰器
from django.views.decorators.cache import cache_page
@cache_page(30)
def test_cache(request):
...
方式二:在路由中修改
from django.views.decorators.cache import cache_page
urlpatterns = [
path('foo/', cache_page(60)(test_cache)),
]
其实都是一样的
(3)测试缓存是否配置成功
那就修改视图函数test_cache如下
import time
from django.views.decorators.cache import cache_page
@cache_page(15)
def test_cache(request):
t = time.time()
return HttpResponse('time is %s' % t)
因为使用了缓存,按道理页面中的时间应该不是实时变化的,而是缓存中的,可以在页面中查看效果验证确实如此
3、数据库级缓存-局部缓存(缓存api)
(1)局部缓存的概念
之前的cache_page算是全局缓存,因为是放在视图函数前边,所以是把视图函数返回的数据全缓存,而且这种使用cache_page的方式往缓存里存放的缓存内容并不是键值对的方式进行存放的,也没有专门删除特定缓存的方法,除非缓存全删,所以cache_page这种方式的缓存虽然使用上很简单但是却有明显的缺点,因此还有局部缓存的方式
比如下面这个例子
from django.shortcuts import render
def index(request):
book_list = Book.objects.all()
...
return render(request, 'index.html', locals)
从上面代码可以看出来,最主要的可能耗时的是book_list这个列表查询,显然只缓存这个数据要比缓存整个视图函数的返回结果要好一点,甚至其他视图函数还可以使用这里缓存的book_list这份数据,复用性也强了,那么Django中可以使用缓存api的方式来进行局部缓存
先引入cache对象
方式一:使用caches[‘CACHES配置项中的key’]导入具体对象
from django.core.cache import caches
cache1 = caches['myalias']
cache2 = caches['myalias_2']
方式二:直接引入CACHES配置项中的’default’项
from django.core.cache import cache
上面不管哪种方式,操作缓存时都是操作缓存对象,使用第二种方式走默认default配置时,缓存对象名字叫cache
(2)缓存api的使用
1、存储缓存
使用cache.set(key, value, timeout)来进行缓存
key为缓存的key,value为python对象,timeout为缓存的存储时间(单位s秒),默认为CACHES中的TIMEOUT值,返回值为None
2、获取缓存
使用cache.get(key)来进行缓存的获取
key为缓存时保存使用的key,返回值为key的具体值,如果没有数据则返回None
3、存储缓存-在key不存在时生效
使用cache.add(key, value)进行缓存的存储,只在key不存在时才生效
如果存储成功,返回值为True,如果失败返回值为False
4、若未获取到数据则执行set
使用cache.get_or_set(key, value, timeout)方法来获取数据,如果没有找到数据,则执行set操作来缓存数据
返回值为value
5、批量存储缓存
使用cache.set_many(dict, timeout)方法来批量缓存
dict为key和value的字典,timeout为存储时间(s),返回值为插入不成功的key的数组
因此这样就可以控制缓存中的每一份数据了,在视图函数中,在想要查询某些低频数据时,可以先判断,用cache.get看一下缓存里是否有数据,有则从缓存取出,如果没有则正常走视图函数中的查询语句,查出来的结果再使用cache.set缓存一份数据
二、浏览器缓存策略
因为数据通过网络传输也是需要时间的,那么对用重复请求的数据,在浏览器中也可以进行缓存,缓存在客户端而不是服务器
浏览器
浏览器缓存
服务器
第一次发起HTTP请求
没有该请求的缓存结果和缓存标识
发起HTTP请求
返回该请求结果和缓存规则
将该请求结果和缓存标识存入浏览器缓存中
浏览器
浏览器缓存
服务器
浏览器缓存有两大类,一个强缓存,一个协商缓存
1、强缓存
不会向服务器发送请求,直接从缓存中读取数据
(1)响应头-Expires
定义:缓存过期时间,用来制定资源到期的时间,是服务器端的具体的时间点
样例:Expires:Thu, 02 Apr 2030 05:14:08 GMT
(2)响应头-Cache-Control
在HTTP/1.1中,Cache-Control主要用于控制网页缓存。比如当Cache-Control:max-age=120 代表请求创建时间后的120秒,缓存失效
说明:目前服务器都会带着这两个头同时响应给浏览器,浏览器优先使用Cache-Control
使用了cache_page之后,会自动发送缓存时间到浏览器端
2、协商缓存
强缓存中的数据一旦过期,还需要跟服务器进行通信,从而获取最新数据,如果强缓存的数据是一些静态文件、大的图片呢?
考虑到大图片这类比较费带宽且不易变化的数据,强缓存时间到期后,浏览器会去跟服务器协商,当前缓存是否可用,如果可用,服务器不必返回数据,浏览器继续使用原来缓存的数据,如果文件不可用,则返回最新数据
如果要使用协商缓存这个策略,那么需要使用Last-Mofified响应头和If-Modified-Since请求头
(1)Last-Modified
Last-Modified为文件的最近修改时间,浏览器第一次请求静态文件时,服务器如果返回Last-Modified响应头,则代表该资源为需协商的缓存
当缓存到期后,浏览器将获取到的Last-Modified值作为请求头If-Modified-Since的值,与服务器发请求协商,服务器返回304响应码[响应体为空],代表缓存继续使用,200响应码代表缓存不可用[响应体为最新资源]
也就是说,协商缓存是在强缓存的基础上多了一个Last-Modified头,会在缓存到期了之后,会跟服务器先商量一下,根据商量的结果来看缓存该怎么处理,Last_modified其实不是最好的方式,后来又有了新的浏览器缓存方式,使用Etag和If-None-Match
(2)Etag
之所以Last-Modified这种方式不太好,是因为其判断文件是否存在的单位标准是秒,但有时候一秒内就有多个文件发生变化
Etag是服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成,比如利用哈希值),只要资源有变化,Etag就会重新生成
缓存到期后,浏览器将Etag响应头的值作为If-None-Match请求头的值,给服务器发请求协商,服务器接到请求头后,对比文件标识,不一致则认为资源不可用,返回200响应码[响应体为最新资源],可用则返回304响应码
|