Google GAE Datastore:云計算中的結構化數據
GAE Datastore是Google App Engine提供的(半)結構化數據存儲系統,基于Google大名鼎鼎的Bigtable技術構建。
一、數據模型
GAE Datastore的數據模型與關系模型有很大的相似性,但是無模式的。GAE Datastore的接口主要是ORM風格的,一個類,稱為kind,與關系數據庫中的表類似。一個kind中的數據為多個entity,每個entity有唯一的key標識。每個entity可有多個property,一個property可用多個value。這與關系模型有類似的地方,但GAE Datastore中屬于同一個model的不同entity可以擁有完成不同的property,不同entity的同一個property的value的類型也可以不一樣。因此GAE Datastore的數據模型更為靈活。
多個entity可組成entity group,一個entity group實際上是以一個entity為根,通過父子關系(在創建entity時指定父親)構成的子樹。這一模型類似于關系模型之前的層次數據庫,自然也擁有與層次數據庫類似的局限,如很多模型就很難自然的用這種層次模型建模,如學生選課系統Student-Course-Elect,誰是誰的父親呢。entity group主要用于事務,后面會講到。
二、查詢與索引
GAE Datastore提供類似于SQL的GQL查詢,從SQL的觀點看,GQL的限制是只有單表查詢,有WHERE、ORDER BY和LIMIT/OFFSET,但沒有GROUP BY、HAVING、聚集函數等功能,也不支持子查詢。WHERE條件可以是基本的"property op value"條件通過and/or任意組合,ORDER BY可指定多個屬性。但條件的復雜度有一定限制:
1、如IN (list)條件中list最多只能有30個元素;
2、不等條件只能針對一個屬性指定;
3、不等條件屬性必須出現到ORDER BY的最前;
這些限制,據估計應該是為了實現方便和保證性能,如不等條件屬性在ORDER BY的最前這一限制使得系統可以方便的通過索引掃描直接輸出有序的結果,不需要再來排序。
更新的形式相比SQL有很大的限制。UPDATE通過put接口實現,給的參數是一個完整的entity,似乎不能像SQL一樣只更新某些屬性,為了更新一個屬性,似乎需要先取出整個entity(系統可能用lazy load技術,沒有用到的屬性不會取)。刪除時只能指定一個key列表,在關系數據庫中的一條DELETE語句要分成兩步,先通過查詢得到要刪除的entity的key,然后再來刪除。并且一次操作中刪除的entity個數不能超過500。
默認情況下GAE Datastore會建立一些基本的索引,根據文檔的描述,我推測GAE應默認為每個屬性建了一個索引,并且索引中都包含key (類似于InnoDB中的二級索引中都包含主鍵)。應用也可以在在配置文件中定義索引,指定索引包含的屬性及排序方向。索引的排序方向必須與查詢中ORDER BY的方向一致,也就是索引只能正向,不能反向掃描,我不清楚造成這一奇怪限制的原因是什么。
如果一個查詢沒有合適的索引,則不允許執行,也就是像關系數據庫一樣的表掃描是不行的。
三、事務
不使用事務時,對每個entity的寫操作是原子的。
系統使用樂觀的并發控制,其特征是在有并發沖突時,不等待,而是讓操作回滾失敗。這保證了操作的響應時間,但可能導致由于無法立即完成而失敗的操作增多,這就好比基于鎖的數據結構會被阻塞,無鎖數據結構則可能需要不斷的進行CAS循環。系統提供自動的重試機制緩解這一問題。
在同一個entity group中的多個entity操作可組合成一個事務,事務的ACID性質有保障。GAE Datastore應該是通過多版本的技術實現的,因此事務能夠獲得事務開始時的一致快照,奇怪的是事務本身的更新也看不到。
對不同entity group的操作是無法組合事務的,而entity group必須通過entity間的父子關系才能組織趕來。這使得GAE Datastore的事務會受一些限制,比如經典的銀行轉賬問題是搞不定的,兩個銀行賬戶,誰是誰的父親呢。理論上用一個偽的根entity把所有entity組成一個entity group,可以解決這一問題,但這會影響性能。因此只所以限制事務只能在一個entity group內,是因為系統在決定entity存儲位置時,會將同一entity group存在在一臺機器上,如果把所有entity都納到一個group,系統就無法分布與伸縮。
有一個細節問題是事務的提交分兩步進行:更新entity和更新索引。因此可能出現根據key找到的是更新后的entity,但根據索引找不到。
四、限制
GAE Datastore的數據或操作有很多限制,比如entity***1M,一次刪除的entity最多500個,查詢最多返回1000個結果等。這些限制可能會給應用開發帶來不便。對于查詢最多返回1000個結果這個限制,準確的說是limit + offset不能超過1000,即如果你指定了offset是200,那最多只能返回800個結果了。
五、評價
系統性能的兩大要素是Scalabity和Efficiency。Scalable的系統不一定Efficient,Efficient的系統也不一定Scalable。對于海量數據存儲系統來說,Scalable是必須的,是行與不行的問題,但Efficient也是非常重要的,是省與不省的問題。
GAE Datastore的Scalabity我估計是不錯的,但我不清楚有什么具體的證據表明其Scalabity到底怎么樣。GAE Datastore的數據分布對應用來說是透明的,應用不能指定根據某屬性的值進行哈希分區之類的顯式數據分布策略,這使得精準的查詢路由難以實現,Bigtable論文中說的bloom filer的效果是值得懷疑的。如果實現不了精準的查詢路由,很多查詢都要訪問大量存儲節點的話,就會影響到Scalabity。 雖然Google內部很多產品也用用GAE Datastore,但我們知道Google是買服務器不眨眼的,不好比。
但其Efficiency怎么樣,我持很大的懷疑態度。無模式將使得系統不能進行很多優化,底層基于GFS,通過冗余保證可靠性等都可能會影響到系統效率。有人反映Amazon SimpleDB不快,最簡單的查詢的響應時間也超過100ms,不知道類似的GAE Datastore會怎么樣。
功能上,***的優勢是無模式帶來的好處,即應用升級時不需要像數據庫那樣做非常耗時的增加/刪除字段操作了。但這是一把雙刃劍,也可能會帶來混亂。打個比方,這就類似于靜態類型與動態類型編程語句的區別。
其次,是ORM風格的接口帶來的開發便利,不需要像JDBC編程那樣寫很多SQL語句。
與數據庫相比,GAE Datastore的功能局限性也是明顯的,主要體現在查詢處理和事務處理兩個方面。查詢處理方面,查詢只能是單表,沒有GROUP BY和聚集函數,查詢的條件復雜度和查詢返回的記錄數都存在限制;DELETE不能指定WHERE,只能指定key的列表等。對事務的支持是受限的,只能在entity group中進行。這些局限,給應用開發會帶來多大的困難,我不清楚。我想,只有將我們的常見的應用如用戶與好友關系、日志、相冊、消息等,用關系數據庫和GAE Datastore對照著實現一遍,那么哪個系統好用,哪個不好用才能一清二楚。
【編輯推薦】