【轉】來自Google、Amazon和Facebook等7大知名互聯網的系統擴展經驗

出處http://web.itivy.com/article-531-1.htmlphp

本文出自澳大利亞一位ID爲Dodgy Coder的程序員2012年4月的博客文章。他從High Scalability上整理和總結了Google、YouTube、Twitter、Amazon、Ebay、Facebook和Instagram等7家知名互聯網的系統擴展經驗。值得注意的是,有些資料時過境遷,已經再也不反映最新狀況,可是核心的理念和許多具體經驗仍是很是寶貴的學習資料,值得一讀。html

不難發現,這7個公司都有如下共同的6大理念:前端

  1. 保持簡單——隨着時間推移,複雜性會天然出現。
  2. 自動化一切——包括災難恢復。
  3. 不斷迭代——想擴展到更高水平?必須準備好忍痛棄用如今能工做的某個組件。
  4. 選擇合適的工具——但也不怕本身動手打造。
  5. 使用緩存——在適當的地方。
  6. 根據場景,在數據的一致性和可用性之間作取捨。

下面來分別看一下7大公司的經驗吧。java

 

1、  Googlepython

可靠的存儲(Reliable Storage)nginx

可靠、可擴展的存儲基本上是任何應用程序的核心。GFS(Google File System)是Google的核心存儲平臺——它是一個大型分佈式結構化的日誌文件系統,Google在其中存放了大量的數據。爲何會自建系統,而不是使用其餘已有的產品?由於Google須要對系統有絕對的掌控力,同時這個平臺也正是Google之因此成爲Google的地方。GFS使他們得到了跨數據中心的高可靠性、擴展到數以千計個節點的能力、提供巨大的讀寫帶寬、支持以GB爲單位的大數據塊處理和跨節點分佈操做以下降瓶頸的高效技術。git

基礎設施成爲競爭優點程序員

Google能夠更快、更便宜而且在規模上罕有匹敵地發佈新的互聯網服務。許多公司與Google的想法並不相同,他們把基礎設施當作負擔,花錢的事兒。新舊兩類公司使用的技術徹底不一樣,在系統開發上也少有共識。github

在平臺的基礎上構建應用程序web

大平臺方式有一個常常被忽略的優點,就是初級開發者也能很快並自信地開發健壯的應用程序。若是每一個項目都須要創建分佈式基礎設施,那麼你很快將會陷入困境,由於懂得這麼去作的開發者很是少。協同效應並不老是空談,從整個系統上着眼改善,能夠幫助到創建在這個系統上的全部應用程序或項目。好比:改善了文件系統就可讓全部項目都當即並且透明地(指上層開發者和使用者都無需操心)獲益。若是每一個項目都使用不一樣的文件系統,那麼在整個技術棧上的改進將不會帶來持續不斷的增益。

自動化和恢復

創建自管理系統,讓工做不須要停機進行。這樣容許你更容易地進行如下操做:在多臺服務器間從新調配資源、動態添加容量、將機器下線以及從容地處理升級。

創建不斷進化的基礎設施

並行地執行一個耗時(CPU綁定的)操做,並取優勝者。這尤爲適合在CPU富餘而IO不足的狀況。

不要忽視學術界

學術界有不少很棒的思想,只不過尚未進入生產環境。你如今看到Google所作的事情其實都並不新鮮,只是沒有大規模部署而已。

考慮數據壓縮

當由許多機器組成的大型集羣受限於IO時,壓縮不失爲一良策。

2、  YouTube

越簡單越好

尋找問題領域的最簡解決方案。這裏存在許多複雜的問題,可是選擇解決方案的首要前提就是不能複雜。隨着時間的發展,複雜性會一直存在,而最簡單和最鬆散的解決方案是始終適用的。這樣作的緣由是保持解決問題的靈活性,反之你則會把本身逼入角落。你將會失去對程序的控制,一樣當你試圖解決時,問題將變的愈來愈複雜,你會變得無路可走。

欺騙:知曉如何在數據上做假

