面向星球的網絡搜索:Google集羣架構


備註:

   最近在學習hadoop,Google關於集羣架構的論文不可不讀。於是找到其英文原文以及網絡上資源對照翻譯。原文出處:http://research.google.com/archive/googlecluster.html


面向星球的網絡搜索:Google集羣架構

Luiz Andre Barroso   Jeffrey Dean   Urs Holzle   Google

爲了能夠支持可擴展的並行化,google的網絡搜索應用讓不同的查詢由不同的處理器處理,同時通過劃分全局索引,使得單個查詢可以利用多個處理器處理。針對所要處理的工作負載類型,google的集羣架構由15000個普通pc機和容錯軟件組成。這種架構達到了很高的性能,同時由於採用了普通pc機,也節省了採用昂貴的高端服務器的大部分花費。

很少有網絡服務的單個請求像搜索引擎佔用那樣多的計算資源。平均來看,在google上的每次查詢需要讀取數百m的數據耗費數10億的cpu指令循環。爲了能夠支持峯值在每秒數千次請求流,需要與世界上最大的超級計算機規模相當的硬件設施。通過容錯性軟件將15000個普通pc機聯合起來,提供了一種比使用高端服務器更廉價的解決方案。

本文我們將介紹google的集羣架構,討論那些影響到設計方案的最重要的因素:能效和性價比。在我們的實際操作中,能效實際上是一個關鍵的度量標準,因爲數據中心的電力是有限的,因此電力耗費和製冷成爲運作中的關鍵。

我們的應用本身可以很容易進行並行化:不同的查詢可以運行在不同的處理器上,同時全局索引也劃分的使得單個查詢可以使用多個處理器。因此,處理器的性價比比峯值性能變得更重要。同時,google的應用是面向吞吐率的,可以更有效的利用處理器提供的並行化,比如並行多線程(SMT),或者多核處理器(CMP)。

Google架構概覽

Google的軟件架構來源於兩個基本的觀點。首先我們需要在軟件層面提供可靠性,而不是通過硬件,這樣我們就可以使用普通的pc構建廉價的高端集羣。其次,我們不斷的裁剪設計是爲了達到最好的總體請求吞吐率,不是爲了提高服務器的峯值響應時間, 因爲我們可以通過並行化獨立的請求來控制響應時間。

我們相信使用不可靠的廉價pc來構建可靠的計算設施可以達到最好的性價比。通過在不同的機器上備份服務,以及自動化的故障檢測和錯誤處理,爲我們的環境提供軟件級的可靠性。這種軟件級的可靠性在我們的系統設計中幾乎隨處可見。檢查一下一次查詢處理的控制流程,有助於理解這種高級的查詢服務系統,同時也有助於對於可靠性考慮的理解。

Google的一次查詢

當用戶在google中輸入一次查詢,用戶瀏覽器首先通過DNS進行域名解析,將www.google.com轉換爲ip地址。爲了對查詢可以進行更有效的處理,我們的服務由分佈在世界各地的多個集羣組成。每個集羣大概有數千個機器,這種地理上的分佈可以有效的應付災難性的數據中心失敗比如地震,大規模的停電。基於DNS的負載平衡系統,會計算用戶的與每一個物理集羣地理上的距離來選擇一個合適的物理集羣。負載平衡系統,需要最小化請求往返時間,同時要考慮各個集羣的可用容量。

用戶瀏覽器然後給這些集羣中的一個發送一個http請求,之後,對於該集羣來說,所有的處理都變成了本地化的。在每個集羣中有一個基於硬件的負載平衡器監控當前可用的google web   servers(GWS)集合,並在這個集合上將本地的請求處理進行負載平衡。收到一個請求之後,GWS協調這個查詢的執行,並將結果格式化爲html語言。圖1表示了這個過程。


查詢執行由兩個主要階段組成,第一個階段,索引服務器查閱倒排索引(將每個查詢詞映射到匹配的文檔列表)。索引服務器然後決定相關的文檔集合,通過對每個查詢詞匹配的文檔列表求交集,爲每個文檔計算出一個相關性的分值,這個分值決定了在輸出結果中的排序。

搜索的過程非常具有挑戰性,因爲需要處理海量數據:原始網頁文檔通常具有數十T的未壓縮數據,從原始數據中導出的倒排索引本身也有好幾T的數據。幸運的是,通過將索引劃分到不同的片段,可以將搜索高度並行化,每個片段具有從全布索引中隨機選擇的一個文檔子集。一組機器負責處理對於一個索引片段的請求,在整個集羣中每個片段都會有這樣的一組機器與之對應。每個請求通過中間負載平衡器選擇組內機器中的一個,換句話說每個查詢將會訪問分配到每個片段的一臺機器(或者是一組機器的子集)。如果一個片段的備份壞了,負載平衡器將會避免在查詢時使用它,我們的集羣管理系統的其他組件將會嘗試修復它,實在不行就用另一臺機器來取代它。停工期間,系統的容量需要減去那臺壞掉的機器所代表的容量。然而,服務仍然是未中斷的的,索引仍然是可用的。

