缓存

由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存,缓存将一个某个views的返回值保存至内存或者memcache中,5分钟内再有人来访问时,则不再去执行view中的操作,而是直接从内存或者Redis中之前缓存的内容拿到,并返回。

Django中提供了6种缓存方式:

  • 开发调试
  • 内存
  • 文件
  • 数据库
  • Memcache缓存(python-memcached模块)
  • Memcache缓存(pylibmc模块)

1、配置

a、开发调试

python缓存数据库 python 缓存库_缓存

python缓存数据库 python 缓存库_数据库_02

1 # 此为开始调试用,实际内部不做任何操作
 2     # 配置:
 3         CACHES = {
 4             'default': {
 5                 'BACKEND': 'django.core.cache.backends.dummy.DummyCache',     # 引擎
 6                 'TIMEOUT': 300,                                               # 缓存超时时间(默认300,None表示永不过期,0表示立即过期)
 7                 'OPTIONS':{
 8                     'MAX_ENTRIES': 300,                                       # 最大缓存个数(默认300)
 9                     'CULL_FREQUENCY': 3,                                      # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
10                 },
11                 'KEY_PREFIX': '',                                             # 缓存key的前缀(默认空)
12                 'VERSION': 1,                                                 # 缓存key的版本(默认1)
13                 'KEY_FUNCTION' 函数名                                          # 生成key的函数(默认函数会生成为:【前缀:版本:key】)
14             }
15         }
16 
17 
18     # 自定义key
19     def default_key_func(key, key_prefix, version):
20         """
21         Default function to generate keys.
22 
23         Constructs the key used by all other methods. By default it prepends
24         the `key_prefix'. KEY_FUNCTION can be used to specify an alternate
25         function with custom key making behavior.
26         """
27         return '%s:%s:%s' % (key_prefix, version, key)
28 
29     def get_key_func(key_func):
30         """
31         Function to decide which key function to use.
32 
33         Defaults to ``default_key_func``.
34         """
35         if key_func is not None:
36             if callable(key_func):
37                 return key_func
38             else:
39                 return import_string(key_func)
40         return default_key_func


View Code


b、内存

python缓存数据库 python 缓存库_缓存

python缓存数据库 python 缓存库_数据库_02

1 # 此缓存将内容保存至内存的变量中
 2     # 配置:
 3         CACHES = {
 4             'default': {
 5                 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
 6                 'LOCATION': 'unique-snowflake',
 7             }
 8         }
 9 
10     # 注:其他配置同开发调试版本


View Code


c、文件

python缓存数据库 python 缓存库_缓存

python缓存数据库 python 缓存库_数据库_02

1 # 此缓存将内容保存至文件
 2     # 配置:
 3 
 4         CACHES = {
 5             'default': {
 6                 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
 7                 'LOCATION': '/var/tmp/django_cache',
 8             }
 9         }
10     # 注:其他配置同开发调试版本


View Code


d、数据库

python缓存数据库 python 缓存库_缓存

python缓存数据库 python 缓存库_数据库_02

1 # 此缓存将内容保存至数据库
 2 
 3     # 配置:
 4         CACHES = {
 5             'default': {
 6                 'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
 7                 'LOCATION': 'my_cache_table', # 数据库表
 8             }
 9         }
10 
11     # 注:执行创建表命令 python manage.py createcachetable


View Code


e、Memcache缓存(python-memcached模块)


python缓存数据库 python 缓存库_数据库_02

1 # 此缓存使用python-memcached模块连接memcache
 2 
 3     CACHES = {
 4         'default': {
 5             'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
 6             'LOCATION': '127.0.0.1:11211',
 7         }
 8     }
 9 
10     CACHES = {
11         'default': {
12             'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
13             'LOCATION': 'unix:/tmp/memcached.sock',
14         }
15     }   
16 
17     CACHES = {
18         'default': {
19             'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
20             'LOCATION': [
21                 '172.19.26.240:11211',
22                 '172.19.26.242:11211',
23             ]
24         }
25     }