最快的函數調用就是根本上沒有發生。當你須要作一個持續增長的計數器時,好比說一個瀏覽計數,你須要爲每次的更改作數據庫調用。或者你能夠每隔一段的時間作一次調用,或者是一個隨機數量作更改——可是人們可能就會認爲它是實時顯示的。你必需要知道如何在數據上做假。

抖動(Jitter)

若是你的系統不存在抖動,將會由於用戶在同一時間對同一個資源進行請求產生Thundering Herd(「驚羣效應」)。對於一個流行的視頻,YouTube會盡量的爲其作緩衝。最流行的視頻可能會緩衝24小時。若是全部緩存同時到期,將會形成上面所說的Thundering Herd。經過抖動,你能夠設置隨機的時間(18-30小時)。這將阻止事情在同一個時間發生,而且保證很長時間內請求的順利完成。

近似正確

用戶所見就是你係統的狀態。若是用戶看不到你係統中存在的偏移和不一致,那麼這些問題從本質上來講根本「不存在」。若是你正在一個頁面上發佈評論,而這時候某些用戶恰好打開了這個頁面,那麼這些用戶在半秒內可能根本看不到你的評論,然而那些閱讀這個頁面的用戶根本不會在乎這個事情。這種狀況就容許你稍微的進行「做弊」,由於你的評論並無達到全局一致性。若是真的去作這個全局上的一致性,那將會投入大量的開銷,一樣也是牛刀殺雞——由於你並非在作金融系統,因此你能夠做弊。

3、 Twitter

實現API

Twitter的API流量是Twitter網站的10倍,API是Twitter增加用戶數量最重要的手段。保持服務的簡單,容許開發者在本身基礎設施上創建服務,而且想出比Twitter本身更好的應用程序點子。所謂衆人拾柴火焰高,集思廣益才能作更好的創新。因此開放你的應用,而且讓其保持簡單,這樣就能夠和其餘人的應用程序進行整合。(固然,後來在贏利壓力下,Twitter過河拆橋,將有史以來最有活力的API生態鏈生生幹掉了。)

使用你清楚的東西

Twitter使用了一堆消息傳送。對用戶發佈的消息進行排隊,而後分發給指定的用戶。Twitter最主要的功能就是扮演消息傳遞的橋樑,架起不一樣格式(SMS、Web、IM等等)之間的消息傳送。在後臺同步發送消息去清除朋友的緩存,而不是單獨的進行。Twitter開發者對Ruby最爲熟悉,因此他們拋棄DRb轉至Starling(一個Ruby編寫的分佈式隊列系統)。分佈式隊列系統將隊列寫入磁盤,以防止系統崩潰。以Twitter的經驗,大部分的性能提高不是語言的選擇而是應用程序的設計。(這一點也不徹底正確了,Twitter由於性能,後來從Ruby整個遷移到了Scala/JVM。)

知道什麼時候進行緩存以及緩存什麼

舉個例子,得到你朋友的狀態是很複雜的,包括了安全等多個隱患。因此,取代對數據庫進行查詢,朋友的狀態將會被放入緩存。永遠都不會接觸到數據庫。90%的請求都是API請求,因此他們在前端基本上不作任何頁面緩存。由於Twitter的頁面都對時間敏感,這樣作(緩存頁面)沒有任何好處。

4、 Amazon

使用SOA

Amazon的架構都是鬆耦合的,而且圍繞着服務創建。一個面向服務的體系結構(SOA),基於他們能夠快速及獨立的創建軟件的多個組件,容許他們更快的向市場上投放。Amazon.com Web頁就是一個相似的應用程序服務器。這樣的話這個應用程序同時服務了網絡服務接口、用戶服務應用程序以及賣方接口。

使用API打造你的系統,你將圍繞你的應用程序創建起一整套的生態系統。圍繞着服務展開將給你更高的靈活性——你能夠並行的進行操做,由於全部的輸出都是一項服務。禁止客戶端直接對數據庫進行訪問,由於不會涉及到客戶端,因此你的服務將擁有更好的擴展性和可靠性。這點很像谷歌的改變某個組件讓創建在整個系統或平臺上的應用程序都獲益。