第一階段的查詢執行最終輸出一個排過序的文檔標識符列表。第二階段則通過獲取這個文檔列表,然後計算出所有文檔的標題和url以及面向查詢內容的文檔摘要。文檔服務器處理這項任務,從硬盤中獲取文檔,抽取標題以及查詢關鍵詞在文檔中的出現片段。像索引查找階段,這裏的策略也是對文檔進行劃分,主要通過:隨機分佈文檔到不同的小片段;針對每個片段的處理具有多個服務器作爲備份;通過一個負載平衡器分發請求。文檔服務器必須能夠訪問一個在線的低延時的整個網絡的網頁的副本。實際上由於對於這個副本的訪問需要性能及可用性,所以google實際上在集羣中存儲了整個web的多個副本。

除了索引和文檔服務階段,GWS在收到查詢時還會初始化幾個其他的輔助任務,比如將查詢發送給拼寫檢查系統,廣告系統生成相關廣告。當所有階段完成後,GWS生成html輸出頁面,然後返回給用戶瀏覽器。

使用備份進行容量擴充和容錯

我們對系統進行了一些結構化以保證對於索引和其他響應查詢相關的數據結構是隻讀的:更新是相對不頻繁的,這樣我們就能通過將查詢轉移到一個服務備份來安全的進行更新。 這條原則,使得我們避免了很多在通用數據庫中出現的一致性問題。

我們也盡力挖掘出大量應用中的固有的並行性:比如我們將在一個大索引中的匹配文檔的查詢轉化爲針對多個片段中的匹配文檔的多個查詢加上開銷相對便宜的歸併步驟。類似的,我們將查詢請求流劃分爲多個流,每個由一個集羣來處理。增加爲每個處理索引片段的機器組增加機器來增加系統容量,伴隨着索引的增長增長片段的個數。通過將搜索在多個機器上並行化,我們降低了響應一個查詢的必需的平均延時,將整個計算任務劃分在多個cpu和硬盤上。因爲獨立的片段相互之間不需要通信,所以極速比幾乎是線性的。換句話說,單個索引服務器的cpu速度不會影響整個搜索的整體性能,因爲我們可以增加片段數來適應慢的cpu,因此我們的硬件選擇主要關注那些可以爲我們的應用提供出色的請求吞吐率的機器,而不是可以提供最高的單線程性能的那些。

簡單來說,google的集羣主要遵循下面三個主要設計原則:

1、軟件可靠性。我們沒有選擇硬件性容錯,比如採用冗餘電源,RAID,高質量組件,而是專注於軟件可靠性。

2、使用備份得到更好的吞吐率和可用性。因爲機器本身是不可靠的,我們備份我們的內部服務在很多機器上。通過備份我們得到了容量,與此同時也得到了容錯,而這種容錯幾乎是免費的。

3、性價比重於峯值性能。我們購買當前最具性價比的cpu,而不是那些具有最高絕對性能的cpu。

4、使用普通pc降低計算花費。這樣我們可以爲每一個查詢提供更多的計算資源,在ranking算法中使用更昂貴的技術,可以搜索文檔的更大的索引。

使用商業化部件

Google的機櫃是專門定製的,由兩面組成,總共放置了40到80個基於80x86的服務器(每側包含20個20u或者40個10u服務器) 。我們對於性價比的偏愛,使得我們選擇自己組裝的桌面pc通過它們的組件,除了選擇大的硬盤驅動器。目前的服務中使用了好幾個cpu產品,從533m intel-celeron 到雙核1.4G Intel奔三服務器。每個服務器包含一個或者多個IDE硬盤,每個80g空間。與文檔服務器相比,索引服務器通常具有更少的磁盤空間,因爲它的負載類型是對cpu更敏感。在機櫃一側的服務器通過一個100m 以太網交換機相連,該交換機通過一個或者兩個GB級的鏈路與一個核心的GB交換機相連,該核心交換機連接所有的機櫃。

我們的根本選擇標準是單次查詢花費,可以表示爲性能/資金花費總和(包括折舊)+管理花費(主機,系統管理,維修)。實際來看,一個服務器的壽命通常不會超過2,3年,因爲與新機器相比,無法在性能上保持一致。三年前的機子性能上要遠遠落後於當前的機子,對於包含這兩類機器的集羣,很難達到合適的負載分佈和配置。有了這個相對的短期分攤週期,可以看到設備的花費在總的開銷中佔到相當的一部分。

