在 flask 開發中,我們經常會有資料庫操作、模板渲染等,這些操作單次可能速度感覺挺快,壓力不大,但是當次數一上來,那就不行了,各種問題就來了,所以為了緩解這些問題,我們經常會採用快取的方法以空間換時間。
但是,我們要怎麼快取呢?在 flask 的官方文件中有乙個簡單的解決方法,那就是利用 werkzeug(flask非常依賴它) 的 ******cache 來快取,如果有興趣可以檢視一下這頁文件:caching。雖然這是官網的乙個介紹,但是並非是很好的實踐,因為我們需要參與的事情太多了,所以為了解決一些繁雜的手續,有人開發了乙個外掛程式 flask-cache,它能幫助我們解決很多不需要的**,簡化到只需要乙個裝飾器。
下面,我就以我實踐過的專案介紹一下 flask-cache 的基本使用和一些比較好的實踐。
這個就是老生常談了,大多數的依賴都可以通過 pip 解決,這個也不例外:
pip install flask-cache
一開始就先來個簡單的應用,展示一下如何使用 flask-cache 吧,至於一些實踐之類的就先介紹完基本用法之後在後面介紹。下面就舉乙個快取 view 結果的示例:
#!/usr/bin/env python
# encoding: utf-8
from flask import flask
from flask.ext.cache import cache
# check configuring flask-cache section for more details
@cache.cached()
def index():
print "index called"
return "hello world"
if __name__ == '__main__':
這裡是乙個簡單的 flask 應用,在 line:12 我們指定了快取 view index,所以我們想把伺服器跑起來,然後訪問一下這個 url:
http://localhost:8080
當第一次訪問的時候我們可以看到控制台的輸出是:
* running on (press ctrl+c to quit)
index called
192.168.1.158 - - [18/mar/2019 18:03:05] "get /index http/1.1" 200 -
然後我們再重新整理一遍瀏覽器,這個時候看一下控制台的輸出:
192.168.1.158 - - [18/mar/2019 18:03:18] "get /index http/1.1" 200 -對比一下可以發現,當我們第二次訪問的時候,其實是沒有再執行一遍 index 函式了,而是直接將快取的結果返回了,這就達到了我們快取的目的了。
可能有的時候我們修改過資料或者更換過模板之類的情況,需要清理快取,這有主動和被動兩種辦法:
被動清除就是我們在設定快取裝飾器的時候指定快取生效時間,如果不想設定也行,那就在 flask 的設定中加上配置項:cache_default_timeout 這個配置,推薦使用變數 cache_default_timeout 的配置方式,但是這裡就介紹裝飾器的方式,還是以之前的示例為例進行介紹:
@cache.cached(timeout=50)
def index():
print "index called"
return "hello world"
這裡可以看到和之前的**有所區別,區別就在於 cache.cached 是帶引數了,引數就是 timeout,然後值是 50,其實就是說每次快取的有效期是 50 秒,50 秒過期之後需要重新獲取一遍,然後再快取 50 秒。這樣我們就可以在一定程度上保證快取的新鮮度。
其實,要保持更高的新鮮度,主動清除才是比較合適的方式,主動清除就是我們呼叫 cache 的 delete 方法來刪除指定的快取,首先想看下 delete 的函式原型:
delete(*args, **kwargs)
好像看不出什麼東西,那這裡直說吧,乙個呼叫的示例是這樣的:
cache.delete(key='view//')
這是刪除首頁的示例,這裡可能你會有點疑問了,這個 key 是什麼,我要刪除乙個快取我怎麼知道它的 key 是什麼?
對於這個問題,可能文件不會告訴你,但是我稍看了下原始碼,發現這個 key 的函式很簡單:
def make_cache_key(*args, **kwargs):
if callable(key_prefix):
cache_key = key_prefix()
elif '%s' in key_prefix:
cache_key = key_prefix % request.path
else:
cache_key = key_prefix
return cache_key
在第 5 行 可以看到 key 就是 key_prefix % request.path,和請求的路徑是相關的,那麼 key_prefix 是什麼呢,稍作查詢就會發現是: key_prefix=『view/%s』,這樣的話我們就可以很快得知道哪個 view 的 key 是什麼,也能很方便得清除快取了。
前面介紹的都是快取 view 的,那麼假設我要快取資料庫查詢怎麼辦,其實也很方便,和 view 的快取差不多,但是有一點點不一樣的就是我們需要制定快取的 key。因為我們前面可以看到,如果我們不指定 key 的話,預設的快取 key 是和請求路徑相關的,那麼就會和 view 的快取 key 衝突,這樣的話就悲劇了,混淆了快取。下面是乙個快取資料庫查詢的示例:
@cache.cached(key='all_post')
def get_all_post():
return post.query.all()
刪除快取
既然我們都明確指定 key 了,那麼刪除快取也就水到渠成的事情了,直接呼叫 cache.delete(『all_post』) 就刪除掉這個快取了,簡單明瞭。
前面我們都對這個問題避而不談,現在是時候來聊聊了,那就是快取快取,我們的快取到底快取在哪個地方?
我們往前面的例子看一下,可以看到初始化 cache 的**:
有個引數是 cache_type,這裡設定的值是 ******,那麼代表著什麼?根據官方文件的介紹,這個 ****** 的意思就是說使用本地python字典作為快取的位置,也就是說我們的快取都是放到記憶體中 python 的字典上,當獲取快取的時候直接從字典中根據 key 獲取。
那麼,除了 ******,還有那些可選的位置?根據官方文件的描述,目前支援的儲存位置有:
前面舉的例子是在乙個簡單的 flask 應用中的,但是,我們正常在使用的時候並不會就這麼簡單得使用 flask,我們會劃分為各個模組,例如 routes.py
models.py 以及 templates 等等,那麼,在這種情況下,我們該如何在 blueprint 上快取 view 呢?
首先先舉個 bad example:
// views.py
cache = cache()
@bp.route('test')
@cache.cached()
def test()
...// persistens.py
cache = cache()
@cache.cached()
def get_all_post()
...
這裡是每個地方都例項化了乙個 cache ,這明顯是不合理的,這裡我給的乙個比較合理的建議。
首先先說下目錄結構:
route.py
service.py
extensions.py
然後將初始化放到 extensions.py 裡面去:
// extension.spy
...cache = cache()
然後再在需要使用的地方 import 進來就好了:
@cache.cached()
def test()
...之前說過了,當我們需要更新資料的時候需要重新整理 cache,有兩種方式:主動和被動。主動重新整理我們需要刪除快取,那麼假設對於乙個部落格系統,我們再多個地方都快取了 cache,那麼在更新文章的時候難道需要在更新函式裡面重新整理?像這樣:
...這樣好像很難看,而且當我們在哪個新增了乙個新的快取的時候,還有可能要在這裡新增東西,那麼,有什麼好的辦法可以處理這個?我給的建議是使用 訊號,例如:
使用process exporter監控應用
node exporter是基於prometheus grafana的程序監控程式 安裝prometheus grafana sudo mkdir opt process exporter cd opt process exporter sudo vim process exporter.ymlno...
瀏覽器端的快取localStorage應用
伺服器傳輸大量資訊到客戶端 瀏覽器 即使有了伺服器端快取,使用者每次開啟web頁面都需要請求伺服器,傳輸大量資訊,然後渲染。主要存在網路傳輸成本,如果我們將大量的不太會變動的字典資訊儲存於localstorage,就能實現高效能的操作。由於localstorage是永久的,自身沒有過期時間,這對我們...
使用UIWebView開發hybrid應用(二)
使用uiwebview開發hybrid應用 一 hybrid應用中,快取處理是比較棘手的。objective c有快取的類nsurlcache,官方給出的解釋是 it provides a composite in memory and on disk cache。也就是說,當應用關閉後,快取就失效...