View Code


f、Memcache缓存(pylibmc模块)

python缓存数据库 python 缓存库_缓存

python缓存数据库 python 缓存库_数据库_02

1 # 此缓存使用pylibmc模块连接memcache
 2     
 3     CACHES = {
 4         'default': {
 5             'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
 6             'LOCATION': '127.0.0.1:11211',
 7         }
 8     }
 9 
10     CACHES = {
11         'default': {
12             'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
13             'LOCATION': '/tmp/memcached.sock',
14         }
15     }   
16 
17     CACHES = {
18         'default': {
19             'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
20             'LOCATION': [
21                 '172.19.26.240:11211',
22                 '172.19.26.242:11211',
23             ]
24         }
25     }


View Code


g. Redis缓存(依赖:pip3 install django-redis)

python缓存数据库 python 缓存库_缓存

python缓存数据库 python 缓存库_数据库_02

1 CACHES = {
 2     "default": {
 3         "BACKEND": "django_redis.cache.RedisCache",
 4         "LOCATION": "redis://127.0.0.1:6379",
 5         "OPTIONS": {
 6             "CLIENT_CLASS": "django_redis.client.DefaultClient",
 7             "CONNECTION_POOL_KWARGS": {"max_connections": 100}
 8             # "PASSWORD": "密码",
 9         }
10     }
11 }


View Code

python缓存数据库 python 缓存库_数据库_02

from django_redis import get_redis_connection
conn = get_redis_connection("default")


视图中链接并操作


2、应用

a. 全站使用

python缓存数据库 python 缓存库_数据库_02

1 使用中间件,经过一系列的认证等操作,如果内容在缓存中存在,则使用FetchFromCacheMiddleware获取内容并返回给用户,当返回给用户之前,判断缓存中是否已经存在,如果不存在则UpdateCacheMiddleware会将缓存保存至缓存,从而实现全站缓存
 2 
 3     MIDDLEWARE = [
 4         'django.middleware.cache.UpdateCacheMiddleware',
 5         # 其他中间件...
 6         'django.middleware.cache.FetchFromCacheMiddleware',
 7     ]
 8 
 9     CACHE_MIDDLEWARE_ALIAS = ""
10     CACHE_MIDDLEWARE_SECONDS = ""
11     CACHE_MIDDLEWARE_KEY_PREFIX = ""


View Code


b. 单独视图缓存

python缓存数据库 python 缓存库_缓存

python缓存数据库 python 缓存库_数据库_02

1 方式一:
 2         from django.views.decorators.cache import cache_page
 3 
 4         @cache_page(60 * 15)
 5         def my_view(request):
 6             ...
 7 
 8     方式二:
 9         from django.views.decorators.cache import cache_page
10 
11         urlpatterns = [
12             url(r'^foo/([0-9]{1,2})/$', cache_page(60 * 15)(my_view)),
13         ]


View Code


c、局部视图使用

python缓存数据库 python 缓存库_数据库_02

1 a. 引入TemplateTag
2 
3         {% load cache %}
4 
5     b. 使用缓存
6 
7         {% cache 5000 缓存key %}
8             缓存内容
9         {% endcache %}


View Code


更多:猛击这里

 

Memcached

Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态、数据库驱动网站的速度。Memcached基于一个存储键/值对的hashmap。其守护进程(daemon )是用C写的,但是客户端可以用任何语言来编写,并通过memcached协议与守护进程通信。

Memcached安装和基本使用

Memcached安装:

wget http:           /           /           memcached.org           /           latest          


           tar            -           zxvf memcached           -           1.x           .x.tar.gz          


           cd memcached           -           1.x           .x          


           .           /           configure && make && make test && sudo make install          


                      


           PS:依赖libevent          


                      yum install libevent           -           devel          


                      apt           -           get install libevent           -           dev