根據場景在數據的一致性和數據的可用性之間作取捨

既然擴展你就必須作分片,因此你必須爲特定的系統作高一致性或者高可用性的選擇。你必須發現有效性和一致性上的重疊部分,根據服務的需求選擇一個合適的方案。舉個結帳系統的用例:你老是但願將請求做爲購物車的添加項,由於它產生了收入。在這個用例中,你就選擇了高可用性。錯誤就隱藏在了客戶方面,而且由其提出:當客戶進行提交時,你必須對一致性進行重點對待,由於不一樣的服務(信用卡處理、運輸、操做、報告)都將同時訪問數據,而且每一個都有各自數據一致性的需求。

擁抱失敗

對失敗抱日常心,它可能會常常出現,因此擁抱它。好比,使用一個快速重啓和快速恢復方案。選用一個合適的數據傳輸,服務正常運行的概率將接近100%。創建一個自我修復、自我組織、無人值守類型的操做。

只用你須要的

讓設計保持簡單,肯定設計中沒有隱藏的需求及依賴性。將技術程度降到最低,你只須要一些解決問題的必須技術。確保這些技術不會帶來更多的複雜性,慎重甚至是不選擇一些特定的方法或者技術堆棧。有些地方他們使用jboss/JAVA,但他們只選用Servlet,而不使用餘下的幾個J2EE框架。使用C++來處理請求,使用Perl/Mason來創建目錄。

根據客戶的反饋來指定決策

使用測量和客觀的討論去區分好壞。給客戶一個切實的選擇來測試哪一個更好,而且經過這些測試製定決策。這點一般使用相似A/B測試和Web Analytics等技術實現。若是你產生決策上的問題,那麼將其編碼,讓更多的人使用,從而清楚哪一個選擇纔是你真正想要的。

擴展性即競爭優點

和Google同樣,基礎設施一樣是Amazon競爭優點所在。他們能夠簡單的在原始服務上創建很是複雜的應用程序。他們能夠獨立的進行擴展操做,保持無與倫比的系統可用性,在不須要大規模的重配置下就能夠快速的推出新服務。

5、 eBay

切分一切

若是你不能對其進行切分,那麼你就不能對其進行擴展。經過功能和數據,將全部東西都切割成容易控制的組塊。

到處異步

經過事件驅動隊列和傳輸管道,鏈接起全部的組件。

擁抱故障

監視全部發生的事情,別間斷服務——即便有些部分開始發生故障。最小化和控制依賴性,使用抽象的接口和虛擬化技術,組件中包含一個SLA,用戶從SLA違規中恢復。自動化全部事情,組件須要自動調整,而系統則須要自我調節和完善。

擁抱不一致

在須要使用CAP原理的地方挑選好每一個特徵,若是選擇非分佈式事務,不一致性能夠經過操做順序來最小化,經過異步恢復和調整實現最終一致性。

保存全部的數據

數據驅動最佳的機遇、預測和推薦的發現,因此保存全部。清楚哪些數據是有權威的,哪些數據沒有,進行不一樣的對待。

基礎設施:給指定的工做分配合適的工具

須要最大化的使用每一個資源:數據(內存)、處理(CPU)、時鐘時間(延時)等。沒有通吃的策略,區分規模對待。由商用、工業服務器共同組成。

6、 Facebook

擴展須要屢次的迭代

