Django 快取 Cache
文章目錄
一、快取
快取(Cache)對於建立一個高效能的網站和提升使用者體驗來說是非常重要的,快取是一類可以更快的讀取資料的介質統稱,也指其它可以加快資料讀取的儲存方式。一般用來儲存臨時資料,常用介質的是讀取速度很快的記憶體。一般來說從資料庫多次把所需要的資料提取出來,要比從記憶體或者硬碟等一次讀出來付出的成本大很多。對於中大型網站而言,使用快取減少對資料庫的訪問次數是提升網站效能的關鍵之一
某些資料訪問很頻繁的場景下,通過快取的方式,可以減少對於資料庫的連線、查詢請求、頻寬等多個方面;同時也要注意的是快取的佔用空間,快取的失效時間
二、Django 快取應用場景
在Django中,當用戶傳送一個請求後,通過路由到達檢視函式views,當檢視函式需要通過template做資料渲染,那麼就會通過ORM進行資料庫查詢操作來獲取資料,然後再把資料返回給客戶端,也就是頁面。
如果每個使用者每次請求都需要完整的走一遍資料渲染的過程,將會極大的降低效能,不僅僅資料庫壓力大,並且客戶端也無法及時得到響應內容。
那麼這個時候,快取的使用場景就出現了,在Django中使用場景後,會是這樣
當用戶傳送一個請求後,如果有快取資料,則直接將快取資料返回給使用者,如果沒有,才會查詢資料庫,並且將查詢到的資料寫入到快取,然後將請求返回給客戶端,並且客戶端下次請求的時候會先訪問快取我資料
三、Django 快取的五種配置
0、通用配置(以redis為例)
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://10.55.75.20:6379/0",
'TIMEOUT': 1800, # 快取超時時間(預設300,None表示永不過期,0表示立即過期)
"OPTIONS": {
"MAX_ENTRIES": 300, # 最大快取個數(預設300)
"CULL_FREQUENCY": 3, # 快取到達最大個數之後,剔除快取個數的比例,即:1/CULL_FREQUENCY(預設3)
"CLIENT_CLASS": "django_redis.client.DefaultClient", # redis客戶端
"CONNECTION_POOL_KWARGS": {"max_connections": 1}, # redis最大連線池配置
"PASSWORD": "password", # redis密碼
},
'KEY_PREFIX': 'Cache', # 快取key的字首(預設空)
'VERSION': 2, # 快取key的版本(預設1)
},
}
1、開發除錯
CACHES = {
'default1': {
'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
},
}
2、將快取資訊儲存至檔案
CACHES = {
'default2': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': os.path.join(BASE_DIR, 'cache'),
},
}
3、將快取資訊儲存至記憶體
CACHES = {
'default3': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'LOCATION': 'unique-snowflake',
},
}
4、將快取資訊儲存至資料庫
(注:需執行建立表命令 python3 manage.py createcachetable))
CACHES = {
'default4': {
'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
'LOCATION': 'my_cache_table', # 資料庫表
},
}
5、將快取資訊儲存至memcache(python-memcached模組)
CACHES = {
'default5': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
},
'default6': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': 'unix:/tmp/memcached.sock',
},
'default7': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': [
'172.19.26.240:11211',
'172.19.26.242:11211',
]
},
# 我們也可以給快取機器加權重,權重高的承擔更多的請求,如下
'default8': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': [
('172.19.26.240:11211',5),
('172.19.26.242:11211',10),
]
},
}
6、將快取資訊儲存至memcache(pylibmc模組)
CACHES = {
'default9': {
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
'LOCATION': '127.0.0.1:11211',
},
'default10': {
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
'LOCATION': '/tmp/memcached.sock',
},
'default11': {
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
'LOCATION': [
'172.19.26.240:11211',
'172.19.26.242:11211',
]
},
'default12': {
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
'LOCATION': [
('172.19.26.240:11211',10),
('172.19.26.242:11211',10),
]
},
}
7、將快取資訊儲存至redis(django-redis模組)
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://10.55.75.20:6379/0",
"OPTIONS": {
"MAX_ENTRIES": 300,
"CULL_FREQUENCY": 3,
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"CONNECTION_POOL_KWARGS": {"max_connections": 1},
"PASSWORD": "password",
},
},
}
四、Django 快取的三種應用
1、 全站使用
全站使用需要以下兩個中介軟體
中介軟體最上層:django.middleware.cache.UpdateMiddleware
中介軟體最下層:django.middleware.cache.FetchFormCacheMiddleware
使用中介軟體,經過一系列的認證等操作,如果內容在快取中存在,則使用FetchFromCacheMiddleware獲取內容並返回給使用者,當返回給使用者之前,判斷快取中是否已經存在,如果不存在則UpdateCacheMiddleware會將快取儲存至快取,從而實現全站快取
在Django官方中指出:“更新”中介軟體必須是列表中的第一個,“獲取”中介軟體必須是最後一個。細節有點模糊,但如果你想要完整的故事,請參閱下面的MIDDLEWARE。
MIDDLEWARE = [
'django.middleware.cache.UpdateCacheMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.cache.FetchFromCacheMiddleware',
]
middleware關於快取的全域性變數
配置檔案位於當前專案中的路徑:venv/lib/python3.7/site-packages/django/conf/global_settings.py,建議通過settings.py 定義進行覆蓋
CACHE_MIDDLEWARE_KEY_PREFIX = 'champzee' # 表示全域性快取的prefix
CACHE_MIDDLEWARE_SECONDS = 600 # 表示全域性快取的過期時間
CACHE_MIDDLEWARE_ALIAS = 'default' # 表示全域性快取使用的CACHES配置
CACHES配置
配置檔案位於當前專案中的路徑:venv/lib/python3.7/site-packages/django/conf/global_settings.py,建議通過settings.py 定義進行覆蓋
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://10.55.75.20:6379/0",
'TIMEOUT': 1800,
"OPTIONS": {
"MAX_ENTRIES": 300,
"CULL_FREQUENCY": 3,
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"CONNECTION_POOL_KWARGS": {"max_connections": 100},
"PASSWORD": "password",
},
'KEY_PREFIX': 'Cache',
'VERSION': 2,
},
}
檢視函式
def cache1(request):
import time
ctime = time.strftime("%Y-%m-%d %H:%M:%S")
return render(request, 'cache1.html', {'ctime': ctime})
def cache2(request):
import time
ctime = time.strftime("%Y-%m-%d %H:%M:%S")
return render(request, 'cache2.html', {'ctime': ctime})
template模版(cache1和cache2模版)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{{ ctime }} <br />
{{ ctime }} <br />
{{ ctime }}
</body>
</html>
當我配置好了全域性快取中介軟體,CACHES redis配置,檢視函式,模板之後;下面我發起一個請求,我們通過請求來檢視redis是否生成快取,並且檢視快取有效期是否為600秒
curl http://127.0.0.1:8000/wanglei/cache1
curl http://127.0.0.1:8000/wanglei/cache2
可以看到如下內容,接著我們檢視redis
2、檢視使用
在檢視使用中,我們就不需要配置middleware了,並且關於應用場景優先順序第五小節會提到
CACHES配置
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://10.55.75.20:6379/0",
'TIMEOUT': 1800,
"OPTIONS": {
"MAX_ENTRIES": 300,
"CULL_FREQUENCY": 3,
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"CONNECTION_POOL_KWARGS": {"max_connections": 100},
"PASSWORD": "password",
},
'KEY_PREFIX': 'Cache',
'VERSION': 2,
},
}
檢視函式
在檢視函式中,cache_page需要引入,並且支援的三個引數為:快取的失效時間,使用的CACHES的配置,key的字首
from django.views.decorators.cache import cache_page
@cache_page(timeout=120, cache='default', key_prefix='page3')
def cache3(request):
import time
ctime = time.strftime("%Y-%m-%d %H:%M:%S")
return render(request, 'cache3.html', {'ctime': ctime})
@cache_page(timeout=240, cache='default', key_prefix='page4')
def cache4(request):
import time
ctime = time.strftime("%Y-%m-%d %H:%M:%S")
return render(request, 'cache4.html', {'ctime': ctime})
template模版(cache3和cache4)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{{ ctime }} <br />
{{ ctime }} <br />
{{ ctime }}
</body>
</html>
當我配置好了 CACHES redis配置,檢視函式,模板之後;下面我發起一個請求,我們通過請求來檢視redis是否生成快取,並且檢視快取有效期是否為120和240秒(這裡說明一下,我把全域性步驟中的部分session快取進行了清理,所以生成的只有我們區域性檢視中的快取)
curl http://127.0.0.1:8000/wanglei/cache3
curl http://127.0.0.1:8000/wanglei/cache4
3、區域性使用
只配置template即可(cache),需要先load cache
{% load cache %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% cache 600 ctime_key1 %}
{{ ctime }} <br />
{% endcache %}
{% cache 300 ctime_ket2 %}
{{ ctime }} <br />
{% endcache %}
{{ ctime }} <br />
</body>
</html>
下面我將訪問區域性cache
curl http://127.0.0.1:8000/wanglei/cache
我們可以看到,間隔一秒的訪問,第一次三個ctime都是一樣的;而當我第二次訪問的時候,前兩個資料使用區域性快取,而第三個資料獲取到的是當前的時間
在redis中,我們可以看到使用者訪問生成了兩條快取,第一條key_prefix為ctime_key1,並且ttl時間為600;第二條key_prefix為ctime_key2,並且ttl時間為300秒
五、Django 快取結論
1、關於優先順序
全站配置 > 檢視配置 > 區域性配置
2、關於快取名稱的生成規則
快取檔案的名稱生成方法位於當前專案下原始碼配置 venv/lib/python3.7/site-packages/django/core/cache/backends/base.py 中,裡面定義了default_key_func方法;其實我們定義的全域性變數就是傳給它,然後它會生成一個統一的cache名稱,存入CACHE配置中的快取地址中
def default_key_func(key, key_prefix, version):
"""
Default function to generate keys.
Construct the key used by all other methods. By default, prepend
the `key_prefix'. KEY_FUNCTION can be used to specify an alternate
function with custom key making behavior.
"""
print('%s:%s:%s' % (key_prefix, version, key))
#return '%s:%s' % (key_prefix, version)
return '%s:%s:%s' % (key_prefix, version, key)