前言
為了盡量減少緩存穿透,同時減少web的響應時間,我們可以針對那些需要一定時間才能獲取結果的函數和那些不需要頻繁更新的視圖函數提供緩存服務,可以在一定的時間內直接返回結果而不是每次都需要計算或者從數據庫中查找。flask_caching插件就是提供這種功能的神器。
flask_caching
安裝
pip install Flask-Caching
初始化配置
# __init__.py
from flask import Flask
from extensions import cache
from setting import Config
app = Flask(__name__)
app.config.from_object(Config)
# 可以使用config參數添加配置
cache.init_app(app=app,config={'CACHE_TYPE' : 'simple'})
# extensions.py
from flask_caching import Cache
cache = Cache()
# 也可以使用配置文件的方式,推薦使用這種方式
# setting.py
class Config:
CACHE_TYPE = 'simple'
常用配置參數詳解
CACHE_TYPE:設置緩存的類型
# 下面五個參數是所有的類型共有的
CACHE_NO_NULL_WARNING = "warning" # null類型時的警告消息
CACHE_ARGS = [] # 在緩存類實例化過程中解包和傳遞的可選列表,用來配置相關后端的額外的參數
CACHE_OPTIONS = {} # 可選字典,在緩存類實例化期間傳遞,也是用來配置相關后端的額外的鍵值對參數
CACHE_DEFAULT_TIMEOUT # 默認過期/超時時間,單位為秒
CACHE_THRESHOLD # 緩存的最大條目數
CACHE_TYPE = null # 默認的緩存類型,無緩存
CACHE_TYPE = 'simple' # 使用本地python字典進行存儲,線程非安全
CACHE_TYPE = 'filesystem' # 使用文件系統來存儲緩存的值
CACHE_DIR = "" # 文件目錄
CACHE_TYPE = 'memcached' # 使用memcached服務器緩存
CACHE_KEY_PREFIX # 設置cache_key的前綴
CAHCE_MEMCACHED_SERVERS # 服務器地址的列表或元組
CACHE_MEMCACHED_USERNAME # 用戶名
CACHE_MEMCACHED_PASSWORD # 密碼
CACHE_TYPE = 'uwsgi' # 使用uwsgi服務器作為緩存
CACHE_UWSGI_NAME # 要連接的uwsgi緩存實例的名稱
CACHE_TYPE = 'redis' # 使用redis作為緩存
CACHE_KEY_PREFIX # 設置cache_key的前綴
CACHE_REDIS_HOST # redis地址
CACHE_REDIS_PORT # redis端口
CACHE_REDIS_PASSWORD # redis密碼
CACHE_REDIS_DB # 使用哪個數據庫
# 也可以一鍵配置
CACHE_REDIS_URL 連接到Redis服務器的URL。示例redis://user:password@localhost:6379/2
- 配置多個緩存實例
如果有多個緩存需要使用不同的緩存后端,則可以備用多個字典;
cache1 = Cache()
cache2 = Cache()
cache1.init_app(app, config={ 'CACHE_TYPE' : 'redis','CACHE_REDIS_HOST':'192.168.1.20',
'CACHE_REDIS_PORT':'6390'})
cache2.init_app(app, config={ 'CACHE_TYPE' : 'redis','CACHE_REDIS_HOST':'192.168.1.21',
'CACHE_REDIS_PORT':'6390'})
使用實例
- 緩存函數或視圖函數
# __init__.py
from flask import Flask, current_app, make_response, request
from test import get_result, test_xxx
from exsentions import cache
app = Flask(__name__)
app.config['SECRET_KEY'] = '123'
# 配置緩存后端
cache.init_app(app, config={ 'CACHE_TYPE' : 'redis','CACHE_REDIS_HOST':'192.168.1.20',
'CACHE_REDIS_PORT':'6390'})
@app.route('/test1')
def test():
form_dict = request.args
n = form_dict.get('n')
res = get_result(int(n)) # 調用函數,結果會被緩存
return res
@app.route('/test2')
@cache.cached(timeout=30) # 專門為裝飾視圖函數准備的裝飾器
def test2():
cache.delete_memoized(get_result,4) # 刪除緩存數據
return 'ok'
@app.route('/test3')
def test3():
res = test_xxx()
return res
if __name__ == '__main__':
app.run(host='127.0.0.1', port=80, debug=True)
# extensions.py
from flask_caching import Cache
cache = Cache()
# test.py
from exsentions import cache
# 裝飾有參的函數
@cache.memoize(timeout=60, make_name='get_result')
def get_result(n):
return str(n)
@cache.cached(timeout=30)
def test_xxx():
return 'this is a test'
- 緩存鍵值對
# __init__.py
from flask import Flask, current_app, make_response, request
from test import get_result, test_xxx
from exsentions import cache
app = Flask(__name__)
app.config['SECRET_KEY'] = '123'
cache.init_app(app, config={ 'CACHE_TYPE' : 'redis','CACHE_REDIS_HOST':'192.168.1.20',
'CACHE_REDIS_PORT':'6390'})
@app.route('/test1')
def test():
cache.set('name','xiaoming', timeout=30)
cache.set('person',{'name':'aaa', 'age':20})
x = cache.get('name')
print(x)
cache.set_many([('name1','hhh'),('name2','jjj')])
print(cache.get_many("name1","name2"))
print(cache.delete("name"))
print(cache.delete_many("name1","name2"))
return res
if __name__ == '__main__':
app.run(host='127.0.0.1', port=80, debug=True)
分析
Cache對象
Cache作為緩存對象,主要有三個參數:
app:app對象
with_jinja2_ext:是否支持jinja2語法,默認True
config:配置參數
主要方法
cache.cached:裝飾器,裝飾無參數函數,使得該函數結果可以緩存
參數:
timeout:超時時間
key_prefix:設置該函數的標志
unless:設置是否啟用緩存,如果為True,不啟用緩存
forced_update:設置緩存是否實時更新,如果為True,無論是否過期都將更新緩存
query_string:為True時,緩存鍵是先將參數排序然后哈希的結果
cache.memoize:裝飾器,裝飾有參數函數,使得該函數結果可以緩存
make_name:設置函數的標志,如果沒有就使用裝飾的函數
# 其他參數同cached
cache.delete_memoized:刪除緩存
參數:
fname:緩存函數的名字或引用
*args:函數參數
cache.clear() # 清除緩存所有的緩存,這個操作需要慎重
cache.cache # 獲取緩存對象
BaseCache對象
所有類型的緩存對象都繼承自flask框架的BaseCache,它定義了一個使用緩存的標准接口,通過繼承BaseCache實現這些接口就可以在flask中方便的集成各種緩存;而flask_caching插件為我們對redis、memcached等實現了接口,做好了適配工作,我們可以直接使用。
from werkzeug.contrib.cache import BaseCache
# 標准接口
clear():清除緩存
get(key):獲取一個鍵的值,如果值是json格式會自動轉化成字典
set(key,value,timeout):設置一個鍵值,value可以是字典,會自動轉化json格式的字符串
set_many(key,value,timeout):設置多個鍵值對
add(key, value, timeout=None):設置一個鍵值,如果存在就pass,注意和set的區別
delete(key):刪除鍵
delete_many(k1,k2...):刪除多個鍵值
get_many(k1,k2...):獲取多個鍵的值
get_dict(k1,k2...):獲取多個鍵的值,返回一個字典
has(k):查詢是否存在一個鍵
inc(self, key, delta=1):將鍵的值加一
dec(self, key, delta=1):將鍵的值減一
自定義緩存后端
如果flask_caching當前集成的緩存服務器不符合我們的要求,比如需要使用mongodb做為后端緩存,那么我們可以自己實現那些標准接口。
# mycache.py
# 定義緩存類
from werkzeug.contrib.cache import BaseCache
class MongoCache(BaseCache):
def __init__(self, host='localhost', port=27017, username=None, password=None, default_timeout=500,**kwargs):
BaseCache.__init__(self, default_timeout)
if isinstance(host, str):
try:
from pymongo import MongoClient
except ImportError:
raise RuntimeError('no pymongo module found')
self._client = MongoClient(host=host,port=port, username=username, password=password, **kwargs)
else:
self._client = host
# 接下來使用pymongo實現BaseCache的各個接口
pass
def mongo(app, config, args, kwargs):
"""
這里處理app傳進來的參數用來連接mongodb
:param app:
:param config:
:param args:
:param kwargs:
:return:
"""
args.append(app.config['MONGO_SERVERS'])
return MongoCache(*args, **kwargs)
# 初始化時
# __init__.py
from flask import Flask, current_app, make_response, request
from exsentions import cache
app = Flask(__name__)
app.config['SECRET_KEY'] = '123'
cache.init_app(app, config={ 'CACHE_TYPE' : 'mycache.mongo',
'MONGO_SERVERS':'mongodb://username:passwd@localhost:27017/db'})
參考:
- 作者:天宇之游
- 出處:http://www.cnblogs.com/cwp-bg/
- 本文版權歸作者和博客園共有,歡迎轉載、交流,但未經作者同意必須保留此段聲明,且在文章明顯位置給出原文鏈接。