解決方案一般是在工做的開始時提出,然而隨着發展你必須對其進行修改——已經使用了一年的方案,之後可能再也不適用。一個好的例子就是圖片,Facebook如今(文章撰寫時)每秒須要服務12億張圖片。第一代的思想就很是簡單,沒有考慮到擴展到如此規模,只注重功能上的實現。Uploader會將文件儲存爲NFS格式,而原數據將會保存在MySQL中。這個方案只用了3個月,可是這並不重要,在上市時間上他們贏得了巨大的競爭優點,一樣功能上的特色比深思擴展方案來的更加劇要。第二代則使用了不一樣的訪問方式對其進行優化,鑑於較小的圖片訪問頻度會比較高,因此對其使用了緩存,他們一樣開始使用CDN(內容分發網絡)。第三代則是一個overlay系統,讓Facebook能夠在原有的文件系統上使用BLOB存儲。圖片被存儲到一個二進制的BLOB,由於你清楚BLOB中圖片的字節偏移量,因此每張圖片對磁盤只進行一次IO操做。

不要重複設計一個方案,讓其保持簡單

在你對系統進行橫向擴展時,只使用你須要用到的。找到方案中須要重作的地方,進行優化,或者着手從新創建堆棧中須要修改的部分。Facebook花費了大把的時間去優化PHP,最終完成了HipHop的編寫,完成了PHP到C++的轉換,這爲他們節省了大量的內存和CPU開銷。然而你不須要從第一天就着手作這個事情,在徹底重寫一門語言以前你須要作的是聚焦產品的特性。

針對工做選用正確的工具,而且接受這個選擇所帶來的開銷

若是你須要使用Python,並選擇了它進行開發,可是必需要認識到這個選擇是有開銷的:一般是部署、監視、運營等方面。若是選擇了一個面向服務的體系結構(SOA),你必須本身動手創建大部分所需的後端,這須要大把的時間。經過LAMP你能夠省下許多開銷,可是一旦你真的選擇了LAMP堆棧,相似服務的配置以及監視將是隨之要面對的問題。隨着你對這個服務瞭解的加深,你一定會自費力氣作重複的工做。

正確的公司文化

創建一個能夠促進生產的內部環境,並根據需求不斷的進行完善。在進行正確的編碼和作出正確的產品以前,你首先須要定義正確的公司文化;沒有一個正確的文化,公司將不會獲得發展。

7、 Instagram

利用現有的雲基礎設施

不要去作重複的事情,你可使用可靠而且獲得證明的技術。Instagram在Amazon的EC2雲計算基礎設施上運行了100多個Ubuntu 11.04實例,他們一樣還使用了Amazon ELB,其中包括3個nginx實例以及自動的故障恢復(撰稿日期)。圖片被儲存在Amazon S3上,他們還使用了Amazon CloudFront做爲CDN,這麼作能夠有助於世界各地的圖片加載時間。

異步的任務隊列

當一個用戶決定將Instagram上的圖片分享到Twitter或者Facebook時,或者當他們須要給發佈的圖片發送一個實時的通告,他們把任務推送給開源的Gearman任務管理框架。使用異步隊列意味着當「重載」在後臺進行時,媒體上傳能夠快速完成。大約有200個工做者(Python編寫)忙於任務隊列的處理,處理服務中本身分割的份額。

推送通知

他們使用一個開源Apple Push Notification Service(APNS)提供程序pyapns(基於Twisted),天天穩定地爲Instagram解決10億推送消息的任務。

實時的系統級監控

對於擁有100多個EC2實例的Instagram來講,對系統進行實時的全方位監控無疑是重中之重。他們使用Munin進行系統級監視,這個監視工具在系統任何操做超過正常範圍時都會發出警報。他們開發了Munin的定製插件,基於Python-Munin之上,監視非系統級事件。他們使用Pingdom進行服務的外部監視,而且使用PagerDuty處理通知和事件。而Python的錯誤報告,他們使用Sentry,一個開源的Django應用。在任何給定的時間,他們能夠實時地登陸並瞭解系統中出現了什麼錯誤。

選擇性使用NoSQL技術(好比Redis)

Redis驅動了主feed,活動feed、會話系統(會話系統後端代碼見這裏)以及其餘相關係統。Redis全部的數據都須要寫入內存,因此他們在EC2上爲Redis運行了幾個Quadruple Extra-Large Memory實例,而且不按期給任何給定系統作跨Redis的分片。

相關文章
相關標籤/搜索