建立資料結構以達成同步一致性

附註:強烈建議建構新應用程式的開發人員使用 NDB 用戶端程式庫;相較於此用戶端程式庫,NDB 用戶端程式庫有幾項優點,例如能透過 Memcache API 自動快取實體。如果您目前使用的是舊版 DB 用戶端程式庫,請參閱 DB 至 NDB 遷移指南

Cloud Datastore 能透過許多機器發佈資料,還能針對地理範圍廣泛的區域使用免主機的同步備用資源,因此能發揮高度的可用性、擴充性以及耐用性。不過,這種設計有利有弊,缺點在於任何一個實體群組的寫入總處理量受限於大約每秒修訂一次。如要跨多個實體群組進行查詢或交易,也會受到限制。本頁詳細說明相關限制,同時以不犧牲應用程式寫入總處理量需求為前提,探討建立資料以利強式一致性的最佳做法。

同步一致性讀取功能一定能夠傳回最新的資料,此外,若是在交易當中執行,則會呈現來源是單一且一致的數據匯報。不過,查詢必須指定祖系篩選條件,才能保持十分一致或參與交易,且交易最多只能與 25 個實體群組相關。能發揮最終一致性的讀取功能沒有以上限制,適用於許多情況。若使用能發揮最終一致性的讀取功能,可以在為數更多的實體群組之間發佈資料,從而在不同的實體群組同時執行提交,以利提高寫入總處理量。但是,要判斷您的應用程式究竟是否適合使用能發揮最終一致性的讀取功能,就必須瞭解這類功能的特性:

  • 這類讀取功能的結果不見得能反映出最新交易,這是因為這類讀取功能並不要求必須執行最新的備用資源,且會在執行查詢時使用備用資源中的任何一項可用資料。備用資源的延遲時間通常不超過幾秒鐘。
  • 跨多個實體的單一修訂交易可能只適用於其中一部分實體,而不適用其他實體。然而請注意,絕對不會發生在單一實體中只適用部分交易的情形。
  • 查詢結果可能會包含根據篩選條件不應包含的實體,也可能會排除應包含的實體。這是因為索引讀取的版本可能會與實體本身所讀取的版本不同所導致。

如要瞭解如何建立資料結構以達到同步一致性,請比較 App Engine 留言板教學課程練習中的兩種不同方法。第一種方法會針對每一句問候語建立新的根實體:

Java 7

protected Entity createGreeting(
    DatastoreService datastore, User user, Date date, String content) {
  // No parent key specified, so Greeting is a root entity.
  Entity greeting = new Entity("Greeting");
  greeting.setProperty("user", user);
  greeting.setProperty("date", date);
  greeting.setProperty("content", content);

  datastore.put(greeting);
  return greeting;
}
import webapp2
from google.appengine.ext import db

class Guestbook(webapp2.RequestHandler):
  def post(self):
    greeting = Greeting()
    ...

接下來會查詢 Greeting 實體種類,找出最近十句問候語。

import webapp2
from google.appengine.ext import db

class MainPage(webapp2.RequestHandler):
  def get(self):
    self.response.out.write('<html><body>')
    greetings = db.GqlQuery("SELECT * "
                            "FROM Greeting "
                            "ORDER BY date DESC LIMIT 10")

然而,由於您使用的是非祖系查詢,因此當執行查詢作業時,在這項配置中用於執行查詢的備用資源可能尚未發現新的問候語。儘管如此,幾乎所有寫入均可在提交後幾秒內用於非祖系查詢。就許多應用程式而言,只要能在目前使用者自己所做的變更中提供非祖系查詢結果,即使出現備用資源延遲現象,通常也在可以接受的範圍。

如果您的應用程式十分需要具有同步一致性,您可以選擇採用替代方法,在必須透過具有同步一致性的單一祖系查詢來讀取的所有實體中,使用能識別相同根實體的祖系路徑來寫入實體:

import webapp2
from google.appengine.ext import db

class Guestbook(webapp2.RequestHandler):
  def post(self):
    guestbook_name=self.request.get('guestbook_name')
    greeting = Greeting(parent=guestbook_key(guestbook_name))
    ...

接著您就能夠在透過共同根實體所識別的實體群組中,執行具有同步一致性的祖系查詢:

import webapp2
from google.appengine.ext import db

class MainPage(webapp2.RequestHandler):
  def get(self):
    self.response.out.write('<html><body>')
    guestbook_name=self.request.get('guestbook_name')

    greetings = db.GqlQuery("SELECT * "
                            "FROM Greeting "
                            "WHERE ANCESTOR IS :1 "
                            "ORDER BY date DESC LIMIT 10",
                            guestbook_key(guestbook_name))

這個方法透過依留言板寫入單一實體群組來達到同步一致性,但同時也會將留言板限制為每秒最多只能寫入 1 次 (實體群組的支援上限)。若您的應用程式可能會出現較頻繁的寫入情形,可能需要考慮使用其他方法:例如可以為近期的 memcache 貼文設定到期日,並且混合顯示 memcache 和 Cloud Datastore 的近期貼文,也可以使用 Cookie 快取這些貼文,將部分狀態或其他完整資料放入網址中。這麼做的目的在於找到一個快取解決方案,以利目前使用者在您的應用程式中貼文的期間內提供資料。請記住,若在交易中執行 get 操作、祖系查詢或任何操作,一定會顯示最近寫入的資料。

本頁內容對您是否有任何幫助?請提供意見:

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

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