NDB 快取

NDB 會替您管理快取。 快取層級分為兩種:一種是內容快取, 另一種則是 App Engine 標準快取服務 memcache 的閘道。 預設所有實體類型均啟用這兩種快取, 但可以依據進階需求設定。 此外,NDB 會實作一項名為自動批次處理的功能, 這項功能會嘗試將作業群組在一起,盡可能減少伺服器來回處理的次數。

簡介

快取對大多數類型的應用程式有益。NDB 會自動快取 其所寫入或讀取的資料 (除非應用程式設定不啟用這項功能)。 讀取快取的速度比讀取 Datastore 的速度更快。

您可以調整許多 NDB 函式的行為,只要傳遞 內容選項引數即可。 例如,您可以呼叫 key.get(use_cache=False, use_memcache=False) 來略過快取。您也可以按照以下所述, 變更 NDB 上下文的快取政策。

注意: 當您使用 「管理主控台」的「Datastore 檢視器」修改 Datastore 內容時, 並不會更新快取值。 因此,可能會出現快取不一致的情況。 這種情況對內容快取而言通常不會造成問題。 但若是 Memcache,建議使用「管理主控台」 清除快取。

Context 物件

快取管理會採用一種名稱為 Context 的類別:在新內容中執行每一項執行緒和每一筆交易。由於每收到一個傳入 HTTP 要求便會開始一個新的執行緒,因此也會 在新內容中執行每一項要求。若要存取目前的內容, 請使用 ndb.get_context() 函式。

注意:在多項執行緒或要求之間共用 Context 物件是沒有意義的。 請勿將內容另存為全域變數! 將內容儲存在本機或執行緒本機變數即可。

Context 物件具有設定快取政策的方法,以及其他操控快取的方法。

內容快取

內容快取屬性只能在單一執行緒持續時間內存在。也就是說,每項 傳入的 HTTP 要求各有一個新的內容快取,而且只對 處理該項要求的程式碼「顯示」。若您的應用程式會在處理要求時衍生出其他任何執行緒, 這些執行緒也會各自包含新的內容快取。

內容快取的速度很快;這種快取存在記憶體中。NDB 函式寫入 Datastore 時,也會寫入內容快取。NDB 函式讀取實體時,則 會先檢查內容快取。若在內容快取中找到實體,就不會進行 Datastore 互動。

NDB 函式查詢 Datastore 時,會自 Datastore 擷取結果清單。不過,若內容快取中有任何單筆結果, 則會以該筆結果取代 Datastore 查詢所擷取到的值。 出現查詢結果後,會按照快取政策決定是否將 查詢結果重新寫入內容快取 (但一律不會寫入 Memcache)。

若背景工作中執行長時間執行的查詢,內容快取有可能會 佔用相當大量的記憶體。原因在於不論是自目前內容擷取的實體,或是儲存在目前內容中的實體, 快取一律為每一個實體保留一個複本。為避免長時間執行的工作發生記憶體例外狀況, 您可以停用快取或設定政策,運用政策排除 佔用最多記憶體的實體。

Memcache

Memcache 是 App Engine 的標準快取服務,速度比 Datastore 快得多,但比內容快取慢 (毫秒與微秒之差)。

根據預設,非交易內容會快取 memcache 中的所有實體。 應用程式的所有內容 均使用同一個 memcache 伺服器,而且會接收到一組 一致的快取值。

Memcache 不支援交易。因此, 若要更新 Datastore 和 memcache, 「或許」只能將更新套用於兩者其中之一。 在這種情況之下,為保持一致性 (可能必須犧牲 效能),系統會將已經更新的實體自 memcache 刪除, 然後寫入 Datastore。後續的讀取作業 會發現 memcache 中少了該實體,因此會自 Datastore 擷取該實體,然後在 memcache 中更新,這是讀取的副作用。 此外,讀取交易內部的 NDB 會忽略 Memcache。

在交易中寫入實體時,不會使用 memcache;確認交易時,交易內容會嘗試 刪除 memcache 中的所有此類實體。不過請注意,某些 故障情形可能會導致刪除失敗。

政策函式

