2008年7月25日 星期五

HTTP request solution in GAE

雖然 GAE 有提供 urlfetch 這個 API 達到 server side 的 HTTP request 功能,但是在仔細閱讀 GAE 的線上文件後,就不難發現這其實是個看到卻不好吃的功能,為什麼呢?以下這段但書節錄自 urlfetch API 的說明:

Since your application must respond to the user's request within several seconds, a URL fetch action to a slow remote server may cause your application to return a server error to the user. There is currently no way to specify a time limit to the URL fetch action.

從以上的敘述,不難發現 urlfetch 無法設定 timeout 值,任何耗時過長的 urlfetch 呼叫都會導致 GAE 回傳 HTTP 404 error 給使用者,又因為 Google 捨棄了很多 python runtime 功能以達到快速的 response time,包括無法在單一 request 中起始多個 thread,所以自然也沒有所謂的 callback function or method,呼叫 urlfetch 的 script 會一直處於等待回傳的狀態。

既然無法設定 timeout 且 GAE developer 又無法控制遠端服務的回傳時間,真不知 urlfetch API 有何實質用處?或許這是 Google 本身的陰謀:讓 developer 只使用 urlfetch 來取得 Google 本身的其他服務內容。畢竟,從 GAE 發出 HTTP request 給其他 Google Service 的回應時間絕對是最短的。

Well,解決辦法也不是沒有,就是將 HTTP request 從 server side 搬到 client side 去,在 web 開發漸漸朝向 AJAX 靠攏後,似乎也沒有必要在 server side 執行 HTTP request 了。下圖的紅色資料流即是 server side HTTP request 的資料流,綠色部分則是 Yu-Chao 所建議的 HTTP request 方式,亦即透過 client side javascrip 發出 HTTP request。



覺得寫 AJAX 很麻煩嗎?可是在 GAE 又無法使用 Microsoft AJAX.NET 這種傻瓜開發法(效能不佳),那 Yahoo 的 YUI library 倒不失為一好的解決方案。

2008年7月21日 星期一

Advanced GAE development Tips

在 Google 2008 programming day 的 advanced GAE developing section 中,主講人特別針對 Datastore API 的相關主題做了深入淺出的介紹,並提供了幾個十分具有參考價值的範例。第一個重點,也是此次活動不久前 Google 才為 GAE 加入了 memcache 這個機制:

results = memcache.get('cache name')
if results is None
 results = db.GqlQuery('...').fetch(10)
 memcache.add('cache name', results, 60)

講白一點,就是 cache 快取,但是 GAE 的 memcache 是架構在 Google 的整個全球分散式 web hosts 叢集上,有了 Google 強大的硬體支援做後盾,我想運算速度再怎麼強大、記憶體再怎麼多的一般伺服器也難望其項背吧!(Yu-Chao 依稀記得前陣子於工作中身陷 Microsoft ASP.NET 應用程式的效能問題,因為該應用系統是架構於一 Open Source 的 package,在該系統使用者逐漸增多,而客製化的模組又快速成長且缺乏良好的規劃之下,系統的效能瓶頸逐漸顯現,最後只好藉由增大 cache 來解燃眉之急,不過 .NET runtime 的 cache 機制的不穩定性眾所皆知,除非透過轉存 database 的方式,否則記憶體的耗用程度把伺服器搞 crash 是很容易的事情。)

第二點,就是清楚的說明了寫入和讀取的效能差異性,一次性的 disk seek 所耗用的平均時間約為 10ms,也就是每秒最大的 disk seek 數約為 100 次,所以在使用 Datastore API 撰寫相關程式邏輯時,就必須考量到昂貴的寫入成本。相較於寫入,讀取成本則非常低廉,透過 Google 的 bigtable 架構,可達每秒平均 4GB 的讀取量,十分驚人!

再來的重點,就是重新強調了 entity 的 key feature 以及 transaction 和 entity group 的關係,主講人 Brett Slatkin 給了大家一個時分貼切的形容:將整個 bigtable 看做一個大型的 hashtable,透過給定特定 key 值的方式,使得讀取(query)的時間耗用可以降到最低(hash 運算之故),而 transaction 和 entity group 的說明大致上不拖 online document 所提及的內容,不過卻提到了一個開發上的重點,因為 transaction 會 lock 整個 entity group,所以有效的限制 entity group 的規模就很重要,思考如何依據開發需求以設計出有效降低寫入成本的 datastore model,便是 GAE 開發的關鍵點。

Brett Slatkin 提到的第一個範例程式 counter,就說明了分散式的 bigtable 架構的特殊之處,以往的 RDBS 可透過 SQL 命令來計算 query 的筆數,但是在分散式架構中,GAE 無從得知資料的總比數,所以我們必須額外建立一個儲存加總值的 global entity,透過不斷更新該 entity value 的方式來獲得加總值,不過這時又會遇到寫入時的 transaction 問題,如果加總的頻率過高,很可能導致寫入/ transaction 失敗的情形發生。此時,最好的 model 就是建立多個計數的 global entity 在不同的 entity group 中,於加總時動態隨機挑選其中一個 entity 做加總,在最後欲得知總數時,再透過 query 這些 entities 得到的多個 values 加總而得。

第二個範例則說明了相同的 global entity 如何應用在 blog 系統上,在面對需要排序處理的例子時,此範例說明了如何透過單一的 global entity (因為對於 blog 系統來說,張貼文章的速度以及急迫性並未像 counter 來的高)搭配 fetch method 來實作分頁(paging)功能,另外針對 comment 的實作方式,也充分說明了 timestamp 在分散式的 bigtable 上並未能保持絕對的一致,因此針對 timestamp 欄位做排序並未能真正獲得實際的資料產生順序,此時可以透過為每個使用者分別保存各自的 index entity 和 comment entity group 來達成排序的正確性(但非時間上的絕對正確性),此範例實為一 bigtable 上的經典 pattern!若能精通此範例於 Datastore 的應用 concept,就絕對能設計出符合分散式 bigtable 的 datastore model,值得有心鑽研 GAE 的人反覆研究。

Official page of Google developer day 2008:
http://sites.google.com/site/developerdaytaiwan/

Advanced GAE section video:
http://tw.youtube.com/watch?v=YbsU90iGySk

2008年7月15日 星期二

Radio Head 的新 MV

今日 Yu-Chao 進入 Google Code 準備繼續研究 GAE 時,一個斗大的 YouTube 播放窗格就這樣出現在頁面上,當時還心想怎麼 Radio Head 打歌打到 Google Code 裡面來了,會不會太誇張,但是仔細閱讀 MV 旁的說明後,才發現這支 MV 是使用了最新的 3D 擷取技術所拍攝,全程沒有使用到任何一台攝影機以及燈光效果,完全以單純的 3D points 來展現。

MV 中使用到的 3D 擷取技術跟我們以往所熟知,用於電影及遊戲動畫的動態捕捉系統不同,而是跟坊間一種立體雷射雕刻類似,以密集且高速的雷射來掃瞄並建置 3D 場景,只不過雷射雕刻的雷射掃瞄侷限於短距離範圍,而本 Radio Head MV 中使用的系統則可以大範圍的掃瞄整個地貌場景,使得 Video 中得呈現令人驚豔的效果!

You may check with it from here:
http://code.google.com/creative/radiohead/