启动Memcached

memcached            -           d            -           m            10               -           u root            -           l            10.211           .           55.4            -           p            12000            -           c            256            -           P            /           tmp           /           memcached.pid          


                      


           参数说明:          


                      -           d 是启动一个守护进程          


                      -           m 是分配给Memcache使用的内存数量,单位是MB          


                      -           u 是运行Memcache的用户          


                      -           l 是监听的服务器IP地址          


                      -           p 是设置Memcache监听的端口,最好是           1024           以上的端口          


                      -           c 选项是最大运行的并发连接数,默认是           1024           ,按照你服务器的负载量来设定          


                      -           P 是设置保存Memcache的pid文件



Memcached命令

存储命令:            set           /           add           /           replace           /           append           /           prepend           /           cas          


           获取命令: get           /           gets          


           其他命令: delete           /           stats..



Python操作Memcached

安装API

python操作Memcached使用Python           -           memcached模块          


           下载安装:https:           /           /           pypi.python.org           /           pypi           /           python           -           memcached



1、第一次操作


import            memcache          


                      


           mc            =            memcache.Client([           '10.211.55.4:12000'           ], debug           =           True           )          


           mc.           set           (           "foo"           ,            "bar"           )          


           ret            =            mc.get(           'foo'           )          


           print            ret




Ps:debug = True 表示运行出现错误时,现实错误信息,上线后移除该参数。

2、天生支持集群

python-memcached模块原生支持集群操作,其原理是在内存维护一个主机列表,且集群中主机的权重值和主机在列表中重复出现的次数成正比

主机    权重          


                      1.1           .           1.1              1          


                      1.1           .           1.2              2          


                      1.1           .           1.3              1          


                      


           那么在内存中主机列表为:          


                      host_list            =            [           "1.1.1.1"           ,            "1.1.1.2"           ,            "1.1.1.2"           ,            "1.1.1.3"           , ]



如果用户根据如果要在内存中创建一个键值对(如:k1 = "v1"),那么要执行一下步骤:

  • 根据算法将 k1 转换成一个数字
  • 将数字和主机列表长度求余数,得到一个值 N( 0 <= N < 列表长度 )
  • 在主机列表中根据 第2步得到的值为索引获取主机,例如:host_list[N]
  • 连接 将第3步中获取的主机,将 k1 = "v1" 放置在该服务器的内存中

代码实现如下:


mc            =            memcache.Client([(           '1.1.1.1:12000'           ,            1           ), (           '1.1.1.2:12000'           ,            2           ), (           '1.1.1.3:12000'           ,            1           )], debug           =           True           )          


                      


           mc.           set           (           'k1'           ,            'v1'           )




3、add
添加一条键值对,如果已经存在的 key,重复执行add操作异常


#!/usr/bin/env python          


           # -*- coding:utf-8 -*-          


           import            memcache          


                      


           mc            =            memcache.Client([           '10.211.55.4:12000'           ], debug           =           True           )          


           mc.add(           'k1'           ,            'v1'           )          


           # mc.add('k1', 'v2') # 报错,对已经存在的key重复添加,失败!!!




4、replace
replace 修改某个key的值,如果key不存在,则异常

#!/usr/bin/env python          


           # -*- coding:utf-8 -*-          


           import            memcache          


                      


           mc            =            memcache.Client([           '10.211.55.4:12000'           ], debug           =           True           )          


           # 如果memcache中存在kkkk,则替换成功,否则一场          


           mc.replace(           'kkkk'           ,           '999'           )




5、set 和 set_multi

set            设置一个键值对,如果key不存在,则创建,如果key存在,则修改
set_multi   设置多个键值对,如果key不存在,则创建,如果key存在,则修改

#!/usr/bin/env python          


           # -*- coding:utf-8 -*-          


           import            memcache          


                      


           mc            =            memcache.Client([           '10.211.55.4:12000'           ], debug           =           True           )          


                      


           mc.           set           (           'key0'           ,            'wupeiqi'           )          


                      


           mc.set_multi({           'key1'           :            'val1'           ,            'key2'           :            'val2'           })