自動快取比「大部分」的應用程式方便,但 或許您的應用程式非常特別,因此您會想要關閉自動 快取部分或所有實體的功能。 您可以運用設定政策函式的方法控制快取行為。 有一種政策函式可用於同處理序快取,設定方式如下:

context = ndb.get_context()
context.set_cache_policy(func)

另一種政策函式則適用於 memcache,設定方式如下:

context = ndb.get_context()
context.set_memcache_policy(func)

每一個政策函式各接受一個金鑰並傳回一個布林結果。 若傳回 False,對應快取就不會儲存 該金鑰所定義的實體。 例如,若要略過所有 Account 實體的 同處理序快取,您可以寫入

context = ndb.get_context()
context.set_cache_policy(lambda key: key.kind() != 'Account')

(不過,後文有更容易達成同一目的方式。) 為方便起見,您可以傳遞 TrueFalse, 而不傳遞一律傳回同一個值的函式。 預設政策會快取所有實體。

另有一個 Datastore 政策函式負責控管 應寫入 Datastore 本身的實體:

context = ndb.get_context()
context.set_datastore_policy(func)

其運作原理如同內容快取和 memcache 政策函式: 若 Datastore 政策函式遇到特定金鑰時 傳回 False,就不會將對應的實體寫入 Datastore。 (可能會將其寫入同處理序快取或 memcache, 前提是它們的政策函式允許這麼做。) 若您想要快取類實體資料,但不需要 將這些資料儲存在 Datasore 中, 非常適合使用這種方式。 就像快取政策一樣,您可以傳遞 TrueFalse 而不需傳遞一律傳回同一個值的函式。

Memcache 若受限於記憶體壓力,會 自動將項目設為到期。 您可以設定 memcache 逾時政策函式,用於決定 實體在快取中的生命週期上限:

context = ndb.get_context()
context.set_memcache_timeout_policy(func)

呼叫此函式時須使用金鑰引數,且呼叫程序應傳回 整數,按秒數註明生命週期上限; 0 或 None 表示無限期 (只要 memcache 伺服器的記憶體足夠就會繼續存在)。 為方便起見,您可以只傳遞整數常數, 不需要傳遞一律傳回同一個值的函式。如需逾時的詳細資訊,請參閱 memcache 說明文件。

附註:內容快取沒有獨立的生命週期政策:這類快取的生命週期與其內容相同 (也就是單一傳入的 HTTP 要求)。不過,您可以透過下列呼叫清除同處理序快取
context = ndb.get_context()
context.clear_cache()

全新內容會從空的同處理序快取開始。

政策函式的彈性相當大, 但大多數的政策均十分簡單。例如,

  • 不會快取屬於特定模型類別的快取實體。
  • 會將屬於此模型類別之實體的 memcache 逾時設為 30 秒。
  • 不需將屬於此模型類別的實體寫入 Datastore。

為簡化寫入並持續更新瑣碎的 政策函式的流程 (更麻煩的作業是要覆寫每一個 使用內容選項之作業的政策),預設政策函式 會自傳遞至這類政策函式的金鑰中擷取模型類別, 然後在該模型類別中查詢特定的類別變數:

類別變數類型說明
_use_cache bool 指定是否要將實體儲存在同處理序快取中;會覆寫預設的同處理序快取政策。
_use_memcache bool 指定是否要將實體儲存在 memcache 中;會覆寫預設的 memcache 政策。
_use_datastore bool 指定是否要將實體儲存在 datastore 中;會覆寫預設的 Datastore 政策。
_memcache_timeout int 實體在 memcache 中的生命週期上限;會覆寫預設的 memcache 逾時政策。

附註: 這是每一項政策之預設政策函式的功能。如果指定自己的政策函式,但也想要恢復預設政策,請明確呼叫預設政策函式做為 Context 類別的靜態方法:

  • default_cache_policy(key)
  • default_memcache_policy(key)
  • default_datastore_policy(key)
  • default_memcache_timeout_policy(key)
本頁內容對您是否有任何幫助?請提供意見:

傳送您對下列選項的寶貴意見...

這個網頁
Python 2 適用的 App Engine 標準環境