英文原文:High Scalability,編譯:CSDNcss
導讀:和許多新興的網站同樣,著名的輕博客服務Tumblr在急速發展中面臨了系統架構的瓶頸。天天5億次瀏覽量,峯值每秒4萬次請求,天天3TB新的數據存儲,超過1000臺服務器,這樣的狀況下如何保證老系統平穩運行,平穩過渡到新的系統,Tumblr正面臨巨大的挑戰。近日,HighScalability網站的Todd Hoff採訪了該公司的分佈式系統工程師Blake Matheny,撰文系統介紹了網站的架構,內容頗有價值。html
Tumblr每個月頁面瀏覽量超過150億次,已經成爲火爆的博客社區。用戶也許喜歡它的簡約、美麗,對用戶體驗的強烈關注,或是友好而忙碌的溝通方式,總之,它深得人們的喜好。前端
每個月超過30%的增加固然不可能沒有挑戰,其中可靠性問題尤其艱鉅。天天5億次瀏覽量,峯值每秒4萬次請求,天天3TB新的數據存儲,並運行於超過1000臺服務器上,全部這些幫助Tumblr實現巨大的經營規模。nginx
創業公司邁向成功,都要邁過危險的迅速發展期這道門檻。尋找人才,不斷改造基礎架構,維護舊的架構,同時要面對逐月大增的流量,並且曾經只有4位工程師。這意味着必須艱難地選擇應該作什麼,不應作什麼。這就是Tumblr的情況。好在如今已經有20位工程師了,能夠有精力解決問題,並開發一些有意思的解決方案。git
Tumblr最開始是很是典型的LAMP應用。目前正在向分佈式服務模型演進,該模型基於Scala、HBase、Redis(著名開源K-V存儲方案)、Kafka(Apache項目,出自LinkedIn的分佈式發佈-訂閱消息系統)、Finagle(由Twitter開源的容錯、協議中立的RPC系統),此外還有一個有趣的基於Cell的架構,用來支持Dashboard(CSDN注:Tumblr富有特點的用戶界面,相似於微博的時間軸)。程序員
Tumblr目前的最大問題是如何改造爲一個大規模網站。系統架構正在從LAMP演進爲最早進的技術組合,同時團隊也要從小的創業型發展爲全副武裝、隨時待命的正規開發團隊,不斷創造出新的功能和基礎設施。下面就是Blake Matheny對Tumblr系統架構狀況的介紹。github
網站地址web
主要數據
▲天天5億次PV(頁面訪問量)
▲每個月超過150億PV
▲約20名工程師
▲ 峯值請求每秒近4萬次
▲天天超過1TB數據進入Hadoop集羣
▲ MySQL/HBase/Redis/memcache天天生成若干TB數據
▲每個月增加30%
▲近1000硬件節點用於生產環境
▲平均每位工程師每個月負責數以億計的頁面訪問
▲天天上傳大約50GB的文章,天天跟帖更新數據大約2.7TB(CSDN注:這兩個數據的比例看上去不太合理,據Tumblr數據科學家Adam Laiacano在Twitter上解釋,前一個數據應該指的是文章的文本內容和元數據,不包括存儲在S3上的多媒體內容)
軟件環境
▲開發使用OS X,生產環境使用Linux(CentOS/Scientific)
▲Apache
▲PHP, Scala, Ruby
▲Redis, HBase, MySQL
▲memcache, Gearman(支持多語言的任務分發應用框架), Kafka, Kestrel(Twitter開源的分佈式消息隊列系統), Finagle
▲ Thrift, HTTP
▲Func——一個安全、支持腳本的遠程控制框架和API
▲ Git, Capistrano(多服務器腳本部署工具), Puppet, Jenkins
硬件環境
▲500臺Web服務器
▲200臺數據庫服務器(47 pool,20 shard)
▲30臺memcache服務器
▲22臺Redis服務器
▲15臺Varnish服務器
▲25臺HAproxy節點
▲8臺nginx服務器
▲14臺工做隊列服務器(Kestrel + Gearman)
架構
1. 相對其餘社交網站而言,Tumblr有其獨特的使用模式:
▲天天有超過5千萬篇文章更新,平均每篇文章的跟帖又數以百計。用戶通常只有數百個粉絲。這與其餘社會化網站裏少數用戶有幾百萬粉絲很是不一樣,使得Tumblr的擴展性極具挑戰性。
▲按用戶使用時間衡量,Tumblr已是排名第二的社會化網站。內容的吸引力很強,有不少圖片和視頻,文章每每不短,通常也不會太長,但容許寫得很長。文章內容每每比較深刻,用戶會花費更長的時間來閱讀。
▲用戶與其餘用戶創建聯繫後,可能會在Dashboard上往回翻幾百頁逐篇閱讀,這與其餘網站基本上只是部分信息流不一樣。
▲用戶的數量龐大,用戶的平均到達範圍更廣,用戶較頻繁的發帖,這些都意味着有巨量的更新須要處理。
2. Tumblr目前運行在一個託管數據中心中,已在考慮地域上的分佈性。
3. Tumblr做爲一個平臺,由兩個組件構成:公共Tumblelogs和Dashboard
▲公共Tumblelogs與博客相似(此句請Tumblr用戶校訂),並不是動態,易於緩存
▲Dashboard是相似於Twitter的時間軸,用戶由此能夠看到本身關注的全部用戶的實時更新。與博客的擴展性不一樣,緩存做用不大,由於每次請求都不一樣,尤爲是活躍的關注者。並且須要實時並且一致,文章天天僅更新50GB,跟帖天天更新2.7TB,全部的多媒體數據都存儲在S3上面。
▲大多數用戶以Tumblr做爲內容瀏覽工具,天天瀏覽超過5億個頁面,70%的瀏覽來自Dashboard。
▲Dashboard的可用性已經不錯,但Tumblelog一直不夠好,由於基礎設施是老的,並且很難遷移。因爲人手不足,一時半會兒還顧不上。
老的架構
Tumblr最開始是託管在Rackspace上的,每一個自定義域名的博客都有一個A記錄。當2007年Rackspace沒法知足其發展速度不得不遷移時,大量的用戶都須要同時遷移。因此他們不得不將自定義域名保留在Rackspace,而後再使用HAProxy和Varnish路由到新的數據中心。相似這樣的遺留問題不少。
開始的架構演進是典型的LAMP路線:
▲最初用PHP開發,幾乎全部程序員都用PHP
▲最初是三臺服務器:一臺Web,一臺數據庫,一臺PHP
▲爲了擴展,開始使用memcache,而後引入前端cache,而後在cache前再加HAProxy,而後是MySQL sharding(很是奏效)
▲採用「在單臺服務器上榨出一切」的方式。過去一年已經用C開發了兩個後端服務:ID生成程序和Staircar(用Redis支持Dashboard通知)
Dashboard採用了「擴散-收集」方式。當用戶訪問Dashboard時將顯示事件,來自所關注的用戶的事件是經過拉而後顯示的。這樣支撐了6個月。因爲數據是按時間排序的,所以sharding模式不太管用。
新的架構
▲因爲招人和開發速度等緣由,改成以JVM爲中心。目標是將一切從PHP應用改成服務,使應用變成請求鑑別、呈現等諸多服務之上的薄層。
▲這其中,很是重要的是選用了Scala和Finagle。
▲在團隊內部有不少人具有Ruby和PHP經驗,因此Scala頗有吸引力。
▲Finagle是選擇Scala的重要因素之一。這個來自Twitter的庫能夠解決大多數分佈式問題,好比分佈式跟蹤、服務發現、服務註冊等。
▲轉到JVM上以後,Finagle提供了團隊所需的全部基本功能(Thrift, ZooKeeper等),無需再開發許多網絡代碼,另外,團隊成員認識該項目的一些開發者。
▲Foursquare和Twitter都在用Finagle,Meetup也在用Scala。
▲應用接口與Thrift相似,性能極佳。
▲團隊原本很喜歡Netty(Java異步網絡應用框架,2月4日剛剛發佈3.3.1最終版),但不想用Java,Scala是不錯的選擇。
▲選擇Finagle是由於它很酷,還認識幾個開發者。
之因此沒有選擇Node.js,是由於以JVM爲基礎更容易擴展。Node的發展爲時尚短,缺少標準、最佳實踐以及大量久經測試的代碼。而用Scala的話,可使用全部Java代碼。雖然其中並無多少可擴展的東西,也沒法解決5毫秒響應時間、49秒HA、4萬每秒請求甚至有時每秒40萬次請求的問題。可是,Java的生態鏈要大得多,有不少資源能夠利用。
內部服務從C/libevent爲基礎正在轉向Scala/Finagle爲基礎。
開始採用新的NoSQL存儲方案如HBase和Redis。但大量數據仍然存儲在大量分區的MySQL架構中,並無用HBase代替MySQL。HBase主要支持短地址生產程序(數以十億計)還有歷史數據和分析,很是結實。此外,HBase也用於高寫入需求場景,好比Dashboard刷新時一秒上百萬的寫入。之因此尚未替換HBase,是由於不能冒業務上風險,目前仍是依靠人來負責更保險,先在一些小的、不那麼關鍵的項目中應用,以得到經驗。MySQL和時間序列數據sharding(分片)的問題在於,總有一個分片太熱。另外,因爲要在slave上插入併發,也會遇到讀複製延遲問題。
此外,還開發了一個公用服務框架:
▲花了不少時間解決分佈式系統管理這個運維問題。
▲爲服務開發了一種Rails scaffolding,內部用模板來啓動服務。
▲全部服務從運維的角度來看都是同樣的,全部服務檢查統計數據、監控、啓動和中止的方式都同樣。
▲工具方面,構建過程圍繞SBT(一個Scala構建工具),使用插件和輔助程序管理常見操做,包括在Git裏打標籤,發佈到代碼庫等等。大多數程序員都不用再操心構建系統的細節了。
200臺數據庫服務器中,不少是爲了提升可用性而設,使用的是常規硬件,但MTBF(平均故障間隔時間)極低。故障時,備用充足。
爲了支持PHP應用有6個後端服務,並有一個小組專門開發後端服務。新服務的發佈須要兩到三週,包括Dashboard通知、Dashboard二級索引、短地址生成、處理透明分片的memcache代理。其中在MySQL分片上耗時不少。雖然在紐約本地很是熱,但並無使用MongoDB,他們認爲MySQL的可擴展性足夠了。
Gearman用於會長期運行無需人工干預的工做。
可用性是以達到範圍(reach)衡量的。用戶可以訪問自定義域或者Dashboard嗎?也會用錯誤率。
歷史上老是解決那些最高優先級的問題,而如今會對故障模式系統地分析和解決,目的是從用戶和應用的角度來定成功指標。(後一句原文彷佛不全)
最開始Finagle是用於Actor模型的,可是後來放棄了。對於運行後無需人工干預的工做,使用任務隊列。並且Twitter的util工具庫中有Future實現,服務都是用Future(Scala中的無參數函數,在與函數關聯的並行操做沒有完成時,會阻塞調用方)實現的。當須要線程池的時候,就將Future傳入Future池。一切都提交到Future池進行異步執行。
Scala提倡無共享狀態。因爲已經在Twitter生產環境中通過測試,Finagle這方面應該是沒有問題的。使用Scala和Finagle中的結構須要避免可變狀態,不使用長期運行的狀態機。狀態從數據庫中拉出、使用再寫回數據庫。這樣作的好處是,開發人員不須要操心線程和鎖。
22臺Redis服務器,每臺的都有8-32個實例,所以線上同時使用了100多個Redis實例。
▲Redis主要用於Dashboard通知的後端存儲。
▲所謂通知就是指某個用戶like了某篇文章這樣的事件。通知會在用戶的Dashboard中顯示,告訴他其餘用戶對其內容作了哪些操做。
▲高寫入率使MySQL沒法應對。
▲通知轉瞬即逝,因此即便遺漏也不會有嚴重問題,所以Redis是這一場景的合適選擇。
▲這也給了開發團隊瞭解Redis的機會。
▲使用中徹底沒有發現Redis有任何問題,社區也很是棒。
▲開發了一個基於Scala Futures的Redis接口,該功能如今已經併入了Cell架構。
▲短地址生成程序使用Redis做爲一級Cache,HBase做爲永久存儲。
▲Dashboard的二級索引是以Redis爲基礎開發的。
▲Redis還用做Gearman的持久存儲層,使用Finagle開發的memcache代理。
▲正在緩慢地從memcache轉向Redis。但願最終只用一個cache服務。性能上Redis與memcache至關。
內部的firehose(通訊管道)
▲內部的應用須要活躍的信息流通道。這些信息包括用戶建立/刪除的信息,liking/unliking的提示,等等。挑戰在於這些數據要實時的分佈式處理。咱們但願可以檢測內部運行情況,應用的生態系統可以可靠的生長,同時還須要建設分佈式系統的控制中心。
▲之前,這些信息是基於Scribe(Facebook開源的分佈式日誌系統。)/Hadoop的分佈式系統。服務會先記錄在Scribe中,並持續的長尾形式寫入,而後將數據輸送給應用。這種模式能夠當即中止伸縮,尤爲在峯值時每秒要建立數以千計的信息。不要期望人們會細水長流式的發佈文件和grep。
▲內部的firehose就像裝載着信息的大巴,各類服務和應用經過Thrift與消防管線溝通。(一個可伸縮的跨語言的服務開發框架。)
▲LinkedIn的Kafka用於存儲信息。內部人員經過HTTP連接firehose。常常面對巨大的數據衝擊,採用MySQL顯然不是一個好主意,分區實施愈來愈廣泛。
▲firehose的模型是很是靈活的,而不像Twitter的firehose那樣數據被假定是丟失的。
▲firehose的信息流能夠及時的回放。他保留一週內的數據,能夠調出這期間任什麼時候間點的數據。
▲支持多個客戶端鏈接,並且不會看到重複的數據。每一個客戶端有一個ID。Kafka支持客戶羣,每一個羣中的客戶都用同一個ID,他們不會讀取重複的數據。能夠建立多個客戶端使用同一個ID,並且不會看到重複的數據。這將保證數據的獨立性和並行處理。Kafka使用ZooKeeper(Apache推出的開源分佈式應用程序協調服務。)按期檢查用戶閱讀了多少。
爲Dashboard收件箱設計的Cell架構
▲如今支持Dashboard的功能的分散-集中架構很是受限,這種情況不會持續好久。
▲解決方法是採用基於Cell架構的收件箱模型,與Facebook Messages很是類似。
▲收件箱與分散-集中架構是對立的。每一位用戶的dashboard都是由其追隨者的發言和行動組成的,並按照時間順序存儲。
▲就由於是收件箱就解決了分散-集中的問題。你能夠會問到底在收件箱中放了些什麼,讓其如此廉價。這種方式將運行很長時間。
▲重寫Dashboard很是困難。數據已經分佈,可是用戶局部升級產生的數據交換的質量尚未徹底搞定。
▲數據量是很是驚人的。平均每條消息轉發給上百個不一樣的用戶,這比Facebook面對的困難還要大。大數據+高分佈率+多個數據中心。
▲每秒鐘上百萬次寫入,5萬次讀取。沒有重複和壓縮的數據增加爲2.7TB,每秒百萬次寫入操做來自24字節行鍵。
▲已經流行的應用按此方法運行。
▲cell
▲每一個cell是獨立的,並保存着必定數量用戶的所有數據。在用戶的Dashboard中顯示的全部數據也在這個cell中。
▲用戶映射到cell。一個數據中心有不少cell。
▲每一個cell都有一個HBase的集羣,服務集羣,Redis的緩存集羣。
▲用戶歸屬到cell,全部cell的共同爲用戶發言提供支持。
▲每一個cell都基於Finagle(Twitter推出的異步的遠程過程調用庫),建設在HBase上,Thrift用於開發與firehose和各類請求與數據庫的連接。(請糾錯)
▲一個用戶進入Dashboard,其追隨者歸屬到特定的cell,這個服務節點經過HBase讀取他們的dashboard並返回數據。
▲後臺將追隨者的dashboard納入當前用戶的table,並處理請求。
▲Redis的緩存層用於cell內部處理用戶發言。
▲請求流:用戶發佈消息,消息將被寫入firehose,全部的cell處理這條消息並把發言文本寫入數據庫,cell查找是否全部發布消息追隨者都在本cell內,若是是的話,全部追隨者的收件箱將更新用戶的ID。(請糾錯)
▲cell設計的優勢:
▲大規模的請求被並行處理,組件相互隔離不會產生干擾。 cell是一個並行的單位,所以能夠任意調整規格以適應用戶羣的增加。
▲cell的故障是獨立的。一個Cell的故障不會影響其餘cell。
▲cell的表現很是好,可以進行各類升級測試,實施滾動升級,並測試不一樣版本的軟件。
▲關鍵的思想是容易遺漏的:全部的發言都是能夠複製到全部的cell。
▲每一個cell中存儲的全部發言的單一副本。 每一個cell能夠徹底知足Dashboard呈現請求。應用不用請求全部發言者的ID,只須要請求那些用戶的ID。(「那些用戶」所指不清,請指正。)他能夠在dashboard返回內容。每個cell均可以知足Dashboard的全部需求,而不須要與其餘cell進行通訊。
▲用到兩個HBase table :一個table用於存儲每一個發言的副本,這個table相對較小。在cell內,這些數據將與存儲每個發言者ID。第二個table告訴咱們用戶的dashboard不須要顯示全部的追隨者。當用戶經過不一樣的終端訪問一個發言,並不表明閱讀了兩次。收件箱模型能夠保證你閱讀到。
▲發言並不會直接進入到收件箱,由於那實在太大了。因此,發言者的ID將被髮送到收件箱,同時發言內容將進入cell。這個模式有效的減小了存儲需求,只須要返回用戶在收件箱中瀏覽發言的時間。而缺點是每個cell保存全部的發言副本。使人驚奇的是,全部發言比收件箱中的鏡像要小。(請糾錯)天天每一個cell的發言增加50GB,收件箱天天增加2.7TB。用戶消耗的資源遠遠超過他們製造的。
▲用戶的dashboard不包含發言的內容,只顯示發言者的ID,主要的增加來自ID。(請Tumblr用戶糾錯)
▲當追隨者改變時,這種設計方案也是安全的。由於全部的發言都保存在cell中了。若是隻有追隨者的發言保存在cell中,那麼當追隨者改變了,將須要一些回填工做。
▲另一種設計方案是採用獨立的發言存儲集羣。這種設計的缺點是,若是羣集出現故障,它會影響整個網站。所以,使用cell的設計以及後複製到全部cell的方式,建立了一個很是強大的架構。
▲一個用戶擁有上百萬的追隨者,這帶來很是大的困難,有選擇的處理用戶的追隨者以及他們的存取模式(見Feeding Frenzy)
▲不一樣的用戶採用不一樣而且恰當的存取模式和分佈模型,兩個不一樣的分佈模式包括:一個適合受歡迎的用戶,一個使用大衆。
▲依據用戶的類型採用不一樣的數據處理方式,活躍用戶的發言並不會被真正發佈,發言將被有選擇的體現。(果然如此?請Tumblr用戶糾錯)
▲追隨了上百萬用戶的用戶,將像擁有上百萬追隨者的用戶那樣對待。
▲cell的大小很是難於決定。cell的大小直接影響網站的成敗。每一個cell歸於的用戶數量是影響力之一。須要權衡接受怎樣的用戶體驗,以及爲之付出多少投資。
▲從firehose中讀取數據將是對網絡最大的考驗。在cell內部網絡流量是可管理的。
▲當更多cell被增添到網絡中來,他們能夠進入到cell組中,並從firehose中讀取數據。一個分層的數據複製計劃。這能夠幫助遷移到多個數據中心。
在紐約啓動運做
紐約具備獨特的環境,資金和廣告充足。招聘極具挑戰性,由於缺少創業經驗。
在過去的幾年裏,紐約一直致力於推進創業。紐約大學和哥倫比亞大學有一些項目,鼓勵學生到初創企業實習,而不只僅去華爾街。市長創建了一所學院,側重於技術。
團隊架構
▲團隊:基礎架構,平臺,SRE,產品,web ops,服務;
▲基礎架構:5層如下,IP地址和DNS,硬件配置;
▲平臺:核心應用開發,SQL分片,服務,Web運營;
▲SRE:在平臺和產品之間,側重於解決可靠性和擴展性的燃眉之急;
▲服務團隊:相對而言更具戰略性,
▲Web ops:負責問題檢測、響應和優化。
軟件部署
▲開發了一套rsync腳本,能夠隨處部署PHP應用程序。一旦機器的數量超過200臺,系統便開始出現問題,部署花費了很長時間才完成,機器處於部署進程中的各類狀態。
▲接下來,使用Capistrano(一個開源工具,能夠在多臺服務器上運行腳本)在服務堆棧中構建部署進程(開發、分期、生產)。在幾十臺機器上部署能夠正常工做,但當經過SSH部署到數百臺服務器時,再次失敗。
▲如今,全部的機器上運行一個協調軟件。基於Redhat Func(一個安全的、腳本化的遠程控制框架和接口)功能,一個輕量級的API用於向主機發送命令,以構建擴展性。
▲創建部署是在Func的基礎上向主機發送命令,避免了使用SSH。好比,想在組A上部署軟件,控制主機就能夠找出隸屬於組A的節點,並運行部署命令。
▲部署命令經過Capistrano實施。
▲Func API可用於返回狀態報告,報告哪些機器上有這些軟件版本。
▲安全重啓任何服務,由於它們會關閉鏈接,而後重啓。
▲在激活前的黑暗模式下運行全部功能。
展望
▲從哲學上將,任何人均可以使用本身想要的任意工具。但隨着團隊的發展壯大,這些工具出現了問題。新員工想要更好地融入團隊,快速地解決問題,必須以他們爲中心,創建操做的標準化。
▲過程相似於Scrum(一種敏捷管理框架),很是敏捷。
▲每一個開發人員都有一臺預配置的開發機器,並按照控制更新。
▲開發機會出現變化,測試,分期,乃至用於生產。
▲開發者使用VIM和TextMate。
▲測試是對PHP程序進行代碼審覈。
▲在服務方面,他們已經實現了一個與提交相掛鉤的測試基礎架構,接下來將繼承並內建通知機制。
招聘流程
▲面試一般避免數學、猜謎、腦筋急轉彎等問題,而着重關注應聘者在工做中實際要作什麼。
▲着重編程技能。
▲面試不是比較,只是要找對的人。
▲挑戰在於找到具備可用性、擴展性經驗的人才,以應對Tumblr面臨的網絡擁塞。
▲在Tumblr工程博客(Tumblr Engineering Blog),他們對已過世的Dennis Ritchie和John McCarthy予以記念。
經驗及教訓
▲自動化無處不在
▲MySQL(增長分片)規模,應用程序暫時還不行
▲Redis總能帶給人驚喜
▲基於Scala語言的應用執行效率是出色的
▲廢棄項目——當你不肯定將如何工做時
▲不顧用在他們發展經歷中沒經歷過技術挑戰的人,聘用有技術實力的人是由於他們能適合你的團隊以 及工做。
▲選擇正確的軟件集合將會幫助你找到你須要的人
▲創建團隊的技能
▲閱讀文檔和博客文章。
▲多與同行交流,能夠接觸一些領域中經驗豐富的人,例如與在Facebook、Twitter、LinkedIn的工程師 多交流,從他們身上能夠學到不少
▲對技術要按部就班,在正式投入使用以前他們煞費苦心的學習HBase和Redis。同時在試點項目中使用 或將其控制在有限損害範圍以內。
翻譯:包研,張志平,劉江;審校:劉江