Nifty使用4個Web Server支撐5400萬個用戶網(wǎng)站
Nifty運營網(wǎng)站已經(jīng)有很長一段時間,而在基于HTML5的WYSIWYG網(wǎng)頁制作平臺推出后,用戶在該公司建立的網(wǎng)站已超過5400萬個,同時其中大部分網(wǎng)站的日PV都不到100。鑒于每個網(wǎng)頁的PV都很低,因此傳統(tǒng)的緩存策略并不適用。然而即使是這樣,該公司也只使用了4個Web Server 就完成了這些工作。近日,Wix***后端工程師Aviran Mordo在“ Wix Architecture at Scale”的演講中分享了他們 的策略,下面我們一起看High Scalability創(chuàng)始人Todd Hoff的總結(jié):
以下為譯文
Wix圍繞擴展性上的努力可以用“定制化”三個字來總結(jié)——在仔細地審視了系統(tǒng)之后,以高可用和高性能為目標(biāo)對系統(tǒng)進行了改善。
Wix使用了多數(shù)據(jù)中心和云服務(wù),這在通常情況下非常少見,他們將數(shù)據(jù)同時復(fù)制到Google Compute Engine和AWS。對于故障轉(zhuǎn)移,他們有專門的應(yīng)對策略。
從始至 終,Wix都沒有使用事務(wù)。取而代之,所有數(shù)據(jù)都是不可變的,他們?yōu)橛美褂昧艘粋€非常簡單的最終一致性策略。Wix并不是緩存策略愛好者,簡而言之他們 并沒有打造一個非常高端的緩存層。取而代之,他們將大部分的精力放在了路徑渲染優(yōu)化上,讓每個頁面的顯示時間不超過100毫秒。
Wix開始于一個非常小的系統(tǒng),使用了單片架構(gòu);而在業(yè)務(wù)發(fā)展過程中,他們很自然地過渡到一個面向服務(wù)的架構(gòu)。在整個架構(gòu)中,他們使用了一個非常成熟的服務(wù)識別策略,從而可以很輕易的將所有精力都集中到一個事件上來。
系統(tǒng)統(tǒng)計
- 5400個網(wǎng)站,每個月都會新增100萬個
- 800+TB的靜態(tài)數(shù)據(jù),每天1.5TB的新文件
- 3個數(shù)據(jù)中心+兩個云服務(wù)(谷歌和亞馬遜)
- 300個服務(wù)器
- 每天7億個HTTP請求
- 總計600員工,200人的研發(fā)團隊
- 系統(tǒng)內(nèi)服務(wù)數(shù)量達50個
- 4個公共Web Server來支撐4500萬個網(wǎng)站
系統(tǒng)組件
- MySQL
- Google和Amazon云服務(wù)
- CDN(內(nèi)容分發(fā)網(wǎng)絡(luò))
- Chef
系統(tǒng)衍變
1. 系統(tǒng)始于簡單的單片架構(gòu),開始時只有一個應(yīng)用服務(wù)器,對于任何人來說,這都是最簡單的初始策略,非常靈活且易于更新。
- Tomcat、Hibernate、定制網(wǎng)絡(luò)框架。
- 使用有狀態(tài)的登錄。
- 無視任何性能和擴展性相關(guān)。
2. 兩年后。
- 仍然使用單片服務(wù)器支撐所有事情。
- 擁有了一定規(guī)模的開發(fā)團隊,且需要支撐一定規(guī)模的用戶。
- 依賴性產(chǎn)生的問題。某點的改變通常會造成整個系統(tǒng)的變更,無關(guān)領(lǐng)域的故障通常會造成整個系統(tǒng)大范圍崩潰。
3. 系統(tǒng)拆分的時候到了。
- 到面向服務(wù)的架構(gòu)轉(zhuǎn)變,但是這并不是件容易的事情。比如,你如何將某個功能分離到兩個服務(wù)中?
- 聚焦用戶在系統(tǒng)中的行為,并將之主要歸結(jié)為3類:修改網(wǎng)站、查看Wix建立的網(wǎng)站以及媒體服務(wù)。
- 網(wǎng)站更新包括服務(wù)器數(shù)據(jù)的數(shù)據(jù)有效性、安全和驗證、數(shù)據(jù)一致性以及大量的數(shù)據(jù)修改操作。
- 一旦某個網(wǎng)站建立完成,用戶就會進行查看。因此,對于整個系統(tǒng)來說,訪客的數(shù)量十倍于修改者。因此關(guān)注點會轉(zhuǎn)換為:
- 高可用性。因為用戶業(yè)務(wù)行為,HA成為系統(tǒng)***的特性。
- 高性能。
- 高流量值。
- 長尾問題。平臺上已經(jīng)有了大量的網(wǎng)站,但是它們通常都非常小。單獨看某個網(wǎng)站,每天可能只有10或100個PV。鑒于這種特性,緩存對于系統(tǒng)擴展來說并不會起到太大的作用。因此,緩存變得非常低效。
- 媒體支撐是第二大服務(wù),包括HTML、javascript、css及images。他們需要一個途徑來支撐800TB數(shù)據(jù)上的大量請求,其中緩存靜態(tài)內(nèi)容成為制勝的關(guān)鍵。
- 新系統(tǒng)看起來像一個網(wǎng)絡(luò)層,網(wǎng)站被切分為3個部分服務(wù):修改部分(任何對數(shù)據(jù)產(chǎn)生修改的操作),媒體部分(支撐靜態(tài)內(nèi)容,只讀),公共部分(一個文件被訪問的首部分,只讀)。
服務(wù)打造的指導(dǎo)方針
- 每個服務(wù)都有自己獨立的數(shù)據(jù)庫,每個數(shù)據(jù)庫只能一個被一個服務(wù)寫入。
- 數(shù)據(jù)庫只能被服務(wù)的API訪問,這樣可以將關(guān)注點分離,并將數(shù)據(jù)模型對其他服務(wù)透明。
- 鑒于性能原因,其他服務(wù)只被賦予數(shù)據(jù)庫的只讀權(quán)限,一個數(shù)據(jù)庫只能被一個服務(wù)寫入。
- 服務(wù)都是無狀態(tài)的,這讓水平擴展非常便捷,業(yè)務(wù)的增長只需要添加更多服務(wù)器就可以支撐。
- 不使用事務(wù)。除下billing/financial 事務(wù)以外,所有其他服務(wù)都不使用事務(wù),這里的理念是避免數(shù)據(jù)庫事務(wù)所帶來的開銷,從而提升性能。鑒于不使用事務(wù),開發(fā)者必須考慮設(shè)計合適的數(shù)據(jù)模型來完成事務(wù)邏輯特性,從而避免不一致狀態(tài)。
- 在新服務(wù)設(shè)計時,緩存并不是所需要考慮的因素。首先,盡可能的考慮服務(wù)性能,然后快速的部署到生產(chǎn)環(huán)境,查看服務(wù)的運行情況。只有在代碼無法優(yōu)化的情況下,才使用緩存來解決性能問題。
更新服務(wù)
- 更新服務(wù)必須處理大量的文件。
- 數(shù)據(jù)被使用不可變的JSON pages在MySQL中存儲,每天大約250萬個。
- MySQL是個非常棒的鍵值存儲。鍵的設(shè)定基于文件的哈希函數(shù),因此鍵是不可變的,通過主鍵來訪問MySQL可以獲得非常理想的性能。
- 可接受的擴展性。在擴展性方面,Wix又做了什么樣的權(quán)衡?Wix之所以不使用NoSQL的原因是NoSQL往往會犧牲一致性,而通常開發(fā)者并不具備處理這種情況的能力,所以堅持MySQL也并非不可。
- 動態(tài)數(shù)據(jù)庫。為了給那些經(jīng)常訪問的網(wǎng)站讓路,所有網(wǎng)站的冷數(shù)據(jù)(通常是建立時間超過3個月以上的數(shù)據(jù))都會被轉(zhuǎn)移到其他的數(shù)據(jù)庫,這些數(shù)據(jù)庫的性能往往會非常低,但是容量很高。
- 給用戶增長留有容量空間。大型檔案數(shù)據(jù)庫是非常緩慢的,但是鑒于數(shù)據(jù)使用的頻率這不會出現(xiàn)任何問題。但是一旦這個數(shù)據(jù)被訪問,在下次訪問之前這個數(shù)據(jù)就會被轉(zhuǎn)移到活躍數(shù)據(jù)庫。
打造更新服務(wù)的高可用性
- 大數(shù)據(jù)體積達到一定程度時,任何事情的高可用都是難以保證的。因此,著眼關(guān)鍵路徑,在網(wǎng)站領(lǐng)域無疑就是網(wǎng)站的內(nèi)容。如果網(wǎng)站的一個裝飾部分問題,它對網(wǎng)站的可用性不會造成任何致命影響。因此對一個網(wǎng)站來說,關(guān)鍵路徑才是唯一關(guān)注點。
- 防止數(shù)據(jù)庫崩潰。如果你想盡可能快的完成故障轉(zhuǎn)移,務(wù)必做好數(shù)據(jù)庫的備份,并在故障恢復(fù)時快速切換到從數(shù)據(jù)庫。
- 數(shù)據(jù)完整性保護。這里并不一定是惡意破壞,一個bug可能就會對數(shù)據(jù)存儲產(chǎn)生影響。所有數(shù)據(jù)都是不可變的,為任何數(shù)據(jù)保存校訂版本。最壞的情況下,即使數(shù)據(jù)被破壞到無法修復(fù),我們也可以將之恢復(fù)到修訂版本。
- 阻止不可用情況發(fā)生。區(qū)別于桌面應(yīng)用程序,網(wǎng)站必須可以被隨時隨地地訪問。因此,在不同地理位置的數(shù)據(jù)中心,不同云環(huán)境中對數(shù)據(jù)進行備份非常重要,這將賦予系統(tǒng)足夠的彈性。
- 在一個網(wǎng)站上點擊“保存”按鈕,修改會話會給修改服務(wù)器發(fā)送一個JSON文件。
- 服務(wù)器會給活躍MySQL服務(wù)器發(fā)送頁面,同時它會在另一個數(shù)據(jù)中心進行備份。
- 當(dāng)數(shù)據(jù)在本地修改后,一個異步的進程會將修改上傳到一個靜態(tài)網(wǎng)格,也就是所謂的媒體部分。
- 當(dāng)數(shù)據(jù)被傳輸?shù)届o態(tài)網(wǎng)格后,一個通知會發(fā)送給保存在Google Compute Engine上的存檔服務(wù)。存檔服務(wù)會連接到這個靜態(tài)網(wǎng)格,下載這個修改頁面,并將之保存在谷歌云服務(wù)中。
- 然后,一個通知會發(fā)送到修改器,告知頁面已經(jīng)存儲到GCE。
- 同時,系統(tǒng)會根據(jù)GCE的數(shù)據(jù)在Amazon中保存另一個副本。
- 當(dāng)***一個通知收到后,這意味著這個數(shù)據(jù)已經(jīng)保存了3個副本:一個數(shù)據(jù)庫,一個靜態(tài)網(wǎng)格以及一個GCE。
- 對于新版本來說是3個副本,而對于舊版本來說則會存在兩個副本。
- 這個過程具備自我修復(fù)的特性。如果這里存在一個錯誤,當(dāng)用戶下一次更新其網(wǎng)站內(nèi)容時,所有未完成的修改會被重新上傳。
- 停用文件會做垃圾收集處理。
使用無數(shù)據(jù)庫事務(wù)方式給數(shù)據(jù)建模
- 對于服務(wù)擁有者來說,他們從來都不期望發(fā)生這樣的情況:用戶同時對兩個頁面進行修改,結(jié)果只有一個頁面被存儲到了數(shù)據(jù)庫中,這就造成了不一致狀態(tài)。
- 取得所有JSON文件,隨后按照順序?qū)⑺麄儽4娴綌?shù)據(jù)庫。當(dāng)所有數(shù)據(jù)被保存后,一個命令會被發(fā)布,它包含了上傳到這個靜態(tài)服務(wù)器上所有被保存頁面的ID清單(靜態(tài)服務(wù)器中文件名稱的哈希值)。
媒體部分
- 存儲了大量文件。800TB的用戶媒體文件,平均每天300萬個文件,5億條元記錄。
- 對圖像進行修改。它們會針對不同設(shè)備和屏幕對圖像進行修改。在這里,可以根據(jù)需求插入水印,同時還可以對音頻格式進行轉(zhuǎn)換。
- 建立一個一致性分布式文件系統(tǒng),使用多數(shù)據(jù)中心備份模式,并且實現(xiàn)跨數(shù)據(jù)中心的故障恢復(fù)。
- 運行的痛苦。32個服務(wù)器,每9個月翻一倍。
- 計劃遷移到云中以獲得更好的擴展性。
- 讓供應(yīng)商鎖定見鬼。因為都使用了API,只需要改變實現(xiàn)方式就可以在數(shù)周內(nèi)跨云服務(wù)供應(yīng)商進行遷移。
- 在Google Compute Engine中遭遇失敗。當(dāng)他們從數(shù)據(jù)中心遷移到GCE時,很快就受到了谷歌云服務(wù)的限制。而在谷歌做出了一些改變后,系統(tǒng)得以正常運行。
- 數(shù)據(jù)是不可變的,因此非常有利于緩存。
- 圖像請求會首先發(fā)送到CDN。如果所請求的圖像在CDN中并不存在,請求會被直接傳遞給他們奧斯丁的主數(shù)據(jù)中心。如果在主數(shù)據(jù)中心也沒有發(fā)現(xiàn)這個圖像,隨后尋找的地點就是谷歌云服務(wù)。如果谷歌云服務(wù)中仍然未發(fā)現(xiàn)所請求的圖像,那么下一個尋找地點則是坦帕市的數(shù)據(jù)中心。
公用部分
- 解析URL(在4500萬網(wǎng)站中),并將之分配給指定的渲染程序,然后轉(zhuǎn)換成HTML、sitemap XML或者robots TXT等。
- 公用的SLA,峰值時響應(yīng)時間低于100毫秒。網(wǎng)站必須是高可用的,同時也需要非常高的性能,但是緩存卻并不能發(fā)揮作用。
- 當(dāng)一個用戶修改某個頁面并進行發(fā)布后,包括這個頁面元素的清單會被推送到公用環(huán)境,同時推送的還有路由表。
- 最小化宕機情況。解析一次路由需要促發(fā)一個數(shù)據(jù)庫調(diào)用。將請求分配個渲染器需要1次RPC調(diào)用。獲得網(wǎng)站清單也需要一次數(shù)據(jù)庫調(diào)用。
- 查詢表會在內(nèi)存中進行緩存,每5分鐘修改一次。
- 因為需要傳送給編輯器,數(shù)據(jù)不可能保存為同一種格式。數(shù)據(jù)使用非規(guī)范化格式進行存儲,通過主鍵進行優(yōu)化,所有需求的內(nèi)容都會在單一請求中返回。
- 最小化業(yè)務(wù)邏輯。數(shù)據(jù)是非規(guī)范化的,并且進行預(yù)計算。大規(guī)模場景下,每秒內(nèi)發(fā)生的每個操作都會乘以4500萬次,因此發(fā)生在公共服務(wù)器上的每個操作都需要被調(diào)整。
- 頁面渲染
- 由公共服務(wù)器返回的html是 bootstrap html類型的,它使用了一個JavaScript Shell,并包含了所有網(wǎng)站清單和動態(tài)數(shù)據(jù)相關(guān)的JSON數(shù)據(jù)。
- 渲染會被放在客戶端進行。當(dāng)下,筆記本電腦和移動設(shè)備已經(jīng)擁有了很強大的性能,它們完全可以從事這個工作。
- 之所以選擇JSON,因為解析和壓縮都非常方便。
- 客戶端上的bug非常容易修補。修補客戶端bug只需要重新部署一個客戶端代碼,如果在服務(wù)器端進行渲染,html則會被緩存,因此修補一個bug需要重新渲染上千萬個網(wǎng)站。
公用部分的高可用性
- 雖然目標(biāo)是一直可用,但是總會發(fā)生一些意外情況
- 通常情況下:請求由瀏覽器發(fā)出,隨之會被傳輸?shù)?一個數(shù)據(jù)中心,通過一個負載均衡器,它將會給發(fā)送到一個公共服務(wù)器,解析路由,傳送給渲染器,隨后返回到瀏覽器,并使用瀏覽器運行javascript。 隨后,瀏覽器會對檔案服務(wù)發(fā)送請求,檔案服務(wù)會做與瀏覽器相同的操作,然后將數(shù)據(jù)儲存到緩存。
- 數(shù)據(jù)中心丟失發(fā)生的情況:這時候,所有UPS都會掛掉,數(shù)據(jù)中心也會丟失。所有DNS都會被改變,請求會發(fā)送給次數(shù)據(jù)中心。
- 公用部分丟失的情況:當(dāng)負載均衡器配置只進行一 半發(fā)生這個問題時,所有公共服務(wù)器都會丟失?;蛘弋?dāng)部署錯誤版本時,服務(wù)器則會拋出故障。Wix通過定制負載均衡器代碼來解決這個問題,在公共服務(wù)器丟失 時,他們會將檔案服務(wù)器路由到高速緩存,即使系統(tǒng)在警報后已經(jīng)進行故障恢復(fù)。
- 在網(wǎng)絡(luò)連通性很爛的情況:請求由瀏覽器發(fā)出,隨 之會被傳輸?shù)揭粋€數(shù)據(jù)中心,通過一個負載均衡器,并返回對應(yīng)的html。現(xiàn)在JavaScript代碼必須取回所有的JSON數(shù)據(jù)和頁面。隨后進入內(nèi)容分 發(fā)網(wǎng)絡(luò),發(fā)送到靜態(tài)網(wǎng)格,并獲得所有的文件進行網(wǎng)站渲染。在網(wǎng)絡(luò)很卡的情況下,文件返回可能無法進行。JavaScript則會做出選擇:如果主要位置無 法獲得文件,代碼則會在檔案服務(wù)中獲取。
學(xué)到的知識
- 識別業(yè)務(wù)的關(guān)鍵路勁和關(guān)注點,仔細了解產(chǎn)品運行的方式,開發(fā)使用場景,盡力讓你工作物有所值。
- 使用多云和多數(shù)據(jù)中心。為了更好的可用性,在關(guān)鍵路徑上建立冗余。
- 對數(shù)據(jù)進行轉(zhuǎn)換,最小化進程外跳,一切只為了性能。預(yù)計算并做一切可以做的事情來減少網(wǎng)絡(luò)抖動。
- 利用好客戶端的CPU,為可用性建立關(guān)鍵路徑上的冗余。
- 從小做起,先跑起來,然后尋找下一個決策。從始至終,Wix首要解決的都是如何才能讓服務(wù)可以良好運行的工作,然后有條不紊的轉(zhuǎn)移到面向服務(wù)的架構(gòu)。
- 長尾需要不同的途徑進行解決。取代緩存一切,Wix通過優(yōu)化渲染途徑來提升服務(wù),并將數(shù)據(jù)在活躍和檔案數(shù)據(jù)庫中同時進行備份。
- 使用不可變的方式。不可變會對服務(wù)的架構(gòu)產(chǎn)生深遠影響,覆蓋后端到客戶端的所有處理,對于許多問題來說,這都是個優(yōu)雅的解決方案。
- 供應(yīng)商鎖定根本不存在。所有功能都通過API實現(xiàn),只需要修改實現(xiàn)就可以在數(shù)周內(nèi)完成不同云供應(yīng)商的遷移。
- ***的瓶頸來自數(shù)據(jù)。在不同云環(huán)境中轉(zhuǎn)移大量數(shù)據(jù)異常困難。
原文來自:http://www.oschina.net/news/57344/nifty-4-web-server-support-54-millions-users