Django 缓存 Cache

Posted 亦非我所愿丶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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/

以上是关于Django 缓存 Cache的主要内容,如果未能解决你的问题,请参考以下文章

Django 基础实践:cache缓存--上篇

Django Cache缓存系统

Cache._cache.flush_all () 不工作,如何使用 django 和 memcached 清除缓存?

django-redis-cache 和 django-redis 用于使用 Django 进行 redis 缓存的区别?

django-缓存

Django缓存系统设置