6、delete 和 delete_multi

delete             在Memcached中删除指定的一个键值对
delete_multi    在Memcached中删除指定的多个键值对

#!/usr/bin/env python          


           # -*- coding:utf-8 -*-          


           import            memcache          


                      


           mc            =            memcache.Client([           '10.211.55.4:12000'           ], debug           =           True           )          


                      


           mc.delete(           'key0'           )          


           mc.delete_multi([           'key1'           ,            'key2'           ])



7、get 和 get_multi

get            获取一个键值对
get_multi   获取多一个键值对

#!/usr/bin/env python          


           # -*- coding:utf-8 -*-          


           import            memcache          


                      


           mc            =            memcache.Client([           '10.211.55.4:12000'           ], debug           =           True           )          


                      


           val            =            mc.get(           'key0'           )          


           item_dict            =            mc.get_multi([           "key1"           ,            "key2"           ,            "key3"           ])



8、append 和 prepend

append    修改指定key的值,在该值 后面 追加内容
prepend   修改指定key的值,在该值 前面 插入内容


#!/usr/bin/env python          


           # -*- coding:utf-8 -*-          


           import            memcache          


                      


           mc            =            memcache.Client([           '10.211.55.4:12000'           ], debug           =           True           )          


           # k1 = "v1"          


                      


           mc.append(           'k1'           ,            'after'           )          


           # k1 = "v1after"          


                      


           mc.prepend(           'k1'           ,            'before'           )          


           # k1 = "beforev1after"




9、decr 和 incr  

incr  自增,将Memcached中的某一个值增加 N ( N默认为1 )
decr 自减,将Memcached中的某一个值减少 N ( N默认为1 )


#!/usr/bin/env python          


           # -*- coding:utf-8 -*-          


           import            memcache          


                      


           mc            =            memcache.Client([           '10.211.55.4:12000'           ], debug           =           True           )          


           mc.           set           (           'k1'           ,            '777'           )          


                      


           mc.incr(           'k1'           )          


           # k1 = 778          


                      


           mc.incr(           'k1'           ,            10           )          


           # k1 = 788          


                      


           mc.decr(           'k1'           )          


           # k1 = 787          


                      


           mc.decr(           'k1'           ,            10           )          


           # k1 = 777

10、gets 和 cas

如商城商品剩余个数,假设改值保存在memcache中,product_count = 900
A用户刷新页面从memcache中读取到product_count = 900
B用户刷新页面从memcache中读取到product_count = 900

如果A、B用户均购买商品

A用户修改商品剩余个数 product_count=899
B用户修改商品剩余个数 product_count=899

如此一来缓存内的数据便不在正确,两个用户购买商品后,商品剩余还是 899
如果使用python的set和get来操作以上过程,那么程序就会如上述所示情况!

如果想要避免此情况的发生,只要使用 gets 和 cas 即可,如:

#!/usr/bin/env python          


           # -*- coding:utf-8 -*-          


           import            memcache          


           mc            =            memcache.Client([           '10.211.55.4:12000'           ], debug           =           True           , cache_cas           =           True           )          


                      


           v            =            mc.gets(           'product_count'           )          


           # ...          


           # 如果有人在gets之后和cas之前修改了product_count,那么,下面的设置将会执行失败,剖出异常,从而避免非正常数据的产生          


           mc.cas(           'product_count'           ,            "899"           )



Ps:本质上每次执行gets时,会从memcache中获取一个自增的数字,通过cas去修改gets的值时,会携带之前获取的自增值和memcache中的自增值进行比较,如果相等,则可以提交,如果不想等,那表示在gets和cas执行之间,又有其他人执行了gets(获取了缓冲的指定值), 如此一来有可能出现非正常数据,则不允许修改。