1. 程式人生 > >Django 快取 Cache

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)

3、關於django 快取官方文件

https://docs.djangoproject.com/en/2.1/topics/cache/