GAE Java 應用效能最佳化
轉載請保留作者資訊:
作者:88250
日期:2011 年 2 月 8 日
本文是作者開發 GAE 應用的效能最佳化經驗談,主要從架構、緩衝、非同步呼叫等方面介紹了如何進行高效能 GAE 應用的設計及最佳化。
ToC
使用 Memcache 進行緩衝
HTML 頁面
資料查詢結果
Memcache 使用注意
減少記憶體使用量
盡量避免使用架構
無狀態設計
非同步 APIs
其他
靜態資源
實體組
網域名稱解析
實現邏輯
參考資料
使用 Memcache 進行緩衝
使用緩衝主要是為了提高響應速度。
HTML 頁面
頁面可以根據功能來劃分進行緩衝,請參考:應用 memcached 提升網站效能——減少讀自資料庫和資料來源
。
當然,也可以緩衝整個頁面,簡化緩衝及模板處理邏輯。
資料查詢結果
如果你是直接使用 GAE DatastoreService
來進行資料查詢,那麼有必要緩衝查詢結果:
- 單一實體
根據唯一標識進行查詢的實體。
- 集合實體
根據組合查詢條件查詢的實體,例如分頁結果。
Memcache 使用注意
- 調用 GAE Memcache 也是會消耗一定 CPU 的(需要進行序列化/還原序列化)
- 使用 GAE MemcaheService#clearAll()
方法會清除所有命名空間的緩衝
減少記憶體使用量
減少記憶體使用量主要是為了充分利用有限的 Memcache 服務,降低執行個體啟動時間。
盡量避免使用架構
雖然目前一些流行的 Java Web 架構(Spring、Struts、Play!、etc)是可以運行在 GAE 上的,但如果你想盡量免費地使用 GAE,
那最好還是不要使用現有架構,因為,大多數架構:
- 不是專門為 GAE 設計的
- 比較消耗記憶體
- 將延長啟動時間
另外,關於 JSP 與其他模板引擎的優劣取捨問題這裡不討論。目前經測試無頁面緩衝情況下,FreeMarker 與 JSP 效能非常接近。
無狀態設計
有狀態的設計是比較吃記憶體的,服務端最好少使用有狀態的模型,除非要處理複雜的商務邏輯(例如多步表單、進階搜尋)。
非同步 APIs
GAE 提供了資料存取、HTTP 要求等 APIs 的非同步版本。但需要注意:
- 目前 GAE/J(1.4.0)中的 Query 是沒有非同步 APIs 的
AsyncDatastoreService
或者 DatastoreService
上使用 PreparedQuery.asIterable()
與 PreparedQuery.asIterator()
效果一樣,都是調用了就返回,迭代時才真正去擷取資料
- 阻塞(同步)點
非同步 APIs 調用後的代碼塊中要注意在哪個點進行同步,過早進行同步將降低非同步 APIs 帶來的優勢。
- 調用非同步 APIs 與調用同步 APIs 消耗同樣的配額
其他
靜態資源
仔細配置 appengine-web.xml 中 <static-files> 元素,這些資源將從單獨的 Google 伺服器、緩衝擷取,並不佔用
應用伺服器配額。
實體組
實體組是具有一定邏輯關係的、儲存在同一 GAE 雲端儲存地區的實體集。事務操作只能針對同一實體組的實體操作。
實體組對效能有一定影響(目前尚未實踐證明影響有多大),但請盡量保持實體組的最小化。
網域名稱解析
GAE 送的次層網域(*.appspot.com)在國內訪問非常不穩定,所以最好綁定綁定自己的網域名稱。
但綁定網域名稱時需要配置 GHS IP,目前在國內已經沒有 IP 可用。進一步,需要配置反向 Proxy來進行請求代理。
在服務端效能最佳化後需要選擇一個速度快、穩定的反向 Proxy。不然,辛辛苦苦在服務端最佳化降低了幾百 ms 的處理時間,
結果全耗在路由、丟包上了
如果免費的反向 Proxy實在不能夠滿足效能需要,只能自己打個付費的了,或者等到 GHS 可用。。。。
實現邏輯
另外,目前 GAE 給的免費 CPU 配額比較少,所以最佳化實現邏輯以減少 CPU、APIs 使用也是非常關鍵的。
寫代碼時應該時刻注意代碼的邏輯是否足夠簡潔,能一次性擷取的參數就別重複擷取,擷取後以方法參數的形式進行傳遞。
參考資料
- App Engine Java Overview
- Best practices for writing scalable applications
- GAE SDK Javadoc
- GAE 資料存放區——事務
- GAE/Java 應用程式框架——B3log Latke
本文是使用 B3log Solo
從 簡約設計の藝術
進行同步發布的原文地址:http://88250.b3log.org/gae-java-performance-optimization.html