因爲google服務器是專門定製的,我們可以使用基於pc的服務器機櫃價格做一個展示。比如在2002年,一個88 個雙核cpu 2G intle xeon,2G內存,80G硬盤的機櫃在RackSaver.com上的價格大概是27800$,轉換成三年週期每月的花費將是7700$。剩下的主要花費是人力和hosting。

設備花費的相對重要性使得采用傳統的服務器解決方案並不適合解決我們的問題,因爲雖然它們可以提高性能,但是降低了性價比。比如4處理器的主板是很昂貴的,由於我們的應用已經進了很好的並行化,這樣的主板不需要額外的花費就能獲得很好的性能.類似的,儘管SCSI硬盤更快也更可靠,但是它們通常比同樣容量的IDE硬盤貴2-3倍。

使用基於基於廉價的PC的集羣比使用高端多處理器服務器在成本上的優勢是非常明顯的,至少對於像我們這樣的高並行化應用來說。上面例子中的27800$的機櫃包含176個2G Xeon CPU,176G內存,7T硬盤空間。與此相比,一個典型的x86服務器具有8個2GCPU,64G內存,8T硬盤空間,花費大概758000$。換句話說,這個服務器貴了3倍,但是cpu只是原來的1/22,內存是1/3,硬盤空間稍微多了點。價格的差距,主要是源於更高的互聯網絡帶寬和可靠性。但是google的高度冗餘架構並不依賴於這兩個中的任何一個。

管理數千臺中型PC機和一些高端多處理器服務器將會帶來完全不同的系統管理和維修費用。然而,對於一個相對同構的的應用來說,大部分的服務器只用來運行少數應用中的一個,這些開銷是可管理的。加速安裝和更新工具都是可用的,維護1000臺和100臺服務器所需的時間和成本相差並不大,因爲所有的機器都具有相同的配置。類似的,通過使用可擴展的應用監控系統,監控的花費伴隨這集羣的大小增長也不會有太大的增長。另外,我們可以通過批處理修復將修復的開銷保持在一個較低的水平,同時保證我們可以很容易的替換掉那些具有高損壞率的組件,比如硬盤和電源。

電力問題

如果沒有特殊的高密度包裝,電力消耗和製冷設備將會成爲一個挑戰。一箇中型的1.4G奔三服務器在有負載情況下,通常要耗費90w直流電:55w給cpu,10w給硬盤,25w給DRAM加電和主板,對於一個ATX電源,通常具有75%的效率,這樣轉化成交流電就是120w,每個機櫃就需要10kw。一個機櫃需要25 ft2 的空間,這樣算下來,用電的密度就是400w/ft2。如果採用高端處理器,一個機櫃的用電密度可以超過700w/ft2。

不幸的是,通常的商業數據中心電力密度在70-150w/ft2之間,遠遠低於pc集羣的需求。這樣,如果低端pc集羣使用相對直接的包裝方式,就需要特殊的製冷和額外的空間來降低用電密度使得與標準數據中心兼容。因此只要機櫃還存放在標準數據中心中,如果想要往機櫃裏增加服務器就會在實際部署中收到限制。這種情況就使得我們考慮降低單服務器的電力使用是否是可能的。

對於大規模集羣來說,低功耗服務器是非常具有吸引力的。但是我們必須要牢記以下幾點:降低電力是迫切的,但是對於我們的應用來說,不能帶來性能上的懲罰,我們關心的是每單元性能的瓦特,不是單純的瓦特,第二,低功耗的服務器必須不能太過昂貴,因爲服務器的折舊花費通常要超過電力的花費。前面提到的10kw機櫃,每月大概消耗10mwh的電力(包括製冷的開銷),假設每kwh電15美分,這樣每月需要花費1500$,與折舊的7700$相比並不算大。因此低功耗服務器不能夠多於我們通過採用常規pc節省下的那部分花費。

硬件級別的應用特點

檢查我們應用的各種架構特點可以幫助我們搞清楚哪種硬件平臺可以爲我們的索引查詢系統提供最高的性價比。我們着重於索引服務器的特點,該模塊的性價比對於整體的性價比起着主導性的作用。索引服務器的任務主要包括:對倒排索引中的壓縮數據進行解壓,找到與一個查詢相匹配的文檔集合。表1展示了一些索引服務器程序的基本的指令級別的度量,程序運行在一個1G雙核奔三系統上。


考慮到奔三每個circle基本上可以處理三條指令,可以看到該應用程序的CPI(cycles per instruction)稍微偏高。我們可以預見到這種行爲,考慮到我們的應用程序使用了很多動態數據結構而控制流是依賴於數據的,這樣就會產生大量的很難預測的分支。事實上,如果相同的工作負載在奔四處理器上運行時,CPI幾乎增長了2倍,分支預測幾乎相同,儘管奔四具有更強大的指令並行和分支預測功能。可見,在這種工作負載類型下,並沒有太多的指令級並行性可供挖掘。測量結果顯示,對於我們的應用來說,出現在處理器中的大量的亂序不確定性執行成爲降低程序性能的關鍵點。

