Google App Engine技術架構資料大盤點
今天看到幾篇有關Google App Engine的技術架構文章,一起分享給大家,沒看到過的同學趕緊驚喜一下吧,看到過了的同學也假裝驚喜一下嘛,呵呵。
全部文章有點長,請耐心看下去,相信程序員都是有耐心的,除了我.......
一、Google的核心技術
在切入Google App Engine之前,首先會對Google的核心技術和其整體架構進行分析,以幫助大家之后更好地理解Google App Engine的實現。
本篇將主要介紹Google的十個核心技術,而且可以分為四大類:
◆ 分布式基礎設施:GFS、Chubby 和 Protocol Buffer。
◆ 分布式大規模數據處理:MapReduce 和 Sawzall。
◆ 分布式數據庫技術:BigTable 和數據庫 Sharding。
◆ 數據中心優化技術:數據中心高溫化、12V電池和服務器整合。
分布式基礎設施
GFS
由于搜索引擎需要處理海量的數據,所以Google的兩位創始人Larry Page和Sergey Brin在創業初期設計一套名為"BigFiles"的文件系統,而GFS(全稱為"Google File System")這套分布式文件系統則是"BigFiles"的延續。
首先,介紹它的架構,GFS主要分為兩類節點:
◆ Master節點:主要存儲與數據文件相關的元數據,而不是Chunk(數據塊)。元數據包括一個能將64位標簽映射到數據塊的位置及其組成文件 的表格,數據塊副本位置和哪個進程正在讀寫特定的數據塊等。還有Master節點會周期性地接收從每個Chunk節點來的更新("Heart- beat")來讓元數據保持***狀態。
◆ Chunk節點:顧名思義,肯定用來存儲Chunk,數據文件通過被分割為每個默認大小為64MB的Chunk的方式存儲,而且每個Chunk有唯一一個64位標簽,并且每個Chunk都會在整個分布式系統被復制多次,默認為3次。
下圖就是GFS的架構圖:

圖1. GFS的架構圖(參片[15])
接著,在設計上,GFS主要有八個特點:
◆ 大文件和大數據塊:數據文件的大小普遍在GB級別,而且其每個數據塊默認大小為64MB,這樣做的好處是減少了元數據的大小,能使Master節點能夠非常方便地將元數據放置在內存中以提升訪問效率。
◆ 操作以添加為主:因為文件很少被刪減或者覆蓋,通常只是進行添加或者讀取操作,這樣能充分考慮到硬盤線性吞吐量大和隨機讀寫慢的特點。
◆ 支持容錯:首先,雖然當時為了設計方便,采用了單Master的方案,但是整個系統會保證每個Master都會有其相對應的復制品,以便于在 Master節點出現問題時進行切換。其次,在Chunk層,GFS已經在設計上將節點失敗視為常態,所以能非常好地處理Chunk節點失效的問題。
◆ 高吞吐量:雖然其單個節點的性能無論是從吞吐量還是延遲都很普通,但因為其支持上千的節點,所以總的數據吞吐量是非常驚人的。
◆ 保護數據:首先,文件被分割成固定尺寸的數據塊以便于保存,而且每個數據塊都會被系統復制三份。
◆ 擴展能力強:因為元數據偏小,使得一個Master節點能控制上千個存數據的Chunk節點。
◆ 支持壓縮:對于那些稍舊的文件,可以通過對它進行壓縮,來節省硬盤空間,并且壓縮率非常驚人,有時甚至接近90%。
◆ 用戶空間:雖然在用戶空間運行在運行效率方面稍差,但是更便于開發和測試,還有能更好利用Linux的自帶的一些POSIX API。
現在Google內部至少運行著200多個GFS集群,***的集群有幾千臺服務器,并且服務于多個Google服務,比如Google搜索。但由于 GFS主要為搜索而設計,所以不是很適合新的一些Google產品,比YouTube、Gmail和更強調大規模索引和實時性的Caffeine搜索引擎 等,所以Google已經在開發下一代GFS,代號為"Colossus",并且在設計方面有許多不同,比如:支持分布式Master節點來提升高可用性 并能支撐更多文件,Chunk節點能支持1MB大小的chunk以支撐低延遲應用的需要。
Chubby
簡單的來說,Chubby 屬于分布式鎖服務,通過 Chubby,一個分布式系統中的上千個client都能夠對于某項資源進行"加鎖"或者"解鎖",常用于BigTable的協作工作,在實現方面是通過 對文件的創建操作來實現"加鎖",并基于著名科學家Leslie Lamport的Paxos算法。
Protocol Buffer
Protocol Buffer,是Google內部使用一種語言中立、平臺中立和可擴展的序列化結構化數據的方式,并提供 Java、C++ 和 Python 這三種語言的實現,每一種實現都包含了相應語言的編譯器以及庫文件,而且它是一種二進制的格式,所以其速度是使用 XML 進行數據交換的10倍左右。它主要用于兩個方面:其一是RPC通信,它可用于分布式應用之間或者異構環境下的通信。其二是數據存儲方面,因為它自描述,而 且壓縮很方便,所以可用于對數據進行持久化,比如存儲日志信息,并可被Map Reduce程序處理。與Protocol Buffer比較類似的產品還有Facebook的 Thrift ,而且 Facebook 號稱Thrift在速度上還有一定的優勢。
分布式大規模數據處理
MapReduce
首先,在Google數據中心會有大規模數據需要處理,比如被網絡爬蟲(Web Crawler)抓取的大量網頁等。由于這些數據很多都是PB級別,導致處理工作不得不盡可能的并行化,而Google為了解決這個問題,引入了 MapReduce這個編程模型,MapReduce是源自函數式語言,主要通過"Map(映射)"和"Reduce(化簡)"這兩個步驟來并行處理大規 模的數據集。Map會先對由很多獨立元素組成的邏輯列表中的每一個元素進行指定的操作,且原始列表不會被更改,會創建多個新的列表來保存Map的處理結 果。也就意味著,Map操作是高度并行的。當Map工作完成之后,系統會先對新生成的多個列表進行清理(Shuffle)和排序,之后會這些新創建的列表 進行Reduce操作,也就是對一個列表中的元素根據Key值進行適當的合并。
下圖為MapReduce的運行機制:
圖2. MapReduce的運行機制(參[19])
接下來,將根據上圖來舉一個MapReduce的例子:比如,通過搜索Spider將海量的Web頁面抓取到本地的GFS集群中,然后Index系 統將會對這個GFS集群中多個數據Chunk進行平行的Map處理,生成多個Key為URL,value為html頁面的鍵值對(Key-Value Map),接著系統會對這些剛生成的鍵值對進行Shuffle(清理),之后系統會通過Reduce操作來根據相同的key值(也就是URL)合并這些鍵 值對。
***,通過MapReduce這么簡單的編程模型,不僅能用于處理大規模數據,而且能將很多繁瑣的細節隱藏起來,比如自動并行化,負載均衡和機器宕 機處理等,這樣將極大地簡化程序員的開發工作。MapReduce可用于包括"分布grep,分布排序,web訪問日志分析,反向索引構建,文檔聚類,機 器學習,基于統計的機器翻譯,生成Google的整個搜索的索引"等大規模數據處理工作。Yahoo也推出MapReduce的開源版本Hadoop,而 且Hadoop在業界也已經被大規模使用。
Sawzall
Sawzall可以被認為是構建在MapReduce之上的采用類似Java語法的DSL(Domain-Specific Language),也可以認為它是分布式的AWK。它主要用于對大規模分布式數據進行篩選和聚合等高級數據處理操作,在實現方面,是通過解釋器將其轉化 為相對應的MapReduce任務。除了Google的Sawzall之外,yahoo推出了相似的Pig語言,但其語法類似于SQL。
分布式數據庫技術
BigTable
由于在Google的數據中心存儲PB級以上的非關系型數據時候,比如網頁和地理數據等,為了更好地存儲和利用這些數據,Google開發了一套數 據庫系統,名為"BigTable"。BigTable不是一個關系型的數據庫,它也不支持關聯(Join)等高級SQL操作,取而代之的是多級映射的數 據結構,并是一種面向大規模處理、容錯性強的自我管理系統,擁有TB級的內存和PB級的存儲能力,使用結構化的文件來存儲數據,并每秒可以處理數百萬的讀 寫操作。
什么是多級映射的數據結構呢?就是一個稀疏的,多維的,排序的Map,每個Cell由行關鍵字,列關鍵字和時間戳三維定位.Cell的內容是一個不 解釋的字符串,比如下表存儲每個網站的內容與被其他網站的反向連接的文本。 反向的URL com.cnn.www是這行的關鍵字;contents列存儲網頁內容,每個內容有一個時間戳,因為有兩個反向連接,所以archor的Column Family有兩列:anchor: cnnsi.com和anchhor:my.look.ca。Column Family這個概念,使得表可以輕松地橫向擴展。下面是它具體的數據模型圖:
圖3. BigTable數據模型圖(參[4])
在結構上,首先,BigTable基于GFS分布式文件系統和Chubby分布式鎖服務。其次BigTable也分為兩部分:其一是Master節 點,用來處理元數據相關的操作并支持負載均衡。其二是tablet節點,主要用于存儲數據庫的分片tablet,并提供相應的數據訪問,同時Tablet 是基于名為SSTable的格式,對壓縮有很好的支持。
圖4. BigTable架構圖(參[15])
BigTable正在為Google六十多種產品和項目提供存儲和獲取結構化數據的支撐平臺,其中包括有Google Print、 Orkut、Google Maps、Google Earth和Blogger等,而且Google至少運行著500個BigTable集群。
隨著Google內部服務對需求的不斷提高和技術的不斷地發展,導致原先的BigTable已經無法滿足用戶的需求,而Google也正在開發下一代BigTable,名為"Spanner(扳手)",它主要有下面這些BigTable所無法支持的特性:
◆ 支持多種數據結構,比如table,familie,group和coprocessor等。
◆ 基于分層目錄和行的細粒度的復制和權限管理。
◆ 支持跨數據中心的強一致性和弱一致性控制。
◆ 基于Paxos算法的強一致性副本同步,并支持分布式事務。
◆ 提供許多自動化操作。
◆ 強大的擴展能力,能支持百萬臺服務器級別的集群。
◆ 用戶可以自定義諸如延遲和復制次數等重要參數以適應不同的需求。
數據庫Sharding
Sharding就是分片的意思,雖然非關系型數據庫比如BigTable在Google的世界中占有非常重要的地位,但是面對傳統OLTP應用, 比如廣告系統,Google還是采用傳統的關系型數據庫技術,也就是MySQL,同時由于Google所需要面對流量非常巨大,所以Google在數據庫 層采用了分片(Sharding)的水平擴展(Scale Out)解決方案,分片是在傳統垂直擴展(Scale Up)的分區模式上的一種提升,主要通過時間,范圍和面向服務等方式來將一個大型的數據庫分成多片,并且這些數據片可以跨越多個數據庫和服務器來實現水平 擴展。
Google整套數據庫分片技術主要有下面這些優點:
◆ 擴展性強:在Google生產環境中,已經有支持上千臺服務器的MySQL分片集群。
◆ 吞吐量驚人:通過巨大的MySQL分片集群能滿足巨量的查詢請求。
◆ 全球備份:不僅在一個數據中心還是在全球的范圍,Google都會對MySQL的分片數據進行備份,這樣不僅能保護數據,而且方便擴展。
在實現方面,主要可分為兩塊:其一是在MySQL InnoDB基礎上添加了數據庫分片的技術。其二是在ORM層的Hibernate的基礎上也添加了相關的分片技術,并支持虛擬分片(Virtual Shard)來便于開發和管理。同時Google也已經將這兩方面的代碼提交給相關組織。
數據中心優化技術
數據中心高溫化
大中型數據中心的PUE(Power Usage Effectiveness)普遍在2左右,也就是在服務器等計算設備上耗1度電,在空調等輔助設備上也要消耗一度電。對一些非常出色的數據中心,最多也 就能達到1.7,但是Google通過一些有效的設計使部分數據中心到達了業界領先的1.2,在這些設計當中,其中最有特色的莫過于數據中心高溫化,也就 是讓數據中心內的計算設備運行在偏高的溫度下,Google的能源方面的總監Erik Teetzel在談到這點的時候說:"普通的數據中心在70華氏度(21攝氏度)下面工作,而我們則推薦80華氏度(27攝氏度)"。但是在提高數據中心 的溫度方面會有兩個常見的限制條件:其一是服務器設備的崩潰點,其二是精確的溫度控制。如果做好這兩點,數據中心就能夠在高溫下工作,因為假設數據中心的 管理員能對數據中心的溫度進行正負1/2度的調節,這將使服務器設備能在崩潰點5度之內工作,而不是常見的20度之內,這樣既經濟,又安全。還有,業界傳 言Intel為Google提供抗高溫設計的定制芯片,但云計算界的***專家James Hamilton認為不太可能,因為雖然處理器也非常懼怕熱量,但是與內存和硬盤相比還是強很多,所以處理器在抗高溫設計中并不是一個核心因素。同時他也 非常支持使數據中心高溫化這個想法,而且期望將來數據中心甚至能運行在40攝氏度下,這樣不僅能節省空調方面的成本,而且對環境也很有利。
12V電池
由于傳統的UPS在資源方面比較浪費,所以Google在這方面另辟蹊徑,采用了給每臺服務器配一個專用的12V電池的做法來替換了常用的UPS, 如果主電源系統出現故障,將由該電池負責對服務器供電。雖然大型UPS可以達到92%到95%的效率,但是比起內置電池的99.99%而言是非常捉襟見肘 的,而且由于能量守恒的原因,導致那么未被UPS充分利用的電力會被轉化成熱能,這將導致用于空調的能耗相應地攀升,從而走入一個惡性循環。同時在電源方 面也有類似的"神來之筆",普通的服務器電源會同時提供5V和12V的直流電。但是Google設計的服務器電源只輸出12V直流電,必要的轉換在主板上 進行,雖然這種設計會使主板的成本增加1美元到2美元,但是它不僅能使電源能在接近其峰值容量的情況下運行,而且在銅線上傳輸電流時效率更高。
服務器整合
談到虛擬化的殺手锏時,***個讓人想到肯定是服務器整合,而且普遍能實現1:8的整合率來降低各方面的成本。有趣的是,Google在硬件方面也引 入類似服務器整合的想法,它的做法是在一個機箱大小的空間內放置兩臺服務器,這些做的好處有很多,首先,減小了占地面積。其次,通過讓兩臺服務器共享諸如 電源等設備,來降低設備和能源等方面的投入。
#p#
二、Google App Engine簡介
由于發布S3和EC2這兩個優秀的云服務,使得Amazon已經率先在云計算市場站穩了腳跟,而身為云計算這個浪潮的發起者之一的Google肯定 不甘示弱,并在2008年四月份推出了Google App Engine這項PaaS服務,雖然現在無法稱其為一個革命性的產品,但肯定是現在市面上最成熟,并且功能最全面的PaaS平臺。
Google App Engine 提供一整套開發組件來讓用戶輕松地在本地構建和調試網絡應用,之后能讓用戶在Google強大的基礎設施上部署和運行網絡應用程序,并自動根據應用所承受 的負載來對應用進行擴展,并免去用戶對應用和服務器等的維護工作。同時提供大量的免費額度和靈活的資費標準。在開發語言方面,現支持Java和 Python這兩種語言,并為這兩種語言提供基本相同的功能和API。
功能
在功能上,主要有六個方面:
◆ 動態網絡服務,并提供對常用網絡技術的支持,比如SSL等 。
◆ 持久存儲空間,并支持簡單的查詢和本地事務。
◆ 能對應用進行自動擴展和負載平衡。
◆ 一套功能完整的本地開發環境,可以讓用戶在本機上對App Engine進行開發和調試。
◆ 支持包括Email和用戶認證等多種服務。
◆ 提供能在指定時間和定期觸發事件的計劃任務和能實現后臺處理的任務隊列。
使用流程
整個使用流程主要包括五個步驟:
◆ 下載SDK和IDE,并在本地搭建開發環境。
◆ 在本地對應用進行開發和調試。
◆ 使用GAE自帶上傳工具來將應用部署到平臺上。
◆ 在管理界面中啟動這個應用。
◆ 利用管理界面來監控整個應用的運行狀態和資費。
由于本系列是專注于GAE的實現和設計兩方面,所以不會對GAE的使用有非常深入地介紹,如果希望大家對GAE的使用方面有更深的理解,具體可以參看一下GAE的官方文檔(http://code.google.com/intl/zh-CN/appengine/docs/whatisgoogleappengine.html)。
Google App Engine的主要組成部分
主要可分為五部分:
◆ 應用服務器:主要是用于接收來自于外部的Web請求。
◆ Datastore:主要用于對信息進行持久化,并基于Google著名的BigTable技術。
◆ 服務:除了必備的應用服務器和Datastore之外,GAE還自帶很多服務來幫助開發者,比如:Memcache,郵件,網頁抓取,任務隊列,XMPP等。
◆ 管理界面:主要用于管理應用并監控應用的運行狀態,比如,消耗了多少資源,發送了多少郵件和應用運行的日志等。
◆ 本地開發環境:主要是幫助用戶在本地開發和調試基于GAE的應用,包括用于安全調試的沙盒,SDK和IDE插件等工具。
應用服務器
應用服務器依據其支持語言的不同而有不同的實現。
Python的實現
Python版應用服務器的基礎就是普通的Python 2.5.2版的Runtime,并考慮在在未來版本中添加對Python 3的支持,但是因為Python 3對Python而言,就好比Java2之于Java1,跨度非常大,所以引入Python3的難度很大。在Web技術方面,支持諸如 Django,CherryPy,Pylons和Web2py等Python Web框架,并自帶名為"WSGI"的CGI框架。雖然Python版應用服務器是基于標準的Python Runtime,但是為了安全并更好地適應App Engine的整體架構,對運行在應用服務器內的代碼設置了很多方面的限制,比如不能加載用C編寫Python模塊和無法創建Socket等。
Java的實現
在實現方面,Java版應用服務器和Python版基本一致,也是基于標準的Java Web容器,而且選用了輕量級的Jetty技術,并跑在Java 6上。通過這個Web容器不僅能運行常見的Java Web 技術,包括Servlet,JSP,JSTL和GWT等,而且還能跑大多數常用的Java API(App Engine有一個The JRE Class White List(http://code.google.com/intl/zh-CN/appengine/docs/java/jrewhitelist.html)來 定義那些Java API能在App Engine的環境中被使用)和一些基于JVM的腳本語言,例如JavaScript,Ruby或Scala等,但同樣無法創建Socket和 Thread,或者對文件進行讀寫,也不支持一些比較高階的API和框架,包括JDBC,JSF,Struts 2,RMI,JAX-RPC和Hibernate等。
Datastore
Datastore提供了一整套強大的分布式數據存儲和查詢服務,并能通過水平擴展來支撐海量的數據。但Datastore并不是傳統的關系型數據 庫,它主要以"Entity"的形式存儲數據,一個Entity包括一個Kind(在概念上和數據庫的Table比較類似)和一系列屬性。
Datastore提供強一致性和樂觀(optimistic)同步控制,而在事務方面,則支持本地事務,也就是在只能同一個Entity Group內執行事務。
在接口方面,Python版提供了非常豐富的接口,而且還包括名為GQL的查詢語言,而Java版則提供了標準的JDO和JPA這兩套API。
而且Google已經在今年的Google I/O大會上宣布將在未來的App Engine for Business套件中包含標準的SQL數據庫服務,但現在還不確定這個SQL數據庫的實現方式,是基于開源的MySQL技術,還是基于其私有的實現,這是一個問題。
服務
Memcache
Memcache是大中型網站所備的服務,主要用來在內存中存儲常用的數據,而App Engine也包含了這個服務。有趣的是App Engine的Memcache也是由Brad Fitzpatrick開發。
URL抓取(Fetch)
App Engine的應用可以通過URL抓取這個服務抓取網上的資源,并可以這個服務來與其他主機進行通信。這樣避免了應用在Python和Java環境中無法使用Socket的尷尬。
App Engine應用使用這個服務來利用Gmail的基礎設施來發送電子郵件。
計劃任務(Cron)
計劃服務允許應用在指定時間或按指定間隔執行其設定的任務。這些任務通常稱為Cron job。
圖形
App Engine 提供了使用專用圖像服務來操作圖像數據的功能。圖像服務可以調整圖像大小,旋轉、翻轉和裁剪圖像。它還能夠使用預先定義的算法提升圖片的質量。
用戶認證
App Engine的應用可以依賴Google帳戶系統來驗證用戶。App Engine還將支持OAuth。
XMPP
在App Engine上運行的程序能利用XMPP服務和其他兼容XMPP的IM服務(比如Google Talk)進行通信。
任務隊列(Task Queue)
App Engine應用能通過在一個隊列插入任務(以Web Hook的形式)來實現后臺處理,而且App Engine會根據調度方面的設置來安排這個隊列里面的任務執行。
Blobstore
因為Datastore最多支持存儲1MB大小的數據對象,所以App Engine推出了Blobstore服務來存儲和調用那些大于1MB但小于2G的二進制數據對象。
Mapper
Mapper可以認為就是"Map Reduce"中的Map,也就是能通過Mapper API對大規模的數據進行平行的處理,這些數據可以存儲在Datastore或者Blobstore,但這個功能還處于內部開發階段。
Channel
其實Channel就是我們常說的"Comet",通過Channel API能讓應用將內容直接推至用戶的瀏覽器,而不需常見的輪詢。
除了Java版的Memcache,Email和URL抓取都是采用標準的API之外,其他服務無論是Java版還是Python版,其API都是私有的,但是提供了豐富和細致的文檔來幫助用戶使用。
管理界面
用了讓用戶更好地管理應用,Google提供了一整套完善的管理界面,地址是http://appengine.google.com/ ,而且只需用戶的Google帳戶就能登錄和使用。下圖為其截屏:
圖1. 管理界面(點擊看大圖)
使用這個管理界面可執行許多操作,包括創建新的應用程序,為這個應用設置域名,查看與訪問數據和錯誤相關的日志,觀察主要資源的使用狀況。
本地開發環境
為了安全起見,本地開發環境采用了沙箱(Sandbox)模式,基本上和上面提到的應用服務器的限制差不多,比如無法創建Socket和 Thread,也無法對文件進行讀寫。Python版App Engine SDK是以普通的應用程序的形式發布,本地需要安裝相應的Python Runtime,通過命令行方式啟動Python版的Sandbox,同時也可以在安裝有PyDev插件的Eclipse上啟動。Java版App Engine SDK是以Eclispe Plugin形式發布,只要用戶在他的Eclipse上安裝這個Plugin,用戶就能啟動本地Java沙箱來開發和調試應用。
編程模型
因為App Engine主要為了支撐Web應用而存在,所以Web層編程模型對于App Engine也是最關鍵的。App Engine主要使用的Web模型是CGI,CGI全稱為"Common Gateway Interface",它的意思非常簡單,就是收到一個請求,起一個進程或者線程來處理這個請求,當處理結束后這個進程或者線程自動關閉,之后是不斷地重 復這個流程。由于CGI這種方式每次處理的時候,都要重新起一個新的進程或者線程,可以說在資源消耗方面還是很厲害的,雖然有線程池(Thread Pool)這樣的優化技術。但是由于CGI在架構上的簡單性使其成為GAE***的編程模型,同時由于CGI支持無狀態模式,所以也在伸縮性方面非常有優 勢。而且App Engine的兩個語言版本都自帶一個CGI框架:在Python平臺為WSGI。在Java平臺則為經典的Servlet。最近,由于App Engine引入了計劃任務和任務隊列這兩個特性,所以App Engine已經支持計劃任務和后臺進程這兩種編程模型。
限制和資費
首先,談一下App Engine的使用限制,具體請看下表:
類別 | 限制 |
Datastore中每個對象的大小 |
1MB |
每個開發者所擁有的項目 |
10個 |
每個項目的文件數 |
1000個 |
每個項目代碼的大小 |
150MB |
每個請求最多執行時間 |
30秒 |
Blobstore(二進制存儲)的大小 |
1GB |
HTTP Response的大小 |
10MB |
表1. App Engine的使用限制
雖然這些限制對開發者是一種障礙,但對App Engine這樣的多租戶環境而且卻是非常重要的,因為如果一個租戶的應用消耗過多的資源的話,將會影響到在臨近應用的正常使用,而App Engine上面這些限制就是為了是運行在其平臺上面應用能安全地運行著想,避免了一個吞噬資源或惡性的應用影響到臨近應用的情況。除了安全的方面考慮之 后,還有伸縮的原因,也就是說,當一個應用的所占空間(footprint)處于比較低的狀態,比如少于1000個文件和大小低于150MB等,那么能夠 非常方便地通過復制應用來實現伸縮。
接著,談一下資費情況,App Engine的資費情況主要有兩個特點:其一是免費額度高,現有免費的額度能支撐一個中型網站的運行,且不需付任何費用。其二是資費項目非常細粒度,普通 IaaS服務資費,主要就是CPU,內存,硬盤和網絡帶寬這四項,而App Engine則除了常見的CPU和網絡帶寬這兩項之外,還包括很多應用級別的項目,比如:Datastore API和郵件API的調用次數等。具體資費的機制是這樣的:如果用戶的應用每天消費的各種資源都低于這個額度,那們用戶無需支付任何費用,但是當免費額度 被超過的時候,用戶就需要為超過的部分付費。因為App Engine整套資費標準比較復雜,所以在這里就主要介紹一下它的免費額度,具體請看下表:
類型 |
數量(每天) |
郵件API調用 |
7000次 |
傳出(outbound)帶寬 |
10G |
傳入(inbound)帶寬 |
10G |
CPU時間 |
46個小時 |
HTTP請求 |
130萬次 |
Datastore API |
1000萬次 |
存儲的數據 |
1G |
URL抓取的API |
657千次 |
表2. App Engine的免費額度表
從上面免費額度來看,除了存儲數據的容量外,其它都是非常強大的。
#p#
三、Google App Engine架構
設計理念
App Engine在設計理念方面,主要可以總結為下面這五條:
◆ 重用現有的Google技術:大家都知道,重用是軟件工程的核心理念之一,因為通過重用不僅能減低開發成本,而且能簡化架構。在App Engine開發的過程中,重用的思想也得到了非常好的體現,比如Datastore是基于Google的bigtable技術,Images服務是基于 Picasa的,用戶認證服務是利用Google Account的,Email服務是基于Gmail的等。
◆ 無狀態:為了讓更好地支持擴展,Google沒有在應用服務器層存儲任何重要的狀態,而主要在datastore這層對數據進行持久化,這樣當應用流量突然爆發時,可以通過為應用添加新的服務器來實現擴展。
◆ 硬限制:App Engine對運行在其之上的應用代碼設置了很多硬性限制,比如無法創建Socket和Thread等有限的系統資源,這樣能保證不讓一些惡性的應用影響到與其臨近應用的正常運行,同時也能保證在應用之間能做到一定的隔離。
◆ 利用Protocol Buffers技術來解決服務方面的異構性:應用服務器和很多服務相連,有可能會出現異構性的問題,比如應用服務器是用Java寫的,而部分服務是用 C++寫的等。Google在這方面的解決方法是基于語言中立,平臺中立和可擴展的Protocol Buffer,并且在App Engine平臺上所有API的調用都需要在進行RPC(Remote Procedure Call,遠程方面調用)之前被編譯成Protocol Buffer的二進制格式。
◆ 分布式數據庫:因為App Engine將支撐海量的網絡應用,所以獨立數據庫的設計肯定是不可取的,而且很有可能將面對起伏不定的流量,所以需要一個分布式的數據庫來支撐海量的數據和海量的查詢。
組成部分
圖1. GAE的架構圖(圖源自參[6])
簡單而言,其架構可以分為三個部分:前端,Datastore和服務群:
前端
共包括四個模塊:
◆ Front End:既可以認為它是Load Balancer,也可以認為它是Proxy,它主要負責負載均衡和將請求轉發給App Server(應用服務器)或者Static Files等工作。
◆ Static Files:在概念上,比較類似于CDN(Content Delivery Network,內容分發網絡),用于存儲和傳送那些應用附帶的靜態文件,比如圖片,CSS和JS腳本等。
◆ App Server:用于處理用戶發來的請求,并根據請求的內容來調用后面的Datastore和服務群。
◆ App Master:是在應用服務器間調度應用,并將調度之后的情況通知Front End。
Datastore
它是基于BigTable技術的分布式數據庫,雖然其也可以被理解成為一個服務,但是由于其是整個App Engine唯一存儲持久化數據的地方,所以其是App Engine中一個非常核心的模塊。其具體細節將在下篇和大家討論。
服務群
整個服務群包括很多服務供App Server調用,比如Memcache,圖形,用戶,URL抓取和任務隊列等。
Python版和Java版App Engine在實現方面的區別
因為大多數服務都可以被這兩個版本共享,所以兩者之間的區別主要集中在App Server端,Python版App Server應該是經過Google修改的Python Runtime,版本號應該是2.5.2,而Java版App Server是基于Jetty 6的,因為它的體積和最常用的Tomcat相比更嬌小,這樣能使得一臺服務器支持更多的應用,而且其應該經過Google的一定的修改。
流程
在這里舉一個普通的HTTP請求的處理流程為例:
◆ 用戶發送一個HTTP請求。
◆ Front End接受這個請求,并將這個請求轉發給一個空閑的App Server。
◆ App Server會處理這個請求。
◆ 檢查用于處理這個請求的Handler是不是已經被初始化了,如果沒有的話,需要對這個Handler進行初始化。
◆ 調用服務群的用戶認證服務來對用戶進行認證,如果失敗的話,需要終止整個請求的處理工作,并返回用戶無法被認證的信息。
◆ 查看這個請求所需的數據是否已經緩存在Memcahe中,如果沒有的話,將對Datastore發出查詢請求來得到數據。
◆ 通過整合上步得到數據來生成相關的HTML,并返回給用戶。
◆ 由于HTML里面會包含對一些靜態文件的引用,比如圖片和CSS等,所以當用戶收到HTML之后,還會通過Front End對Static Files里面存儲的靜態文件進行讀取。
四、Database設計
使用方面
首先,在編程方面,Datastore是基于"Entity(實體)"這個概念,而且Entity和"對象"這個概念比較類似,同時Entity可 以包括多個Property(屬性),Property的類別有整數,浮點和字符串等,比如,可以設計一個名為"Person"的Entity,它包含名 為"Name"的字符串Property和名為"Age"的整數Property。由于Datastore是"Schema-less"的,所以數據的 Schema都由應用維護,而且能非常方便地對一個Entity所包含的屬性進行增刪和修改。在存儲方面,一個Entity的實例可以被認為是一個普通 的"Row(行)",而包含所有這種Entity的實例的Table被稱為Kind,比如,所有通過"Person"這個Entity生成實例,比如小 吳,小朱和小華等,它們都會存放在同一個名為"Person"的Kind中。在結構方面,雖然也能通過特定的方式在Datastore中實現關系型結構, 但是Datastore在設計上是為層次(Hierarchical)性結構"度身定做"的,有Root Entity和Child Entity之分,比如,可以把"Person"作為Root Entity(父實體),"Address"作為"Person"的Child Entity,兩者合在一起可以稱為一個"Entity Group"。這樣做的好處是能將這兩個實體集中一個BigTable本地分區中,而且能對這兩個實體進行本地事務。
接下來,將談一下Datastore支持那些高級功能:其一是提供名為GQL(Google Query Language)的查詢語言,GQL是SQL的一個非常小的子集,包括對">","<"和"="等操作符。其二是App Engine會根據代碼中查詢語句來自動生成相應Index,但不支持對Composite Index生成。其三是雖然由于Datastore分布式的設計,所以在速度方面和傳統的關系型數據庫相比一定的差距,但是Google的架構師保證大部 分對Datastore的操作能在200ms之內完成,同時也得益于它的分布式設計,使得它在擴展性方面特別出色。其四是Datastore也支持在實體 之間創建關系,比如在Python版App Engine中可以使用ReferenceProperty在實體間構建一對多和多對多的關系。
下表為Datastore和傳統的關系型數據庫之間的比較:
Datastore |
關系型數據庫 | |
SQL支持 | 只支持一些基本的查詢 |
全部支持 |
主要結構 | 層次(Hierarchical) |
關系 |
Index | 部分可自動創建 |
手動創建 |
事務 | 只支持在一個Entity Group內執行 |
支持 |
平均執行速度(ms) | 低于200 |
低于100 |
擴展型 | 非常好 |
很困難,而且需要進行大量的修改 |
表1. Datastore和關系型數據庫之間的比較
***,在接口方面,Python版提供一套私有的API和框架,在基本功能方面,比較容易學習,但在部分高級功能方面,比如關系和事務等方面,學習 難度很高;Java版的API是基于JDO和JPA這兩套官方的ORM標準,但是和現在事實的標準Hibernate有一定的差異。
實現方面
在實現方面,Datastore是在BigTable的基礎上構建的,所以本段會首先重新介紹一下BigTable,之后會介紹Datastore的兩個組成部分:Entities Table和Index,***會講一下它在事務和備份這兩方面所采用的機制。
BigTable
在本系列的***篇已經按照Google的Paper對BigTable技術做了一定的介紹,但其實BigTable本身其實沒有之前介紹的那樣復 雜,其實就是一個非常巨大的Table,這也是是它之所以名為"BigTable"的原因,而且結構就像圖1那樣非常簡單,就是一個個ROW,每個ROW 都有一個Name和一組Cloumn,但是為了支持海量的數據,它將這個大的Table進行分片(Sharding)處理,每臺服務器存儲一個海量的 Table的一小部分,并且為了查詢效率,會對這個Table進行排序。就像App Engine的創始人之一Ryan Barrett所說的那樣"BigTable is a sharded, sorted array "。
圖1. BigTable簡化版模型
在功能方面,首先,BigTable支持基本的CRUD操作,也就是增加(Create),查詢(Read),更新(Update)和刪除(Delete)。其次支持對Single-Row的事務與基于前綴和范圍的掃描。
Entities Table
它是Datastore最核心的Table,是以BigTable的形式存在的,主要用于存儲所有的Entity,而且是格式非常簡單,每行都會有 一個Row Name,也稱為Entity Key(可認為它是一個Entity的Primary Key),而且只有唯一一個Column,主要用于存放被序列化的Entity。每個Entity的Key的生成是基于它的父Entity(如果有的話) 和其父至上的Entity,直到其Root Entity。以下圖為例,timmy的父Entity是jane,jane的父Entity兼Root Entity是Ethel,所以***timmy的Entity Key是"/Grandparent:Ethel/Parent:Jane/Child:Timmy"。
圖2. Entity Key的例子
Index
Index主要是為方便和加速查詢而生的,所以在切入Index之前,先介紹一下Datastore主要支持那些查詢,主要有三類:其一是基于Kind的,其二是基于Property值的,其三是基于多個Property值的。
Index表也是以BigTable的形式存在,但是和上面的Entities Table是分離的,主要用來單獨存放那些需要被Index的數據,而且由于怕Index表體積太大,所以不會有時將其放置在內存中以提升查詢速度。
主要有下面這幾種Index表:
◆ Kind Index:用于加速那些用于獲取所有屬于某個Kind的Entity的查詢,比如把所有屬于Person這個Kind的Entity,包括小吳,小朱和 小華等提取出來,Kind Index表每行有Kind和Entity Key這兩個列,此Index會有系統自動生成。
◆ Single-property Index:用于加速那些基于單一屬性值的查詢,比如要找出所有Age在20之下的Person,Age就是所謂的那個單一屬性值,Single- property Index表每行除了Kind和Entity Key之外,還有屬性名和屬性值這兩個列,此Index也會有系統自動生成,還會根據升降序的不同,生成兩個表。
◆ Composite Index:用于加速那些基于對多個屬性值的查詢,Composite Index表基本和上面的Single-property Index表非常類似,但是每行包括多個屬性名和屬性值,而且由于此Index消耗資源非常多,所有由開發人自己確定是不是需要這個Index,系統不自 動生成。
事務
原則上所有對單一Entity的Write操作都是事務的,并基于上面提到的BigTable的Single-Row事務和Optimistic Concurrency Control這兩個技術,下面是流程:首先,系統會讀這個Entity的Committed Timestamp(提交時間戳),Write會以串行(Serialized)的形式寫入到BigTable的日志中,之后,系統會將日志更新到 BigTable的表中,如果成功的話,系統會更新這個Entity的Committed Timestamp,但如果系統發現在更新之前,Committed Timestamp發生了變化,也就是說另一個事務在這個事務執行過程中已經對這個Entity進行了操作,在這個時候,系統會重新執行這個事務。由于在 整個事務過程采用Optimistic Concurrency Control,而不是Locking,所以在吞吐量方面表現不錯。
如果要對多個Entity執行事務,那就需要將這幾個Entity設為一個Entity Group,也就意味著將這幾個Entity放在同一臺物理機上。在執行的時候,會將以Root Entity的Committed Timestamp為準來對所有參與事務的Entity進行和上面差不多的事務操作。
備份
與BigTable基于Row級別的備份不同的是,Datastore是基于Enity Group級別,而且采用Paxos算法,所以Datastore的備份方法比BigTable的更安全。
總體而言,Datastore在設計理念上和傳統的關系型數據庫有很大的不同,所以其在反應速度和寫數據方面不是***的,但是現在Web應用以讀為 主,而且需要能通過簡單的擴展就能支持其海量的數據,而這兩點卻是Datastore所擅長,所以Datastore非常適合支撐Web應用。
對于Googe App Engine架構的介紹就到這里了,另外其實還有很多網站的架構也是比較經典的,像我以前介紹過的Facebook架構、MySpace架構、優酷架構、Twitter架構、Flickr架構等等,有興趣的朋友可以關注一下這方面的技術資料,因為“云”上來了,這些都是我們學習的基礎。
***感謝作者吳朱華,膜拜一下....
原文:http://peopleyun.com/
【編輯推薦】