為什麼雅虎會收購tumblr? 這場交易中的商業價值我可能無法判斷,但是如果你對tumblr的技術方面有所了解,你一定會為tumblr豎起大拇指. 為什麼這麼說呢,請接着讀...
tumblr每月頁面浏覽量超過150億次,已經成為火爆的部落格社群。使用者也許喜歡它的簡約、漂亮,并且它對使用者體驗強烈的關注,或是友好而忙碌的溝通方式,總之,它深得人們的喜愛。
每月超過30%的增長當然不可能沒有挑戰,其中可靠性問題尤為艱巨。每天5億次浏覽量,峰值每秒4萬次請求,每天3tb新的資料存儲,并運作于超過1000台伺服器上,所有這些幫助tumblr實作巨大的經營規模。
創業公司邁向成功,都要邁過危險的迅速發展期這道門檻。尋找人才,不斷改造基礎架構,維護舊的架構,同時要面對逐月大增的流量,而且曾經隻有4位工程師。 這意味着必須艱難地選擇應該做什麼,不該做什麼。這就是tumblr的狀況。好在現在已經有20位工程師了,可以有精力解決問題,并開發一些有意思的解決 方案。
tumblr目前的最大問題是如何改造為一個大規模網站。系統架構正在從lamp演進為最先進的技術組合,同時團隊也要從小的創業型發展為全副武裝、随時待命的正規開發團隊,不斷創造出新的功能和基礎設施。下面就是blake對tumblr系統架構情況的介紹。
<a target="_blank"></a>
每天 5 億頁面浏覽量
每月超過 150億 頁面浏覽量
約 20 名工程師
峰值每秒大約 4 萬請求
每天有超過 1tb 的資料進入 hadoop 叢集
每天有幾個 tb 的資料進入 mysql/hbase/redis/memcache
每月增長 30%
産品環境有大約 1000 個硬體節點
平均每個工程師每月處理10億頁面通路
每天大約 50gb 的文章,關注者清單更新大約每天 2.7tb
dashboard 每秒百萬次寫,每秒 5w 讀
os x 用于開發,産品環境用 linux (centos, scientific)
apache
php, scala, ruby
redis, hbase, mysql
varnish, ha-proxy, nginx,
memcache, gearman, kafka,kestrel, finagle
thrift, http
git, capistrano, puppet, jenkins
500 台 web 伺服器
200 資料庫伺服器 (大多數是備用池)
47 個池
30 個分區
30 台 memcache 伺服器
22 台 redis 伺服器
15 台 varnish 伺服器
25 個 haproxy 節點
8 個 nginx
14 個作業隊列伺服器 (kestrel + gearman)
與其他社交網站不同的是,tumblr有其獨特的使用模式。
每天有超過5千萬篇文章更新,平均每篇文章的跟帖又數以百計。使用者一般隻有數百個粉絲。這與其他社會化網站裡少數使用者有幾百萬粉絲非常不同,使得tumblr的擴充性極具挑戰性。
按使用者使用時間衡量,tumblr已經是排名第二的社會化網站。内容的吸引力很強,有很多圖檔和視訊,文章往往不短,一般也不會太長,但允許寫得很長。文章内容往往比較深入,使用者會花費更長的時間來閱讀。
使用者與其他使用者建立聯系後,可能會在dashboard上往回翻幾百頁逐篇閱讀,這與其他網站基本上隻是部分資訊流不同。
使用者的數量龐大,使用者的平均到達範圍更廣,使用者較頻繁的發帖,這些都意味着有巨量的更新需要處理。
tumblr目前運作在一個托管資料中心中,已在考慮地域上的分布式構架。
tumblr平台由兩個元件構成:公共tumblelogs和dashboard
公共tumblelogs與部落格類似,并非動态,易于緩存
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
dashboard采用了“擴散-收集”方式。當使用者通路dashboard時将顯示事件,來自所關注的使用者的事件是通過拉然後顯示的。這樣支撐了6個月。由于資料是按時間排序的,是以sharding模式不太管用。
<a></a>
由于招人和開發速度等原因,改為以jvm為中心。
目标是将一切從php應用改為服務,使應用變成請求鑒别、呈現等諸多服務之上的薄層。
選擇了scala 和 finagle
在團隊内部有很多人具備ruby和php經驗,是以scala很有吸引力。
finagle是選擇scala的重要因素之一。這個來自twitter的庫可以解決大多數分布式問題,比如分布式跟蹤、服務發現、服務注冊等。
轉到jvm上之後,finagle提供了團隊所需的所有基本功能(thrift, zookeeper等),無需再開發許多網絡代碼,另外,團隊成員認識該項目的一些開發者。
foursquare和twitter都在用finagle,meetup也在用scala。
應用接口與thrift類似,性能極佳。
團隊本來很喜歡netty,但不想用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裡打标簽,釋出到代碼庫等等。大多數程式員都不用再操心建構系統的細節了。
40台伺服器采用haproxy進行負載均衡,varnish進行緩存.
200台資料庫伺服器中,很多是為了提高可用性而設,使用的是正常硬體,但mtbf(平均故障間隔時間)極低。故障時,備用充足。
500台伺服器運作apache和其他php程式。
6個為了支援php應用的後端服務,并有一個小組專門開發後端服務。新服務的釋出需要兩到三周,包括dashboard通知、dashboard二級索引、短位址生成、處理透明分片的memcache代理。
其中在mysql分片上耗時很多。雖然在紐約本地非常熱,但并沒有使用mongodb,他們認為mysql的可擴充性足夠了。
gearman用于會長期運作無需人工幹預的工作。
可用性是以達到範圍(reach)衡量的。使用者能夠通路自定義域或者dashboard嗎?也會用錯誤率。
曆史上總是解決那些最高優先級的問題,而現在會對故障模式系統地分析和解決,目的是從使用者和應用的角度來定成功名額。
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相當。
内部的應用需要活躍的資訊流通道。這些資訊包括使用者建立/删除的資訊,liking/unliking 的提示,等等。挑戰在于這些資料要實時的分布式處理。我們希望能夠檢測内部運作狀況,應用的生态系統能夠可靠的生長,同時還需要建設分布式系統的控制中心。
以前,這些資訊是基于 scribe (facebook 開源的分布式日志系統。)/hadoop 的分布式系統。服務會先記錄在 scribe 中,并持續的長尾形式寫入,然後将資料輸送給應用。這種模式可以立即停止伸縮,尤其在峰值時每秒要建立數以千計的資訊。不要指望人們會細水長流式的釋出文 件和 grep。
linkedin 的 kafka 用于存儲資訊。内部人員通過 http 連結 firehose。經常面對巨大的資料沖擊,采用 mysql 顯然不是一個好主意,分區實施越來越普遍。
firehose 的模型是非常靈活的,而不像 twitter 的 firehose 那樣資料被假定是丢失的。
firehose 的資訊流可以及時的回放。他保留一周内的資料,可以調出這期間任何時間點的資料。
支援多個用戶端連接配接,而且不會看到重複的資料。每個用戶端有一個 id。kafka 支援客戶群,每個群中的客戶都用同一個 id,他們不會讀取重複的資料。可以建立多個用戶端使用同一個 id,而且不會看到重複的資料。這将保證資料的獨立性和并行處理。kafka 使用 zookeeper (apache 推出的開源分布式應用程式協調服務。)定期檢查使用者閱讀了多少。
現在支援 dashboard 的功能的分散-集中架構非常受限,這種狀況不會持續很久。
收件箱與分散-集中架構是對立的。每一位使用者的 dashboard 都是由其追随者的發言和行動組成的,并按照時間順序存儲。
就因為是收件箱就解決了分散-集中的問題。你可以會問到底在收件箱中放了些什麼,讓其如此廉價。這種方式将運作很長時間。
重寫 dashboard 非常困難。資料已經分布,但是使用者局部更新産生的資料交換的品質還沒有完全搞定。
資料量是非常驚人的。平均每條消息轉發給上百個不同的使用者,這比 facebook 面對的困難還要大。大資料+高分布率+多個資料中心。
每秒鐘上百萬次寫入,5萬次讀取。沒有重複和壓縮的資料增長為2.7tb,每秒百萬次寫入操作來自 24 位元組行鍵。
已經流行的應用按此方法運作。
cell構架
每個 cell 是獨立的,并儲存着一定數量使用者的全部資料。在使用者的 dashboard 中顯示的所有資料也在這個 cell 中。
使用者映射到 cell。一個資料中心有很多 cell。
每個 cell 都有一個 hbase 的叢集,服務叢集,redis 的緩存叢集。
使用者歸屬到 cell,所有 cell 的共同為使用者發言提供支援。
一個使用者進入 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。
當追随者改變時,這種設計方案也是安全的。因為所有的發言都儲存在 cell 中了。如果隻有追随者的發言儲存在 cell 中,那麼當追随者改變了,将需要一些回填工作。
另外一種設計方案是采用獨立的發言存儲叢集。這種設計的缺點是,如果群集出現故障,它會影響整個網站。是以,使用 cell 的設計以及後複制到所有 cell 的方式,建立了一個非常強大的架構。
不同的使用者采用不同并且恰當的存取模式和分布模型,兩個不同的分布模式包括:一個适合受歡迎的使用者,一個使用大衆。
依據使用者的類型采用不同的資料處理方式,活躍使用者的發言并不會被真正釋出,發言将被有選擇的展現。
追随了上百萬使用者的使用者,将像擁有上百萬追随者的使用者那樣對待。
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的指令實作部署。它可以可以從git倉庫中拉取代碼。正因為是基于http的,是以非常易于擴充。他們喜歡 capistrano,因為它支援簡單的基于目錄的版本控制,能夠很好地管理php程式。版本更新的時候,每個目錄都包含一個sha,是以很容易檢查版本 的正确性。
func api 可用于傳回狀态報告,報告哪些機器上有這些軟體版本。
安全重新開機任何服務,因為它們會關閉連接配接,然後重新開機。
在激活前的黑暗模式下運作所有功能。
從哲學上,任何人都可以使用自己想要的任意工具。但随着團隊的發展壯大,這些工具出現了問題。新員工想要更好地融入團隊,快速地解決問題,必須以他們為中心,建立操作的标準化。
過程類似于 scrum(一種靈活管理架構),非常靈活。
每個開發人員都有一台預配置的開發機器,并按照控制更新。
開發機會出現變化,測試,分期,乃至用于生産。
開發者使用 vim 和 textmate。
測試是對 php 程式進行代碼稽核。
在服務方面,他們已經實作了一個與送出相挂鈎的測試基礎架構,接下來将繼承并内建通知機制。
面試通常避免數學、猜謎、腦筋急轉彎等問題,而着重關注應聘者在工作中實際要做什麼。
着重程式設計技能。
面試不是比較,隻是要找對的人。
挑戰在于找到具有可用性、擴充性經驗的人才,以應對 tumblr 面臨的網絡擁塞。
例如,對于一個新的id生成器器,他們需要一個高可用的jvm程序,并且需要在1萬次每分鐘的請求下及最多使用500兆記憶體的情況下完成1毫秒以下的響應。他們發現串行收集器給這個特定的工作負載帶來最低的延遲。在 jvm優化上花了大量的時間。
在 tumblr 工程部落格(tumblr engineering blog),他們對已過世的 dennis ritchie 和 john mccarthy 予以紀念。
自動化無處不在
mysql(增加分片)規模,應用程式暫時還不行
redis 總能帶給人驚喜
基于 scala 語言的應用執行效率是出色的
廢棄項目——當你不确定将如何工作時
不顧用在他們發展經曆中沒經曆過技術挑戰的人,聘用有技術實力的人是因為他們能适合你的團隊以及工作。
選擇正确的軟體集合将會幫助你找到你需要的人
建立團隊的技能
閱讀文檔和部落格文章。
多與同行交流,可以接觸一些領域中經驗豐富的人,例如與在 facebook、twitter、linkedin 的工程師多交流,從他們身上可以學到很多
對技術要循序漸進,在正式投入使用之前他們煞費苦心的學習 hbase 和 redis。同時在試點項目中使用或将其控制在有限損害範圍之内。
<b> 原文釋出時間為:2013-05-26</b>
<b></b>
<b>本文來自雲栖社群合作夥伴“linux中國”</b>