對於像索引服務器這樣的應用來說,更合適的挖掘並行性的方式應該是提高平凡的計算並行性。系統在處理每個查詢時共享只讀數據,建立只需要很少通信的工作單元。我們在集羣級別上通過部署大量的廉價節點取代少量的昂貴節點來發揮這個優勢, 挖掘在微架構級別上的線程級並行性看起來也是可行的。並行多線程(SMT)和多處理器架構(CMP)都是面向線程級的並行性,都可以大大提高我們的服務器的性能。一些針對Intel Xeon處理器的早期實驗表明通過使用兩個上下文的SMT比單個上下文具有30%的性能提升。

我們相信對於CMP系統提升的潛力應該是更大的。在CMP的設計中,採用多個簡單的,按序執行的,短流水線核取代複雜的高性能核。如果我們的應用具有很少的指令級並行性(ILP),那麼由於按序執行所帶來的性能懲罰也是很小的。同時短流水線將可以減少甚至排除分支預測失敗所造成的影響。線程級的並行性伴隨着核的增長可以呈現出接近線性的加速比,同時一個合理大小的共享L2 cache將會加速處理器間的通信。

內存系統

表1也描述了主存系統的性能參數,我們可以觀察到對於指令cache和指令tlb具有良好的性能,由於使用了較小的內層循環代碼。索引數據塊不具有時間局部性,因爲索引數據大小變化劇烈同時對於索引的數據塊訪問模式是不可預測的。然而對於一個索引數據塊的訪問可以從空間局部性上獲益,這種局部性能夠通過硬件預取或者大的緩存line開拓出來。這樣如果使用相對合適cache大小就可以得到好的全局cache命中率。

內存帶寬看起來並不會成爲一個瓶頸。我們估計奔騰系列處理器系統的內存帶寬使用率可以很好的控制在20%以下。主要是由於對於索引數據的每個緩存行,需要放到處理器cache裏,這需要大量的計算資源,此外在數據獲取中還存在天然的依賴關係。在很多情況下,索引服務器的內存系統行爲正如TPC-D(Transaction Processing Performance Counicil’s benchmark D)所報告的那樣。對於這種工作負載類型,採用一個相對合適的L2cache大小,短的L2 cache和內存延時,長的(比如128字節)cache line可能是最有效的。

大規模多處理

正如前面提到的,我們的設備是一個由大量廉價pc組成的龐大集羣,而不是少數大規模的共享內存機組成的。大規模共享內存機主要用於在計算通信比很低的時候,通信模式或者數據劃分是動態或者難預測的,或者總的花費使得硬件花費顯得很少的時候(由於管理日常費用和軟件許可證價格)。在這些情況下,使得它們的高價格變得合理。

在google,並不存在這樣的需求,因爲我們通過劃分索引數據和計算來最小化通信和服務器間的負載平衡。我們自己開發需要的軟件,通過可擴展的自動化和監控來降低系統管理的日常費用,這些使得硬件花費成爲整個系統開銷中顯著的一塊。另外,大規模的共享內存機器不能很好的處理硬件或者軟件的失敗。這樣大部分的錯誤可能導致整個系統的crash。通過部署大量的多處理器機,我們可以將錯誤的影響控制在一個小的範圍內。總的來看,這樣的一個集羣通過明顯的低成本解決了我們的服務對於性能和可用性的需求。

初看起來,好像很少有應用具有像google這樣的特點,因爲很少有服務需要數千臺的服務器和數pb的存儲。然而可能有很多的應用需要使用基於pc的集羣架構。一個應用如果關注性價比,能夠運行在不具有私有狀態的多個服務器上(這樣服務器就可以被複制),它都有可能從類似的架構中獲益。比如一個高容量的web服務器或者一個 計算密集型的應用服務器(必須是無狀態的)。這些應用具有大量的請求級並行性(請求可以劃分在在獨立的服務器上處理)。事實上,大的web站點已經採用這樣的架構。

在google規模上,大規模服務器的並行化的一些限制確實變得明顯起來,比如商業數據中心在製冷容量上的限制,當前的cpu對於面向吞吐率的應用所做的優化還遠遠不夠。雖然如此,通過使用廉價pc,明顯地提高了我們可以爲單個查詢所能支付的計算量。因此有助於幫助我們提高成千上萬的用戶的網絡搜索體驗。

致謝

在這些年裏,很多人爲google的硬件架構做出了重要的貢獻。在這裏,特別感謝Gerald Aigner ,Ross Biro,Bogdan Cocosel 和Larry Page所做的工作。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章