缓存主要用来加速慢存储的访问效率,减少对数据库的操作,提升页面访问速度。

一、CentOS 安装 Redis

yum install epel-releas # 添加 EPEL 仓库
yum update  # 更新 yum 源

yum -y install redis
systemctl start redis   # 启动 redis 服务

配置可远程连接 Redis

修改配置文件:/etc/redis.conf

# 找到 `bind 127.0.0.1`,注释掉这一行

# 将 protected-mode 修改为 no
protected-mode no

# 保存重启 `redis` 服务
systemctl restart redis

二、Django 中缓存设置

Django 支持的缓存机制

Django 中可以配置多种缓存源,支持的缓存设置有:

  • 内存缓存
  • 文件缓存
  • 数据库缓存
  • memcached 缓存
  • redis 缓存

内存缓存

local-memory-caching,线程安全的,进程间独立,即每个进程一份缓存,Django 默认配置,配置示例如下:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
        'LOCATION': 'unique-snowflake',
    }
}

文件缓存

filesystem caching,将数据缓存到文件系统中,配置示例如下:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.filebackend.FileBaseCache',
        'LOCATION': '/var/tmp/django_cache',
    }
}

数据库缓存

database caching,需要创建缓存用的表,意义不大,不推荐使用,配置示例如下:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.db.DataaseCache',
        'LOCATION': 'my_cache_table',
    }
}

memcached

Django 推荐的缓存系统,也是分布式的(分布式逻辑在客户端),Django 内置支持,集成度比较好,配置示例如下:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': [
            '172.19.26.240:11211',
            '172.19.26.242.11211',
        ],
    }
}

redis 缓存

使用 redis 缓存有两种思路:

  • Django 模块:django-redisdjango-redis-cache
  • 直接使用 Redis 包操作 Redis,不使用 Django 模块,缺点是无法使用内置缓存模块的接口,不推荐

配置 redis 缓存

安装

pip install django-redis==4.9.0
pip install hiredis

默认安装的 redis 是最新版,使用缓存时可能会报错:redis.exceptions.DataError: Invalid input of type: 'CacheKey'.,可将版本降为 2.10.6

pip install redis==2.10.6

hiredis 的作用是提升 redis 解析性能,具体测试结果可在 https://github.com/redis/hiredis-py#benchmarks


配置

配置 Projects/settings.py

# Redis 缓存

REDIS_URL = 'redis://192.168.131.131:6379/1'

CACHES = {
    'default': {
        'BACKEND': 'django_redis.cache.RedisCache',
        'LOCATION': REDIS_URL,
        'TIMEOUT': 300,
        'OPTIONS': {
            'CLIENT_CLASS': 'django_redis.client.DefaultClient',
            'PASSWORD_CLASS': 'redis.connection.HiredisParser',
        },
        'CONNECTION_POOL_CLASS': 'redis.connection.BlockingConnectionPool',
    }
}

应用场景和缓存粒度

使用缓存首先要知道在哪缓存、缓存什么,即使用场景,千万不要以为缓存一定能优化访问效率,一定要先知道项目的业务特点。

Django 提供的各种粒度的缓存方案:

  • 整站缓存:配置中间件即可,不推荐
  • 整个页面缓存
  • 局部数据缓存

整站缓存

配置 settings 中间件:

MIDDLEWARE = [ 
# 站点缓存 , 注意必须在第一个位置 
'django.middleware.cache.UpdateCacheMiddleware', 
... 
# 站点缓存, 注意必须在最后一个位置 
'django.middleware.cache.FetchFromCacheMiddleware',
 ]

若内容在缓存中存在,则使用 FetchFromCacheMiddleware 获取内容并返回,在返回之前,判断缓存中是否已存在,若不存在则 UpdateCacheMiddleware 会将缓存保存至缓存,从而实现全站缓存。

单页面缓存

from django.shortcuts import render, HttpResponse
import time
from django.views.decorators.cache import cache_page

  
@cache_page(60 * 15)
def index(request):
    ctime = str(time.time())
    return render('index.html', locals())

局部数据缓存

class BookListView(View):
    """书籍列表"""

    def get(self, request):
        res = {"code": 0, "msg": "查询成功", "data": []}

        book_list = cache.get('book_list')
        if not book_list:
            book_list = models.Book.objects.all()
            cache.set('book_list', book_list, 10 * 60)

        res["data"] = json.loads(serializers.serialize("json", book_list))

        return JsonResponse(res)

首先从缓存中获取数据,若不存在则从数据库取出,并放入缓存中,以便下次使用。

URLconf 中使用缓存

场景:多个 URL 指向同一视图函数,但只想缓存一部分 URL

from django.views.decorators.cache import cache _page
urlpatterns = [
    url(r'^foo/([0-9]{1,2})/$',cache_page(60 * 15)(index)),
    url(r'^$', cache_page(60 * 30)(IndexView.as_view()), name='order'),
    ]

URL 缓存缓存的也是整个页面,需要考虑是否整个页面都应该缓存。

模板页面(局部页面)缓存

模板中使用缓存时比较推荐的一种方式,可以充分利用缓存粒度,可保证只缓存那些适合缓存的 HTML 片段:

{% load cache %}
<!DOCTYPE HTML>
<html>
<head>
    <meta charset="UTF-8">
    <title>Myblog</title>
</head>
<body>
    <h2>测试redis</h2>
    <div><p>非缓存地段</p></div>
 
    {% cache 10 aabbcc %}
    <div><p>这里缓存</p></div>
    {% endcache %}
     
</body>

测试缓存

在配置好后,应用之前可以先用 Django shell 测试是否能够成功:

python manage.py shell

from django.core.cache import cache

cache.set('book_list', '流畅的 Python', 60 * 60)
cache.has_key('book_list')
cache.get('book_list)

缓存使用原则

  • 静态页面
  • 不经常变动的页面或数据,实时性不高的数据,如文章热门排行榜等
  • 不建议缓存整个页面,因为页面会经常变动,但是可以缓存侧边栏,侧边栏不经常变动
  • 复杂逻辑生成的 HTML 片段,使用缓存可以减少多次重复操作

参考文章