開始時,Picnik使用了一個開源項目,Mogilefs,用于文件存儲。我們的大部分服務(wù)器都有幾個空閑的驅(qū)動器插槽,我們在這些插槽上接入大容量的SATA驅(qū)動器,用于 Mogilefs文件存儲。大部分后臺服務(wù)都是CPU密集型的,所以與這些I/O密集型的存儲配合得相當好。這個策略工作得很好,但存儲需求超過CPU需求之后,就不行了,這時候,Amazon的S3服務(wù)看起來好像是我們擴展存儲的最容易也最便宜的方法。
在測試S3之前,我們實際上并沒有對費用用做多少評估,一方面是當時并沒有太多的云計算可供選擇,另外就是一些令人尊敬的工程師也極力推薦S3,最后,我們從來就沒指望會大量使用。
因為開發(fā)者的機器沒有使用Mogile,所以已經(jīng)有一個框架用于接口不同的文件存儲系統(tǒng),這樣一來,增加S3的支持就相對容易些。事實上,僅用了大約一天就實現(xiàn)了S3支持,又測試了一兩天,然后就將其打包到我們的每周例行發(fā)布中了。這種實現(xiàn)的簡易性也是我們選擇S3的另一個關(guān)鍵因素。
最初,我們計劃只將最早的文件遷移到S3,這些文件是從2007年12月份開始的,因為這些文件訪問頻率比較低,不用怎么擔心性能和可用性方面的問題。這個模式非常棒,S3看起來性能也很好。
唯一的不足,我們從Mogilefs中遷移文件的速度不夠快,沒有跟上文件增長的速度。而且 Mogilefs也開始出現(xiàn)一些性能問題了。我們的解決方案跟其他幾家大型網(wǎng)站一樣:將文件直接存儲到S3。開始時,只將一小部分新文件直接存儲到S3,然后逐漸增加,一直到絕大部分新文件都流向Amazon。這樣,事情又搞定了,我們就轉(zhuǎn)去解決其他問題了。
雖然S3已經(jīng)相當可靠了,仍然出現(xiàn)了一些值得注意的問題。我們遇到的第一個問題是最終一致性(eventual consistency)問題,基本上,這意味著不能保證立即讀取剛寫入的文件,在寫入到西雅圖的S3集群后,再試圖從EC2中讀,這個問問題會更嚴重。通過將所有的文件訪問都從我們在西雅圖的數(shù)據(jù)中心代理而使這個問題有所緩和,但這樣一來,我們的帶寬就增加了。
我們遇到的第二個問題是Amazon?返回HTTP500錯誤,我們的代碼能夠?qū)Σ怀晒Φ恼埱筮M行重試,這在大多數(shù)情況下工作良好。每一兩周,我們都會遇到錯誤突然爆發(fā),以至于重試邏輯都不起作用了。這種爆發(fā)會持續(xù)一小時左右。一天,我正在查看發(fā)生錯誤的關(guān)鍵字(keys),注意到這些關(guān)鍵字都有相同的前綴!結(jié)果證明,S3是基于關(guān)鍵字的范圍對數(shù)據(jù)進行分區(qū)的,這意味著維護(如增減某個分區(qū)容量)會導(dǎo)致某個范圍內(nèi)的關(guān)鍵字大量出錯。Amazon這樣做是為了保持S3的高性能。對我們而言,這種突發(fā)性錯誤更大程度上是種煩惱,因為我們還有Mogilefs在起作用,如果寫到S3失敗,將其寫到Mogile:就是了。隨著增長率趨于穩(wěn)定,這個問題現(xiàn)在已經(jīng)很少出現(xiàn)了,但Mogile仍然在發(fā)揮作用。
其實我們遇到的這些問題是構(gòu)建大規(guī)模系統(tǒng)必然會發(fā)生的,所以 Amazon也用不著掩飾什么。人們很容易忘記,這其實是一個有著很多用戶的規(guī)模巨大的分布式系統(tǒng)。
隨著流量的增長,我們越來越依賴于S3。要是S3宕掉了,一天的大部分時間里,我們的Mogl都無法處理龐大的請求。幸運的是,S3大部分問題都不是發(fā)生在我我們網(wǎng)站的高峰時間,所以 Mogilev還能夠應(yīng)付。我也應(yīng)該提到的是,Mogile在兩種情況下會宕機幾個小時,種情況是修改 MYSQL的表結(jié)構(gòu),還有就是調(diào)試Mogilev的Perl代碼。這種時候,1009%的流量都會壓到S3上,而我們的用戶則從來不知道發(fā)生了什么。
“無限”存儲的一個危險是很容易造成浪費。對我們來說,我并沒怎么注意刪除無用文件的后臺作業(yè)業(yè),對于創(chuàng)建的文件,最終會刪除掉近75%,而無用文件增長起來是很快的。
即使我們曾經(jīng)注意到了這個問題,我們事實上還是決定忽略它。Picnik的每一個人都很忙,而且這看起來也不是什么大不了的問題,再說了,還有更棒的新功能或其他的伸縮性問題需要我們?nèi)リP(guān)注。有趣的是,S3讓我們選擇或者雇用和訓(xùn)練更多的人,或者更簡單,寫張支票就行了。在我們的信用卡月度額度快用光的時候,一切都變了。
經(jīng)過幾個月的調(diào)整、分析和重寫代碼,我們最后拿出了一份清理無用文件的可伸縮方案。首先是數(shù)據(jù)庫對無用文件記錄進行清理,然后在數(shù)據(jù)庫的文件記錄和S3上的關(guān)鍵字列表之間做一個大型的連接操作(a large merge-join),以執(zhí)行實際的刪除。
在實現(xiàn)更好的清理系統(tǒng)的過程中間,我們開始意識到,S3對我們的工作負荷(workload)來說,實際上是非常昂貴的。先前的成本分析完全沒有考慮PUT操作的成本。很多S3的負荷中,存儲成本占了大頭,因為文件上載以后,在隨后的一個很長時段內(nèi),只是偶爾訪問下。正如前面所提到的,我們的負荷是創(chuàng)建大量文件,然后在隨后的幾天里就刪掉了這意味著PUT操作的成本上升了。
意識到這點以后,我們開始努力優(yōu)化Mogilefsl的性能,并且研究高性能的NAS產(chǎn)品。最后,我們實現(xiàn)了一個基于Linux的NFS概念系統(tǒng)作為前端存儲,這意味著只需要在S3上存儲超過1周的大約25%的文件,這些留下來的文件也有了一個對S3來說更加友好的存取模式。
有很長一段時間,我們都不清楚S3是不是仍然合適。盡管更為傳統(tǒng)的NAS硬件看起來貴了點,但如果你對長期存儲需求有信心的話,可以在一年或兩年內(nèi)分期付款。而另一方面,許多創(chuàng)業(yè)公司的CFO(包括我們自己的)都會告訴你,為了保持靈活性和一定程度的自由,多花點兒錢也值得一一這種靈活與自由就是S3提供的。當然,這種靈活性比將此花費算做運維費用還是資本費用更為重要。至于我們所關(guān)心的,就只是運維費用了,因為這直接與流量和功能有關(guān)。
混合計算
Picnik主要的服務(wù)端組件之一是我們的渲染場(render farm)。用戶在Picnik上保存圖片時,經(jīng)常需要在服務(wù)端重建這個圖片。這時,客戶端會向服務(wù)器發(fā)送一大段XML文本描述用戶的編輯操作。Web服務(wù)器收到后,會將所需要的圖片連同XML文本一起打包,并將其加入到渲染作業(yè)隊列中。渲染服務(wù)器獲取該作業(yè),重建圖片,然后將結(jié)果圖片返回給Web服務(wù)器。此時,客戶端處于阻塞狀態(tài),等待服務(wù)器的響應(yīng)。大多數(shù)時間,客戶只需要等待幾秒鐘。
雖然這是可伸縮系統(tǒng)的典型架構(gòu),我們在設(shè)計時仍然考慮到了未來對云計算的需求。這時的渲染服務(wù)器不需要訪問任何內(nèi)部服務(wù),如數(shù)據(jù)庫或存儲服務(wù)器。簡言之,它們非常適合于運行在EC2上,另外,我們已有了一個自己開發(fā)的配置管理和代碼部署系統(tǒng),稱為Server manager。
像S3一樣,實際實現(xiàn)起來既簡單又快速。內(nèi)部的渲染場已經(jīng)考慮到了運行在Xen之上的WM了,所以我需要做的就是一些簡單修改,使渲染服務(wù)器的VM映像適合于EC2的Xen找,然后將其打包為AMI。在映像啟啟動時,首先連接Server manager?獲取需要安裝和運行的組件列表,其中之一是Renderserver,Renderserver用于連接渲染隊列以獲取渲染作業(yè)。我要做的第一件事就是激活兩個實例運行一下看看怎么樣一一棒極了!
第二階段就是去實現(xiàn)云操作的終極目標(loly Grail)了:自動伸縮(auto-scaling)。我們的自動伸縮實現(xiàn)起來還是很容易的,因為所有處理都是通過隊列實現(xiàn)的。由于用戶在等待渲染結(jié)果,所以自動伸縮代碼的目標是維護一個空隊列5。每分鐘都會喚醒Server manager的一個線程,輪詢隊列的統(tǒng)計信息(上一分鐘已做過平衡),然后進行計算,看為了維持閑者和忙者的比例需要做些什么。當然,由于流量和網(wǎng)絡(luò)延遲會有小幅波動,為避免不必要的振蕩而對閑忙比例的修正會出現(xiàn)遲滯現(xiàn)象,如EC2實例有的時候需要幾分鐘才能啟動,我們的代碼也考慮到了這些問題。所有這些經(jīng)驗性的調(diào)整經(jīng)歷了一兩周的時間,系統(tǒng)運行起來以后,就非常簡單啦。
自動伸縮并不僅僅是典型的容量需求問題,我們也遇到了諸如到EC2的網(wǎng)絡(luò)延遲加大了,或發(fā)布了一個代碼修正而使得渲染速度變慢了。遇到這些情況時,我們先停止自動伸縮,直到找出背后真正的原因并加以改正為止。我們還修正了一個錯誤,這個錯誤使一小部分用戶的保存操作失敗,這一修正使渲染負載増加了20%正好在圣誕節(jié)之前。
這種設(shè)置也很適合批處理作業(yè)。一段時間以前,我們要重建一批縮略圖,我就寫了一些代碼,將作業(yè)提交給渲染隊列,然后用新的縮略圖文件更新數(shù)據(jù)庫記錄。我不需要做任何特別的事情來分配空間或?qū)⒆鳂I(yè)設(shè)置在晚上負載較輕的時候處理,Server manager只是增加新的實例以適應(yīng)新的負載需求。
從財務(wù)方面來說,使用EC2比使用S3更清楚。我們試圖擴建內(nèi)部渲染以滿足平均的容量需求,同時,將做渲染的CPU轉(zhuǎn)換到做Web服務(wù)的CPU也容易。這意味著將云作為渲染服務(wù)器給Web服務(wù)器帶來了一些動態(tài)特性,這讓我們易于適應(yīng)負載模式的變化,而且,通過逐漸購買硬件的方式,這也讓我們更有效地使用現(xiàn)有的硬件。例如,可以在數(shù)據(jù)中心訂購個新的機柜,然后把服務(wù)器上架,而不用擔心浪費大部分的機柜電力。
一般與EC2有關(guān)的問題主要集中在連接性上。雖然互聯(lián)網(wǎng)作為一個整體是可靠的,但任何兩點之間的連接卻并非如此。通常,如果問題出現(xiàn)在網(wǎng)絡(luò)和數(shù)據(jù)中心之間,只有一小部分用戶受影響,但是,假如網(wǎng)絡(luò)恰好是云計算提供者,則所有用戶都會受影響。這種類型的宕機可能非常嚴重,因為問題可能出在這樣的區(qū)域,就是不論是你還是云計算提供者都沒有為之付費,即雙不管的區(qū)域。
在發(fā)生嚴重問題時(而且是在繁忙時段),唯一的選擇就是甩掉負載。過去,我們只有種辦法控制讓多少用戶進來,現(xiàn)在我們按優(yōu)先級將用戶分類(游客、免費用戶、合作伙伴、金牌用戶)??汕榈氖?,大多數(shù)情況下,你不得不等待宕機恢復(fù)。不論哪種情況,我們做的第一件事情就是更新 Twitter信息(fecd),這些消息也顯示在我們的It's raining onour Picnik”頁面上。我們并不指責(zé)任何人一個用戶才不關(guān)心這些呢。
我們并不像對內(nèi)部服務(wù)器那樣監(jiān)控EC2實例。Nagiosi通過 Servermanager自動獲取EC2實例的信息,Nagiost也監(jiān)控隊列深度,因為這是很多問題的預(yù)警器(early indicator)。
Caci以圖示方式顯示運行實例數(shù)(通過EC2API)及集群層層面上的性能數(shù)據(jù)。我們不需要在 Cacti上增加單個實例的信息,因為它并不實際處理集群,何況實例還是動態(tài)變化的。
事實上,我們并不關(guān)心單個實例的性能,已經(jīng)知道這些實例比本地機器上的要慢一點。沒關(guān)系的,因為自動伸縮系統(tǒng)總能在現(xiàn)有資源的條件下找到平衡。
由于實例是從隊列中獲取作業(yè)的,EC2實例稍微慢一點,只是少干點活兒而已,不會躺倒不干。這使我能夠集中精力關(guān)注高層的性能數(shù)據(jù),如一天中使用EC2實例的比例是多少。在一天結(jié)束時,只需要針對web服務(wù)器做容量規(guī)劃,從而決定硬件購買決策,而渲染服務(wù)器只是從未使用的容量中獲益。
要想有效使用網(wǎng)站建設(shè)云計算資源,需要對應(yīng)用架構(gòu)和配置管理/自動化有一個合理的“增長”態(tài)度。我們將渲染服務(wù)器設(shè)計為可分解的,以及我們手邊已經(jīng)具備配置管理系統(tǒng)等,這些事實使得自動伸縮實現(xiàn)起來既容易又可靠。
本文地址:http://m.hbbqcd.cn//article/3306.html