Tumblr:150億月瀏覽量背后的架構挑戰(上)

fmms 12年前發布 | 89K 次閱讀 架構 軟件架構

        導讀:和許多新興的網站一樣,著名的輕博客服務 Tumblr 在急速發展中面臨了系統架構的瓶頸。每天 5 億次瀏覽量,峰值每秒 4 萬次請求,每天 3TB 新的數據存儲,超過 1000 臺服務器,這樣的情況下如何保證老系統平穩運行,平穩過渡到新的系統,Tumblr 正面臨巨大的挑戰。近日,HighScalability 網站的 Todd Hoff 采訪了該公司的分布式系統工程師 Blake Matheny,撰文系統介紹了網站的架構,內容很有價值。我們也非常希望國內的公司和團隊多做類似分享,貢獻于社區的同時,更能提升自身的江湖地位,對招聘、業務發展都好處多多。

Tumblr:150億月瀏覽量背后的架構挑戰(上)

Tumblr:150億月瀏覽量背后的架構挑戰(下)

英文原文:High Scalability

        Tumblr 每月頁面瀏覽量超過 150 億次,已經成為火爆的博客社區。用戶也許喜歡它的簡約、美麗,對用戶體驗的強烈關注,或是友好而忙碌的溝通方式,總之,它深得人們的喜愛。

        每月超過 30% 的增長當然不可能沒有挑戰,其中可靠性問題尤為艱巨。每天 5 億次瀏覽量,峰值每秒 4 萬次請求,每天 3TB 新的數據存儲,并運行于超過 1000 臺服務器上,所有這些幫助 Tumblr 實現巨大的經營規模。

Tumblr:150億月瀏覽量背后的架構挑戰(上)

        創業公司邁向成功,都要邁過危險的迅速發展期這道門檻。尋找人才,不斷改造基礎架構,維護舊的架構,同時要面對逐月大增的流量,而且曾經只有 4 位工程師。這意味著必須艱難地選擇應該做什么,不該做什么。這就是 Tumblr 的狀況。好在現在已經有 20 位工程師了,可以有精力解決問題,并開發一些有意思的解決方案。

        Tumblr 最開始是非常典型的 LAMP 應用。目前正在向分布式服務模型演進,該模型基于 ScalaHBaseRedis(著名開源K-V存儲方案)、Kafka(Apache 項目,出自 LinkedIn 的分布式發布-訂閱消息系統)、Finagle(由 推ter 開源的容錯、協議中立的 RPC 系統),此外還有一個有趣的基于 Cell 的架構,用來支持 Dashboard(CSDN 注:Tumblr 富有特色的用戶界面,類似于微博的時間軸)。

        Tumblr 目前的最大問題是如何改造為一個大規模網站。系統架構正在從 LAMP 演進為最先進的技術組合,同時團隊也要從小的創業型發展為全副武裝、隨時待命的正規開發團隊,不斷創造出新的功能和基礎設施。下面就是 Blake Matheny 對 Tumblr 系統架構情況的介紹。

        網站地址

        http://www.tumblr.com/

        主要數據

  • 每天 5 億次 PV(頁面訪問量)
  • 每月超過 150 億 PV
  • 約 20 名工程師
  • 峰值請求每秒近 4 萬次
  • 每天超過 1TB 數據進入 Hadoop 集群
  • MySQL/HBase/Redis/memcache 每天生成若干 TB 數據
  • 每月增長 30%
  • 近 1000 硬件節點用于生產環境
  • 平均每位工程師每月負責數以億計的頁面訪問
  • 每天上傳大約 50GB 的文章,每天跟帖更新數據大約2.7TB(CSDN 注:這兩個數據的比例看上去不太合理,據 Tumblr 數據科學家 Adam Laiacano 在 推ter 上解釋,前一個數據應該指的是文章的文本內容和元數據,不包括存儲在 S3 上的多媒體內容)

        軟件環境

  • 開發使用 OS X,生產環境使用 Linux(CentOS/Scientific)
  • Apache
  • PHP, Scala, Ruby
  • Redis, HBase, MySQL
  • Varnish, HAProxy, nginx
  • memcache, Gearman(支持多語言的任務分發應用框架), Kafka, Kestrel(推ter 開源的分布式消息隊列系統), 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 是類似于 推ter 的時間軸,用戶由此可以看到自己關注的所有用戶的實時更新。與博客的擴展性不同,緩存作用不大,因為每次請求都不同,尤其是活躍的關注者。而且需要實時而 且一致,文章每天僅更新 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 的重要因素之一。這個來自 推ter 的庫可以解決大多數分布式問題,比如分布式跟蹤、服務發現、服務注冊等。
  • 轉到 JVM 上之后,Finagle 提供了團隊所需的所有基本功能(Thrift, ZooKeeper 等),無需再開發許多網絡代碼,另外,團隊成員認識該項目的一些開發者。
  • Foursquare 和 推ter 都在用 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 模型的,但是后來放棄了。對于運行后無需人工干預的工作,使用任務隊列。而且 推ter 的 util 工具庫中有 Future 實現,服務都是用 Future(Scala 中的無參數函數,在與函數關聯的并行操作沒有完成時,會阻塞調用方)實現的。當需要線程池的時候,就將 Future 傳入 Future 池。一切都提交到 Future 池進行異步執行。

        Scala 提倡無共享狀態。由于已經在 推ter 生產環境中經過測試,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 相當。

        (先到這里吧,敬請期待下篇,包括如何用 Kafaka、Scribe、Thrift 實現內部活動流,Dashboard 的 Cell 架構,開發流程和經驗教訓等精彩內容。)

        翻譯:包研,張志平,劉江;審校:劉江
來自: CSDN

 本文由用戶 fmms 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!