Tumblr 架構(gòu)設(shè)計(jì)
最近的新聞中我們得知雅虎11億美元收購(gòu)了Tumblr: Yahoo bought Tumblr for $1.1 billion. 你也許會(huì)發(fā)現(xiàn)Instagram也被Facebook重金收購(gòu)的介紹. 這是一個(gè)巧合嗎?這就由你來(lái)判斷吧。
為什么雅虎會(huì)收購(gòu)Tumblr? 這場(chǎng)交易中的商業(yè)價(jià)值我可能無(wú)法判斷,但是如果你對(duì)Tumblr的技術(shù)方面有所了解,你一定會(huì)為Tumblr豎起大拇指. 為什么這么說(shuō)呢,請(qǐng)接著讀... Tumblr每月頁(yè)面瀏覽量超過(guò)150億次,已經(jīng)成為火爆的博客社區(qū)。用戶也許喜歡它的簡(jiǎn)約、漂亮,并且它對(duì)用戶體驗(yàn)強(qiáng)烈的關(guān)注,或是友好而忙碌的溝通方式,總之,它深得人們的喜愛。
每月超過(guò)30%的增長(zhǎng)當(dāng)然不可能沒(méi)有挑戰(zhàn),其中可靠性問(wèn)題尤為艱巨。每天5億次瀏覽量,峰值每秒4萬(wàn)次請(qǐng)求,每天3TB新的數(shù)據(jù)存儲(chǔ),并運(yùn)行于超過(guò)1000臺(tái)服務(wù)器上,所有這些幫助Tumblr實(shí)現(xiàn)巨大的經(jīng)營(yíng)規(guī)模。
創(chuàng)業(yè)公司邁向成功,都要邁過(guò)危險(xiǎn)的迅速發(fā)展期這道門檻。尋找人才,不斷改造基礎(chǔ)架構(gòu),維護(hù)舊的架構(gòu),同時(shí)要面對(duì)逐月大增的流量,而且曾經(jīng)只有4位工程師。這意味著必須艱難地選擇應(yīng)該做什么,不該做什么。這就是Tumblr的狀況。好在現(xiàn)在已經(jīng)有20位工程師了,可以有精力解決問(wèn)題,并開發(fā)一些有意思的解決方案。
Tumblr最開始是非常典型的LAMP應(yīng)用。目前正在向分布式服務(wù)模型演進(jìn),該模型基于Scala、HBase、Redis、Kafka、Finagle,此外還有一個(gè)有趣的基于Cell的架構(gòu),用于支持Dashboard .現(xiàn)在的重點(diǎn)被放在了解決他們PHP程序中的短期問(wèn)題,找出問(wèn)題,并正確的使用服務(wù)化去解決他們. Tumblr目前的最大問(wèn)題是如何改造為一個(gè)大規(guī)模網(wǎng)站。系統(tǒng)架構(gòu)正在從LAMP演進(jìn)為最先進(jìn)的技術(shù)組合,同時(shí)團(tuán)隊(duì)也要從小的創(chuàng)業(yè)型發(fā)展為全副武裝、隨時(shí)待命的正規(guī)開發(fā)團(tuán)隊(duì),不斷創(chuàng)造出新的功能和基礎(chǔ)設(shè)施。下面就是Blake對(duì)Tumblr系統(tǒng)架構(gòu)情況的介紹。
Tumblr網(wǎng)址: http://www.tumblr.com/
統(tǒng)計(jì)
- 每天 5 億頁(yè)面瀏覽量
- 每月超過(guò) 150億 頁(yè)面瀏覽量
- 約 20 名工程師
- 峰值每秒大約 4 萬(wàn)請(qǐng)求
- 每天有超過(guò) 1TB 的數(shù)據(jù)進(jìn)入 Hadoop 集群
- 每天有幾個(gè) TB 的數(shù)據(jù)進(jìn)入 MySQL/HBase/Redis/Memcache
- 每月增長(zhǎng) 30%
- 產(chǎn)品環(huán)境有大約 1000 個(gè)硬件節(jié)點(diǎn)
- 平均每個(gè)工程師每月處理10億頁(yè)面訪問(wèn)
- 每天大約 50GB 的文章,關(guān)注者列表更新大約每天 2.7TB
- Dashboard 每秒百萬(wàn)次寫,每秒 5w 讀
軟件
- OS X 用于開發(fā),產(chǎn)品環(huán)境用 Linux (CentOS, Scientific)
- Apache
- PHP, Scala, Ruby
- Redis, HBase, MySQL
- Varnish, HA-Proxy, nginx,
- Memcache, Gearman, Kafka, Kestrel, Finagle
- Thrift, HTTP
- Func - 一個(gè)安全的、腳本化的遠(yuǎn)程控制框架和 API
- Git, Capistrano, Puppet, Jenkins
硬件
- 500 臺(tái) Web 服務(wù)器
- 200 數(shù)據(jù)庫(kù)服務(wù)器 (大多數(shù)是備用池)
- 47 個(gè)池
- 30 個(gè)分區(qū)
- 30 臺(tái) memcache 服務(wù)器
- 22 臺(tái) redis 服務(wù)器
- 15 臺(tái) varnish 服務(wù)器
- 25 個(gè) haproxy 節(jié)點(diǎn)
- 8 個(gè) nginx
- 14 個(gè)作業(yè)隊(duì)列服務(wù)器 (kestrel + gearman)
構(gòu)架
- 與其他社交網(wǎng)站不同的是,Tumblr有其獨(dú)特的使用模式。
- 每天有超過(guò)5千萬(wàn)篇文章更新,平均每篇文章的跟帖又?jǐn)?shù)以百計(jì)。用戶一般只有數(shù)百個(gè)粉絲。這與其他社會(huì)化網(wǎng)站里少數(shù)用戶有幾百萬(wàn)粉絲非常不同,使得Tumblr的擴(kuò)展性極具挑戰(zhàn)性。
- 按用戶使用時(shí)間衡量,Tumblr已經(jīng)是排名第二的社會(huì)化網(wǎng)站。內(nèi)容的吸引力很強(qiáng),有很多圖片和視頻,文章往往不短,一般也不會(huì)太長(zhǎng),但允許寫得很長(zhǎng)。文章內(nèi)容往往比較深入,用戶會(huì)花費(fèi)更長(zhǎng)的時(shí)間來(lái)閱讀。
- 用戶與其他用戶建立聯(lián)系后,可能會(huì)在Dashboard上往回翻幾百頁(yè)逐篇閱讀,這與其他網(wǎng)站基本上只是部分信息流不同。
- 用戶的數(shù)量龐大,用戶的平均到達(dá)范圍更廣,用戶較頻繁的發(fā)帖,這些都意味著有巨量的更新需要處理。
- Tumblr目前運(yùn)行在一個(gè)托管數(shù)據(jù)中心中,已在考慮地域上的分布式構(gòu)架。
- Tumblr平臺(tái)由兩個(gè)組件構(gòu)成:公共Tumblelogs和Dashboard
- 公共Tumblelogs與博客類似,并非動(dòng)態(tài),易于緩存
- Dashboard是類似于Twitter的時(shí)間軸,用戶由此可以看到自己關(guān)注的所有用戶的實(shí)時(shí)更新。
- 與博客的擴(kuò)展性不同,緩存作用不大,因?yàn)槊看握?qǐng)求都不同,尤其是活躍的關(guān)注者。
- 而且需要實(shí)時(shí)而且一致,文章每天僅更新50GB,跟帖每天更新2.7TB,所有的多媒體數(shù)據(jù)都存儲(chǔ)在S3上面。
- 大多數(shù)用戶以Tumblr作為內(nèi)容瀏覽工具,每天瀏覽超過(guò)5億個(gè)頁(yè)面,70%的瀏覽來(lái)自Dashboard。
- Dashboard的可用性已經(jīng)不錯(cuò),但Tumblelog一直不夠好,因?yàn)榛A(chǔ)設(shè)施是老的,而且很難遷移。由于人手不足,一時(shí)半會(huì)兒還顧不上。
老的Tumblr構(gòu)架
- Tumblr最開始是托管在Rackspace上的,每個(gè)自定義域名的博客都有一個(gè)A記錄。當(dāng)2007年Rackspace無(wú)法滿足其發(fā)展速度不得不遷移時(shí),大量的用戶都需要同時(shí)遷移。所以他們不得不將自定義域名保留在Rackspace,然后再使用HAProxy和Varnish路由到新的數(shù)據(jù)中心。類似這樣的遺留問(wèn)題很多。
- 開始的架構(gòu)演進(jìn)是典型的LAMP路線
- 最初用PHP開發(fā),幾乎所有程序員都用PHP
- 最初是三臺(tái)服務(wù)器:一臺(tái)Web,一臺(tái)數(shù)據(jù)庫(kù),一臺(tái)PHP
- 為了擴(kuò)展,開始使用memcache,然后引入前端cache,然后在cache前再加HAProxy,然后是非常奏效的MySQL sharding
- 采用“在單臺(tái)服務(wù)器上榨出一切”的方式。過(guò)去一年已經(jīng)用C開發(fā)了兩個(gè)后端服務(wù):ID generator和Staircar(用Redis進(jìn)行Dashboard通知)
- Dashboard采用了“擴(kuò)散-收集”方式。當(dāng)用戶訪問(wèn)Dashboard時(shí)將顯示事件,來(lái)自所關(guān)注的用戶的事件是通過(guò)拉然后顯示的。這樣支撐了6個(gè)月。由于數(shù)據(jù)是按時(shí)間排序的,因此sharding模式不太管用。
新的構(gòu)架
- 由于招人和開發(fā)速度等原因,改為以JVM為中心。
- 目標(biāo)是將一切從PHP應(yīng)用改為服務(wù),使應(yīng)用變成請(qǐng)求鑒別、呈現(xiàn)等諸多服務(wù)之上的薄層。
- 選擇了Scala 和 Finagle
- 在團(tuán)隊(duì)內(nèi)部有很多人具備Ruby和PHP經(jīng)驗(yàn),所以Scala很有吸引力。
- Finagle是選擇Scala的重要因素之一。這個(gè)來(lái)自Twitter的庫(kù)可以解決大多數(shù)分布式問(wèn)題,比如分布式跟蹤、服務(wù)發(fā)現(xiàn)、服務(wù)注冊(cè)等。
- 轉(zhuǎn)到JVM上之后,F(xiàn)inagle提供了團(tuán)隊(duì)所需的所有基本功能(Thrift, ZooKeeper等),無(wú)需再開發(fā)許多網(wǎng)絡(luò)代碼,另外,團(tuán)隊(duì)成員認(rèn)識(shí)該項(xiàng)目的一些開發(fā)者。
- Foursquare和Twitter都在用Finagle,Meetup也在用Scala。
- 應(yīng)用接口與Thrift類似,性能極佳。
- 團(tuán)隊(duì)本來(lái)很喜歡Netty,但不想用Java,Scala是不錯(cuò)的選擇。
- 選擇Finagle是因?yàn)樗芸?,還認(rèn)識(shí)幾個(gè)開發(fā)者。
- 之所以沒(méi)有選擇Node.js,是因?yàn)橐訨VM為基礎(chǔ)更容易擴(kuò)展。Node的發(fā)展為時(shí)尚短,缺乏標(biāo)準(zhǔn)、最佳實(shí)踐以及大量久經(jīng)測(cè)試的代碼。而用Scala的話,可以使用所有Java代碼。雖然其中并沒(méi)有多少可擴(kuò)展的東西,也無(wú)法解決5毫秒響應(yīng)時(shí)間、49秒HA、4萬(wàn)每秒請(qǐng)求甚至有時(shí)每秒40萬(wàn)次請(qǐng)求的問(wèn)題。但是,Java的生態(tài)鏈要大得多,有很多資源可以利用。
- 內(nèi)部服務(wù)從C/libevent為基礎(chǔ)正在轉(zhuǎn)向Scala/Finagle為基礎(chǔ)。
- 開始采用新的NoSQL存儲(chǔ)方案如HBase和Redis。但大量數(shù)據(jù)仍然存儲(chǔ)在大量分區(qū)的MySQL架構(gòu)中,并沒(méi)有用HBase代替MySQL。
- HBase主要支持短地址生產(chǎn)程序(數(shù)以十億計(jì))還有歷史數(shù)據(jù)和分析,非常結(jié)實(shí)。此外,HBase也用于高寫入需求場(chǎng)景,比如Dashboard刷新時(shí)一秒上百萬(wàn)的寫入。之所以還沒(méi)有替換HBase,是因?yàn)椴荒苊皹I(yè)務(wù)上風(fēng)險(xiǎn),目前還是依靠人來(lái)負(fù)責(zé)更保險(xiǎn),先在一些小的、不那么關(guān)鍵的項(xiàng)目中應(yīng)用,以獲得經(jīng)驗(yàn)。
- MySQL和時(shí)間序列數(shù)據(jù)sharding(分片)的問(wèn)題在于,總有一個(gè)分片太熱。另外,由于要在slave上插入并發(fā),也會(huì)遇到讀復(fù)制延遲問(wèn)題。
- 此外,還開發(fā)了一個(gè)公用服務(wù)框架:
- 花了很多時(shí)間解決分布式系統(tǒng)管理這個(gè)運(yùn)維問(wèn)題。
- 為服務(wù)開發(fā)了一種Rails scaffolding,內(nèi)部用模板來(lái)啟動(dòng)服務(wù)。
- 所有服務(wù)從運(yùn)維的角度來(lái)看都是一樣的,所有服務(wù)檢查統(tǒng)計(jì)數(shù)據(jù)、監(jiān)控、啟動(dòng)和停止的方式都一樣。
- 工具方面,構(gòu)建過(guò)程圍繞SBT(一個(gè)Scala構(gòu)建工具),使用插件和輔助程序管理常見操作,包括在Git里打標(biāo)簽,發(fā)布到代碼庫(kù)等等。大多數(shù)程序員都不用再操心構(gòu)建系統(tǒng)的細(xì)節(jié)了。
- 40臺(tái)服務(wù)器采用HAProxy進(jìn)行負(fù)載均衡,Varnish進(jìn)行緩存.
- 200臺(tái)數(shù)據(jù)庫(kù)服務(wù)器中,很多是為了提高可用性而設(shè),使用的是常規(guī)硬件,但MTBF(平均故障間隔時(shí)間)極低。故障時(shí),備用充足。
- 500臺(tái)服務(wù)器運(yùn)行Apache和其他PHP程序。
- 6個(gè)為了支持PHP應(yīng)用的后端服務(wù),并有一個(gè)小組專門開發(fā)后端服務(wù)。新服務(wù)的發(fā)布需要兩到三周,包括Dashboard通知、Dashboard二級(jí)索引、短地址生成、處理透明分片的memcache代理。
- 其中在MySQL分片上耗時(shí)很多。雖然在紐約本地非常熱,但并沒(méi)有使用MongoDB,他們認(rèn)為MySQL的可擴(kuò)展性足夠了。
- Gearman用于會(huì)長(zhǎng)期運(yùn)行無(wú)需人工干預(yù)的工作。
- 可用性是以達(dá)到范圍(reach)衡量的。用戶能夠訪問(wèn)自定義域或者Dashboard嗎?也會(huì)用錯(cuò)誤率。
- 歷史上總是解決那些最高優(yōu)先級(jí)的問(wèn)題,而現(xiàn)在會(huì)對(duì)故障模式系統(tǒng)地分析和解決,目的是從用戶和應(yīng)用的角度來(lái)定成功指標(biāo)。
- 最開始Finagle是用于Actor模型的,但是后來(lái)放棄了。對(duì)于運(yùn)行后無(wú)需人工干預(yù)的工作,使用任務(wù)隊(duì)列。而且Twitter的util工具庫(kù)中有Future實(shí)現(xiàn),服務(wù)都是用Future(Scala中的無(wú)參數(shù)函數(shù),在與函數(shù)關(guān)聯(lián)的并行操作沒(méi)有完成時(shí),會(huì)阻塞調(diào)用方)實(shí)現(xiàn)的。當(dāng)需要線程池的時(shí)候,就將Future傳入Future池。一切都提交到Future池進(jìn)行異步執(zhí)行。
- Scala提倡無(wú)共享狀態(tài)。由于已經(jīng)在Twitter生產(chǎn)環(huán)境中經(jīng)過(guò)測(cè)試,F(xiàn)inagle這方面應(yīng)該是沒(méi)有問(wèn)題的。使用Scala和Finagle中的結(jié)構(gòu)需要避免可變狀態(tài),不使用長(zhǎng)期運(yùn)行的狀態(tài)機(jī)。狀態(tài)從數(shù)據(jù)庫(kù)中拉出、使用再寫回?cái)?shù)據(jù)庫(kù)。這樣做的好處是,開發(fā)人員不需要操心線程和鎖。
- 22臺(tái)Redis服務(wù)器,每臺(tái)的都有8-32個(gè)實(shí)例,因此線上同時(shí)使用了100多個(gè)Redis實(shí)例。
- Redis主要用于Dashboard通知的后端存儲(chǔ)。
- 所謂通知就是指某個(gè)用戶like了某篇文章這樣的事件。通知會(huì)在用戶的Dashboard中顯示,告訴他其他用戶對(duì)其內(nèi)容做了哪些操作。
- 高寫入率使MySQL無(wú)法應(yīng)對(duì)。
- 通知轉(zhuǎn)瞬即逝,所以即使遺漏也不會(huì)有嚴(yán)重問(wèn)題,因此Redis是這一場(chǎng)景的合適選擇。
- 這也給了開發(fā)團(tuán)隊(duì)了解Redis的機(jī)會(huì)。
- 使用中完全沒(méi)有發(fā)現(xiàn)Redis有任何問(wèn)題,社區(qū)也非常棒。
- 開發(fā)了一個(gè)基于Scala Futures的Redis接口,該功能現(xiàn)在已經(jīng)并入了Cell架構(gòu)。
- 短地址生成程序使用Redis作為一級(jí)Cache,HBase作為永久存儲(chǔ)。
- Dashboard的二級(jí)索引是以Redis為基礎(chǔ)開發(fā)的。
- Redis還用作Gearman的持久存儲(chǔ)層,使用Finagle開發(fā)的memcache代理。
- 正在緩慢地從memcache轉(zhuǎn)向Redis。希望最終只用一個(gè)cache服務(wù)。性能上Redis與memcache相當(dāng)。
#p#
內(nèi)部通訊管道(Firehose)
- 內(nèi)部的應(yīng)用需要活躍的信息流通道。這些信息包括用戶創(chuàng)建/刪除的信息,liking/unliking 的提示,等等。挑戰(zhàn)在于這些數(shù)據(jù)要實(shí)時(shí)的分布式處理。我們希望能夠檢測(cè)內(nèi)部運(yùn)行狀況,應(yīng)用的生態(tài)系統(tǒng)能夠可靠的生長(zhǎng),同時(shí)還需要建設(shè)分布式系統(tǒng)的控制中心。
- 以前,這些信息是基于 Scribe (Facebook 開源的分布式日志系統(tǒng)。)/Hadoop 的分布式系統(tǒng)。服務(wù)會(huì)先記錄在 Scribe 中,并持續(xù)的長(zhǎng)尾形式寫入,然后將數(shù)據(jù)輸送給應(yīng)用。這種模式可以立即停止伸縮,尤其在峰值時(shí)每秒要?jiǎng)?chuàng)建數(shù)以千計(jì)的信息。不要指望人們會(huì)細(xì)水長(zhǎng)流式的發(fā)布文 件和 grep。
- 內(nèi)部的 firehose 就像裝載著信息的大巴,各種服務(wù)和應(yīng)用通過(guò) Thrift 與消防管線溝通。(一個(gè)可伸縮的跨語(yǔ)言的服務(wù)開發(fā)框架。)
- LinkedIn 的 Kafka 用于存儲(chǔ)信息。內(nèi)部人員通過(guò) HTTP 鏈接 firehose。經(jīng)常面對(duì)巨大的數(shù)據(jù)沖擊,采用 MySQL 顯然不是一個(gè)好主意,分區(qū)實(shí)施越來(lái)越普遍。
- firehose 的模型是非常靈活的,而不像 Twitter 的 firehose 那樣數(shù)據(jù)被假定是丟失的。
- firehose 的信息流可以及時(shí)的回放。他保留一周內(nèi)的數(shù)據(jù),可以調(diào)出這期間任何時(shí)間點(diǎn)的數(shù)據(jù)。
- 支持多個(gè)客戶端連接,而且不會(huì)看到重復(fù)的數(shù)據(jù)。每個(gè)客戶端有一個(gè) ID。Kafka 支持客戶群,每個(gè)群中的客戶都用同一個(gè) ID,他們不會(huì)讀取重復(fù)的數(shù)據(jù)??梢詣?chuàng)建多個(gè)客戶端使用同一個(gè) ID,而且不會(huì)看到重復(fù)的數(shù)據(jù)。這將保證數(shù)據(jù)的獨(dú)立性和并行處理。Kafka 使用 ZooKeeper (Apache 推出的開源分布式應(yīng)用程序協(xié)調(diào)服務(wù)。)定期檢查用戶閱讀了多少。
為 Dashboard 收件箱設(shè)計(jì)的 Cell 架構(gòu)
- 現(xiàn)在支持 Dashboard 的功能的分散-集中架構(gòu)非常受限,這種狀況不會(huì)持續(xù)很久。
- 解決方法是采用基于 Cell 架構(gòu)的收件箱模型,與 Facebook Messages 非常相似。
- 收件箱與分散-集中架構(gòu)是對(duì)立的。每一位用戶的 dashboard 都是由其追隨者的發(fā)言和行動(dòng)組成的,并按照時(shí)間順序存儲(chǔ)。
- 就因?yàn)槭鞘占渚徒鉀Q了分散-集中的問(wèn)題。你可以會(huì)問(wèn)到底在收件箱中放了些什么,讓其如此廉價(jià)。這種方式將運(yùn)行很長(zhǎng)時(shí)間。
- 重寫 Dashboard 非常困難。數(shù)據(jù)已經(jīng)分布,但是用戶局部升級(jí)產(chǎn)生的數(shù)據(jù)交換的質(zhì)量還沒(méi)有完全搞定。
- 數(shù)據(jù)量是非常驚人的。平均每條消息轉(zhuǎn)發(fā)給上百個(gè)不同的用戶,這比 Facebook 面對(duì)的困難還要大。大數(shù)據(jù)+高分布率+多個(gè)數(shù)據(jù)中心。
- 每秒鐘上百萬(wàn)次寫入,5萬(wàn)次讀取。沒(méi)有重復(fù)和壓縮的數(shù)據(jù)增長(zhǎng)為2.7TB,每秒百萬(wàn)次寫入操作來(lái)自 24 字節(jié)行鍵。
- 已經(jīng)流行的應(yīng)用按此方法運(yùn)行。
- Cell構(gòu)架
- 每個(gè) cell 是獨(dú)立的,并保存著一定數(shù)量用戶的全部數(shù)據(jù)。在用戶的 Dashboard 中顯示的所有數(shù)據(jù)也在這個(gè) cell 中。
- 用戶映射到 cell。一個(gè)數(shù)據(jù)中心有很多 cell。
- 每個(gè) cell 都有一個(gè) HBase 的集群,服務(wù)集群,Redis 的緩存集群。
- 用戶歸屬到 cell,所有 cell 的共同為用戶發(fā)言提供支持。
- 每個(gè) cell 都基于 Finagle(Twitter 推出的異步的遠(yuǎn)程過(guò)程調(diào)用庫(kù)),建設(shè)在 HBase 上,Thrift 用于開發(fā)與 firehose 和各種請(qǐng)求與數(shù)據(jù)庫(kù)的鏈接。
- 一個(gè)用戶進(jìn)入 Dashboard,其追隨者歸屬到特定的 cell,這個(gè)服務(wù)節(jié)點(diǎn)通過(guò) HBase 讀取他們的 dashboard 并返回?cái)?shù)據(jù)。
- 后臺(tái)將追隨者的 dashboard 歸入當(dāng)前用戶的 table,并處理請(qǐng)求。
- Redis 的緩存層用于 cell 內(nèi)部處理用戶發(fā)言。
- 請(qǐng)求流:用戶發(fā)布消息,消息將被寫入 firehose,所有的 cell 處理這條消息并把發(fā)言文本寫入數(shù)據(jù)庫(kù),cell 查找是否所有發(fā)布消息追隨者都在本 cell 內(nèi),如果是的話,所有追隨者的收件箱將更新用戶的 ID。
- cell 構(gòu)架的優(yōu)點(diǎn):
- 大規(guī)模的請(qǐng)求被并行處理,組件相互隔離不會(huì)產(chǎn)生干擾。 cell 是一個(gè)并行的單位,因此可以任意調(diào)整規(guī)格以適應(yīng)用戶群的增長(zhǎng)。
- cell 的故障是獨(dú)立的。一個(gè) Cell 的故障不會(huì)影響其他 cell。
- cell 的表現(xiàn)非常好,能夠進(jìn)行各種升級(jí)測(cè)試,實(shí)施滾動(dòng)升級(jí),并測(cè)試不同版本的軟件。
- 關(guān)鍵的思想是容易遺漏的:所有的發(fā)言都是可以復(fù)制到所有的 cell。
- 每個(gè) cell 中存儲(chǔ)的所有發(fā)言的單一副本。 每個(gè) cell 可以完全滿足 Dashboard 呈現(xiàn)請(qǐng)求。應(yīng)用不用請(qǐng)求所有發(fā)言者的 ID,只需要請(qǐng)求那些用戶的 ID。他可以在 dashboard 返回內(nèi)容。每一個(gè) cell 都可以滿足 Dashboard 的所有需求,而不需要與其他 cell 進(jìn)行通信。
- 用到兩個(gè) HBase table :一個(gè) table 用于存儲(chǔ)每個(gè)發(fā)言的副本,這個(gè) table 相對(duì)較小。在 cell 內(nèi),這些數(shù)據(jù)將與存儲(chǔ)每一個(gè)發(fā)言者 ID。第二個(gè) table 告訴我們用戶的 dashboard 不需要顯示所有的追隨者。當(dāng)用戶通過(guò)不同的終端訪問(wèn)一個(gè)發(fā)言,并不代表閱讀了兩次。收件箱模型可以保證你閱讀到。
- 發(fā)言并不會(huì)直接進(jìn)入到收件箱,因?yàn)槟菍?shí)在太大了。所以,發(fā)言者的 ID 將被發(fā)送到收件箱,同時(shí)發(fā)言內(nèi)容將進(jìn)入 cell。這個(gè)模式有效的減少了存儲(chǔ)需求,只需要返回用戶在收件箱中瀏覽發(fā)言的時(shí)間。而缺點(diǎn)是每一個(gè) cell 保存所有的發(fā)言副本。令人驚奇的是,所有發(fā)言比收件箱中的鏡像要小。每天每個(gè) cell 的發(fā)言增長(zhǎng) 50GB,收件箱每天增長(zhǎng)2.7TB。用戶消耗的資源遠(yuǎn)遠(yuǎn)超過(guò)他們制造的。
- 用戶的 dashboard 不包含發(fā)言的內(nèi)容,只顯示發(fā)言者的 ID,主要的增長(zhǎng)來(lái)自 ID。
- 當(dāng)追隨者改變時(shí),這種設(shè)計(jì)方案也是安全的。因?yàn)樗械陌l(fā)言都保存在 cell 中了。如果只有追隨者的發(fā)言保存在 cell 中,那么當(dāng)追隨者改變了,將需要一些回填工作。
- 另外一種設(shè)計(jì)方案是采用獨(dú)立的發(fā)言存儲(chǔ)集群。這種設(shè)計(jì)的缺點(diǎn)是,如果群集出現(xiàn)故障,它會(huì)影響整個(gè)網(wǎng)站。因此,使用 cell 的設(shè)計(jì)以及后復(fù)制到所有 cell 的方式,創(chuàng)建了一個(gè)非常強(qiáng)大的架構(gòu)。
- 一個(gè)用戶擁有上百萬(wàn)的追隨者,這帶來(lái)非常大的困難,有選擇的處理用戶的追隨者以及他們的存取模式(見Feeding Frenzy)
- 不同的用戶采用不同并且恰當(dāng)?shù)拇嫒∧J胶头植寄P?,兩個(gè)不同的分布模式包括:一個(gè)適合受歡迎的用戶,一個(gè)使用大眾。
- 依據(jù)用戶的類型采用不同的數(shù)據(jù)處理方式,活躍用戶的發(fā)言并不會(huì)被真正發(fā)布,發(fā)言將被有選擇的體現(xiàn)。
- 追隨了上百萬(wàn)用戶的用戶,將像擁有上百萬(wàn)追隨者的用戶那樣對(duì)待。
- cell 的大小非常難于決定。cell 的大小直接影響網(wǎng)站的成敗。每個(gè) cell 歸于的用戶數(shù)量是影響力之一。需要權(quán)衡接受怎樣的用戶體驗(yàn),以及為之付出多少投資。
- 從 firehose 中讀取數(shù)據(jù)將是對(duì)網(wǎng)絡(luò)最大的考驗(yàn)。在 cell 內(nèi)部網(wǎng)絡(luò)流量是可管理的。
- 當(dāng)更多 cell 被增添到網(wǎng)絡(luò)中來(lái),他們可以進(jìn)入到 cell 組中,并從 firehose 中讀取數(shù)據(jù)。一個(gè)分層的數(shù)據(jù)復(fù)制計(jì)劃。這可以幫助遷移到多個(gè)數(shù)據(jù)中心。
在紐約啟動(dòng)運(yùn)作
- 紐約具有獨(dú)特的環(huán)境,資金和廣告充足。招聘極具挑戰(zhàn)性,因?yàn)槿狈?chuàng)業(yè)經(jīng)驗(yàn)。
- 在過(guò)去的幾年里,紐約一直致力于推動(dòng)創(chuàng)業(yè)。紐約大學(xué)和哥倫比亞大學(xué)有一些項(xiàng)目,鼓勵(lì)學(xué)生到初創(chuàng)企業(yè)實(shí)習(xí),而不僅僅去華爾街。市長(zhǎng)建立了一所學(xué)院,側(cè)重于技術(shù)。
團(tuán)隊(duì)架構(gòu)
- 團(tuán)隊(duì):基礎(chǔ)架構(gòu),平臺(tái),SRE,產(chǎn)品,web ops,服務(wù)
- 基礎(chǔ)架構(gòu):5層以下,IP 地址和 DNS,硬件配置
- 平臺(tái):核心應(yīng)用開發(fā),SQL 分片,服務(wù),Web 運(yùn)營(yíng)
- SRE:在平臺(tái)和產(chǎn)品之間,側(cè)重于解決可靠性和擴(kuò)展性的燃眉之急
- 服務(wù)團(tuán)隊(duì):相對(duì)而言更具戰(zhàn)略性
- Web ops:負(fù)責(zé)問(wèn)題檢測(cè)、響應(yīng)和優(yōu)化
軟件部署
- 開發(fā)了一套 rsync 腳本,可以隨處部署 PHP 應(yīng)用程序。一旦機(jī)器的數(shù)量超過(guò) 200 臺(tái),系統(tǒng)便開始出現(xiàn)問(wèn)題,部署花費(fèi)了很長(zhǎng)時(shí)間才完成,機(jī)器處于部署進(jìn)程中的各種狀態(tài)。
- 接下來(lái),使用 Capistrano(一個(gè)開源工具,可以在多臺(tái)服務(wù)器上運(yùn)行腳本)在服務(wù)堆棧中構(gòu)建部署進(jìn)程(開發(fā)、分期、生產(chǎn))。在幾十臺(tái)機(jī)器上部署可以正常工作,但當(dāng)通過(guò) SSH 部署到數(shù)百臺(tái)服務(wù)器時(shí),再次失敗。
- 現(xiàn)在,所有的機(jī)器上運(yùn)行一個(gè)協(xié)調(diào)軟件?;?Redhat Func(一個(gè)安全的、腳本化的遠(yuǎn)程控制框架和接口)功能,一個(gè)輕量級(jí)的 API 用于向主機(jī)發(fā)送命令,以構(gòu)建擴(kuò)展性。
- 建立部署是在 Func 的基礎(chǔ)上向主機(jī)發(fā)送命令,避免了使用 SSH。比如,想在組A上部署軟件,控制主機(jī)就可以找出隸屬于組A的節(jié)點(diǎn),并運(yùn)行部署命令。
- 通過(guò)Capistrano的命令實(shí)現(xiàn)部署。它可以可以從git倉(cāng)庫(kù)中拉取代碼。正因?yàn)槭腔贖TTP的,所以非常易于擴(kuò)展。他們喜歡 Capistrano,因?yàn)樗С趾?jiǎn)單的基于目錄的版本控制,能夠很好地管理PHP程序。版本更新的時(shí)候,每個(gè)目錄都包含一個(gè)SHA,所以很容易檢查版本的正確性。
- Func API 可用于返回狀態(tài)報(bào)告,報(bào)告哪些機(jī)器上有這些軟件版本。
- 安全重啟任何服務(wù),因?yàn)樗鼈儠?huì)關(guān)閉連接,然后重啟。
- 在激活前的黑暗模式下運(yùn)行所有功能。
開發(fā)
- 從哲學(xué)上,任何人都可以使用自己想要的任意工具。但隨著團(tuán)隊(duì)的發(fā)展壯大,這些工具出現(xiàn)了問(wèn)題。新員工想要更好地融入團(tuán)隊(duì),快速地解決問(wèn)題,必須以他們?yōu)橹行模⒉僮鞯臉?biāo)準(zhǔn)化。
- 過(guò)程類似于 Scrum(一種敏捷管理框架),非常敏捷。
- 每個(gè)開發(fā)人員都有一臺(tái)預(yù)配置的開發(fā)機(jī)器,并按照控制更新。
- 開發(fā)機(jī)會(huì)出現(xiàn)變化,測(cè)試,分期,乃至用于生產(chǎn)。
- 開發(fā)者使用 VIM 和 TextMate。
- 測(cè)試是對(duì) PHP 程序進(jìn)行代碼審核。
- 在服務(wù)方面,他們已經(jīng)實(shí)現(xiàn)了一個(gè)與提交相掛鉤的測(cè)試基礎(chǔ)架構(gòu),接下來(lái)將繼承并內(nèi)建通知機(jī)制。
招聘流程
- 面試通常避免數(shù)學(xué)、猜謎、腦筋急轉(zhuǎn)彎等問(wèn)題,而著重關(guān)注應(yīng)聘者在工作中實(shí)際要做什么。
- 著重編程技能。
- 面試不是比較,只是要找對(duì)的人。
- 挑戰(zhàn)在于找到具有可用性、擴(kuò)展性經(jīng)驗(yàn)的人才,以應(yīng)對(duì) Tumblr 面臨的網(wǎng)絡(luò)擁塞。
- 例如,對(duì)于一個(gè)新的ID生成器器,他們需要一個(gè)高可用的JVM進(jìn)程,并且需要在1萬(wàn)次每分鐘的請(qǐng)求下及最多使用500兆內(nèi)存的情況下完成1毫秒以下的響應(yīng)。他們發(fā)現(xiàn)串行收集器給這個(gè)特定的工作負(fù)載帶來(lái)最低的延遲。在 JVM優(yōu)化上花了大量的時(shí)間。
- 在 Tumblr 工程博客(Tumblr Engineering Blog),他們對(duì)已過(guò)世的 Dennis Ritchie 和 John McCarthy 予以紀(jì)念。
經(jīng)驗(yàn)及教訓(xùn)
- 自動(dòng)化無(wú)處不在
- MySQL(增加分片)規(guī)模,應(yīng)用程序暫時(shí)還不行
- Redis 總能帶給人驚喜
- 基于 Scala 語(yǔ)言的應(yīng)用執(zhí)行效率是出色的
- 廢棄項(xiàng)目——當(dāng)你不確定將如何工作時(shí)
- 不顧用在他們發(fā)展經(jīng)歷中沒(méi)經(jīng)歷過(guò)技術(shù)挑戰(zhàn)的人,聘用有技術(shù)實(shí)力的人是因?yàn)樗麄兡苓m合你的團(tuán)隊(duì)以及工作。
- 選擇正確的軟件集合將會(huì)幫助你找到你需要的人
- 建立團(tuán)隊(duì)的技能
- 閱讀文檔和博客文章。
- 多與同行交流,可以接觸一些領(lǐng)域中經(jīng)驗(yàn)豐富的人,例如與在 Facebook、Twitter、LinkedIn 的工程師多交流,從他們身上可以學(xué)到很多
- 對(duì)技術(shù)要循序漸進(jìn),在正式投入使用之前他們煞費(fèi)苦心的學(xué)習(xí) HBase 和 Redis。同時(shí)在試點(diǎn)項(xiàng)目中使用或?qū)⑵淇刂圃谟邢迵p害范圍之內(nèi)。
英文原文:The Tumblr Architecture Yahoo Bought For A Cool Billion Dollars
譯文鏈接:http://www.oschina.net/translate/the-tumblr-architecture-yahoo-bought-for-a-cool-billion-doll




























