顯示包含「GAE」標籤的文章。顯示所有文章
顯示包含「GAE」標籤的文章。顯示所有文章

2009年9月1日星期二

App Engine的優化技巧(一)- 避免ReferenceProperty讀取資料庫

Google App Engine是一項以CPU時間、資料庫存取次數及其他限制等作收費依據的服務,曾經有過每天CPU時間上限達到46小時的日子,後來降至6.5小時,吸引力的確大不如前,眾用戶變得要過著勒緊褲頭的生活,這時候優化的技術就十分重要。

官方文件中提過不少的技巧,這裏就說一說官方文件中沒有記載的,第一個是關於ReferenceProperty的自動載入、轉換。

參考以下代碼:
class Author(db.Model):
name = db.StringProperty()

class Story(db.Model):
author = db.ReferenceProperty(Author)

story = db.get(story_key)
author_name = story.author.name
ReferenceProperty類別的模型為金鑰值(db.Key()),指向其他的記錄。以上叫做Story的模型有一個叫做author的ReferenceProperty,代表該故事的作者,而作者的資料則記錄在Author模型中,這種做法在SQL資料庫裏也很常見,沒什麼特別。
story = db.get(story_key)

這句在BigTable中取得一項Story記錄(又或者叫做實體模型、Model instance),要留意就是story.author_name所儲存的只是Key,並不包括作者的姓名等記錄在Author的資料。
author_name = story.author.name

當執行了以上的命令時,author_name儲存了什麼呢?答案是Author的實體的模型(model instance),並非以上所說的Key值。

這是ReferenceProperty的「功能」,一項自動載入、轉換的能力,跟據說明文件:
「ReferenceProperty 屬性值可以當做被參考實體的模型實例來使用。若參考的實體不在記憶體中,使用其屬性做為實例時,會自動從資料存放區擷取該實體。

A ReferenceProperty property value can be used as if it were the model instance of the referenced entity. If the referenced entity is not in memory, using the property as an instance automatically fetches the entity from the datastore.」
Source : http://code.google.com/intl/en/appengine/docs/python/datastore/entitiesandmodels.html#References

故此在story.author_name被第一次存取時,GAE就會自動在資料庫中取出記錄,很方便的功能吧?但別忘了,這會存取資料庫,代表會消耗有限的配額。

如果真的需要到這項資料,消耗也是沒有辦法的,但如果在其他的query中已取得這項Author的實體模型,也就冤枉了。

另外有種情況也會造成無辜的消耗,就是創建URL時,現在很喜歡這樣的URL風格:
xxxxxxx/$author_id/$story_id

當author_id=768,story_id = 10045時,就會變成是:
xxxxxxx/768/10045

假設在你的程式裏,已經擁有一個Story的實體,然後你想輸出以上的URL,基於需要用到Author的ID,你可能會這樣寫:
author_id = story.author_name.key().id_or_name()

而很不幸地,雖然在Story的實體中有記錄Author的Key,但這種寫法會導至GAE進行一次資料庫存取 - 浪費了配額下載了你不需要的資料。

這時候需要迂迴一點的寫法:
property = getattr(Story, "author_name")
author_key = property.get_value_for_datastore(story)
author_id = author_key.id_or_name()
這樣就不會造成資料庫的存取,為你省下不少的配額。

註: getattr(story,"author_name")的結果也是會導至資料庫的讀取

2009年8月28日星期五

Google App Engine缺乏備份工具的原因

一直都很奇怪,為什麼Google沒有為App Engine提供官方支援的備份工具呢?雖然Google一貫的做法是若有成熟的開源方案,就直接拿該方案來用,但唯一一套的gaebar有近半年以上沒有更新,跟新版SDK也不兼容,那為什麼仍未有動作呢?而且開源方案也實在太少了。

為了這個問題,做了些許的研究,發覺……原來又是BigTable的問題。

BigTable跟一般SQL的關聯式資料庫的概念非常之不同,那是分散式的資料庫,所以用法跟SQL相去甚遠。

例如說一項記錄的ID,BigTable有三種不同的表達方法,頭二種是numeric ID及key name,key name是由用戶設定的文字,在模組中是唯一的存在,而當記錄沒有被賦予key name時,BigTable就會為記錄加入numeric ID,故名思義那是一個數字,但這個數字的值並不連貫,所以也不能用來計算有多少記錄存在。

無論是numeric ID還是key name,最後都可以編碼成為最後一種表達方法 - 一個50位元的字串,那才是真正的ID。

問題是出於numeric ID,那是資料庫賦予的,用戶沒有辦法指派numeric ID予新建的記錄,就算有那個50位元字串也不能,唯一例外的是key_name。那麼使用了numerc ID的記錄,在備份後,是沒有辦法還原至原來的numeric ID的,那麼備份系統亦無法建立……

gaebar的解決方法是把numeric ID轉成key name(在numeric ID前面加入"id"字串),但這造成二個問題

1) 備份系統會修改資料庫內容,或許會令網站無法使用。
2) numeric ID及key name衝突又如何解決呢?(在Deployment server上應該不會發生,但development server是一定會的)

怎樣才可以設計出GAE合用的備份工具呢?頭痛啊。
Creative Commons License
本網誌Ben Lau製作,以共享創意署名-非商業性-相同方式共享 3.0 香港 授權條款釋出。