Flickr架構

Flickr架構

Flickr(http://www.flickr.com/)是國外一個領先的圖片分享網站,現在應該在yahoo門下,感覺yahoo還是有很多好東西,奈何資本要拋棄他了。這個輪迴其實挺有意思的,起先是做實業被microsoft鬱悶了,說軟件是虛的值不能那麼多錢,然後microsoft被yahoo鬱悶了,說互聯網是虛的不值那麼多錢,然後是yahoo被google鬱悶了,yahoo比較厚道沒說什麼,現在microsoft要收購yahoo了(折騰好久了,估計要落聽了吧),不知道google將來要被誰鬱悶了。成功建立在相同的失敗上,反過來失敗都是建立在相同的成功上也成立,進入正題吧。
原文地址是http://highscalability.com/flickr-architecture,本文不是原文的嚴謹翻譯,帶有我的理解以及補充,由於水平有限,文中的錯誤請各位斧正。
Flickr處理的數據:
  • 多達40億次的請求(http request or database query?不知道了,不管是哪個,都夠大的吧。)
  • squid總計約有3500萬張圖片(硬盤+內存)
  • squid內存中約有200萬張圖片
  • 總計有大約4億7000萬張圖片,每張圖片大概4~5MB
  • 每秒3,8000次請求 (存儲了1200萬對象在裏面)
  • 2 PB 存儲(星期天要消費~1.5TB)
  • 每天新增圖片超過 400,000
嚇死人不償命….
Flickr用到的技術:
  • PHP
  • MySQL
  • Shards
  • Memcached 作爲中間緩存層,memcached在web2.0網站中可能是引用最廣泛的產品之一,開源&強大.
  • Squid 作反向代理服務器(reverse-proxy for html and images).
  • Linux (RedHat),如果你想用RedHat企業版又不想付費,試試這個CentOS,基本上100%克隆RedHat企業版(估計傳說中1%的RedHat代碼沒有),我用的就是這個。
  • Smarty 作爲模板解析,很多人在討論smarty這不好那不好,但是大網站都在用,穩定而且功能強大,系統的瓶頸從來不會再smarty這裏,我保證。
  • Perl 估計用perl做一些系統層面的東西吧,比如日誌處理(猜測)
  • PEAR 做XML和Email解析,和我們一樣,Flickr用的也是PHP4,不過新項目還是用PHP5吧
  • ImageMagick 圖像處理的不二選擇
  • Java, for the node service,Java就不太瞭解了,希望讀者補充
  • Apache 大家都在用,嚐鮮的用戶nginx或者lighttpd(適合靜態文件,youtube用它做媒體文件服務器),出了問題你會抓狂的。
  • SystemImager 作爲服務器部署
  • Ganglia 分佈式系統監控,或者你可以試試nagios,據我所知也很多公司在用
  • Subcon 用SVN維護服務器配置文件並且可以部署不同的配置文件到服務器集羣中去(這個我沒用過,系統運維的可能會喜歡)
  • Cvsup 文件分發,是否類似rsync?
  • Wackamole前端負載均衡,類似的產品有http://haproxy.1wt.eu/
Flickr架構
常見的Squid反向代理、PHP App Servers、Net App’s、Storage Manager我在這裏就不講,我們關注一些讓人興奮的特徵:
  • Mysql的Master-Master結構,mysql的常見的master-slave結構,大家都知道存在”single point of failure”(單點故障的問題),且只對讀操作有好處,對於寫頻繁的網站卻不是一個好的解決方案,Flickr的雙master方案據我推測用的就是這個http://code.google.com/p/mysql-master-master/,原理就是master輪詢,保證同時只有一個master負責寫,解決了單點故障的問題。
  •  Dual Tree Structure,看看下面的圖就知道什麼是“雙樹結構”(姑且這麼翻譯)


示例圖中上方的2臺機器爲master,下方的4臺爲slave,這種“雙樹結構”的設計保證一個slave只有一臺master,易於擴展也不會形成環路。原文中說這種設計是1+1=200%的設計,簡單高效。爲了防止自增長衝突,數據表中無自增長列。
補充:對於大型應用的分表設計,防止自增長衝突是個問題,有個簡單的方案:比如分3張表,可以設第一張表從1開始以3跳躍遞增,那麼第一張表存儲的序列爲1,4,7,10……,第二張表從2開始也以3跳躍遞增,第二張表存儲的序列爲2,5,8,11……,第三張表從3開始以3跳躍遞增,第三張表存儲的序列爲3,6,9,12……,保證不會有重複的序號,但這種方案的缺點是如果數據爆炸,3張表不夠,你分4張表呢?需要手工遷移數據,如果程序寫的不好,底層又要大動了。
Flickr採用的方案是一箇中心’users’ table(用戶表),記錄的信息是用戶主鍵以及此用戶對以的數據庫片區(有點類似Key->Value的設計,這樣的數據結構查詢起來是非常迅速的,據說Google的用戶登錄數據用的就是這樣的設計,通過改進版的BDB數據庫存儲用戶名和密碼,這樣登錄起來就不用去查那個大表了),從中心用戶表中查出用戶數據所在位置,然後直接從目標位置中取出數據。 
用專門的服務器存儲靜態內容,這個容易做到,比如專門的圖片服務器。 “Use a share nothing architecture”這個比較費解了,字面上的意思是使用一個無共享的架構,其實就是解除架構上的依賴,類似我們寫程序解耦合一樣。 除圖片外,所有的數據都存在數據庫中,這裏他們提到了PHP session,我們知道php的session是存儲在服務器文件系統的,而且默認沒有做hash目錄,這就意味着如果你的網站訪問量大,比如有10萬個人在線,你的session目錄下就有10萬個文件,如果你的文件格式是NTFS(windows)或者Ext3(Linux),你要定位到某個文件,系統基本上會假死,有個好的建議是不要在一個文件夾下放超過1000個文件。使用默認的php session還有另外一個問題:服務器session同步,用戶在A服務器登錄後,session存儲在A服務器上,然後應用跳轉到B服務器,B服務器上的session沒有同步就出問題了,當然解決這個問題的方法很多,比如統一存儲session,所有服務器的session都存儲在一個vfs設備上,或者通過cookie重新生成一個session在B服務器上 Flickr的架構不能說是完美的,沒有完美的架構,ebay對於擴展有以下建議:
  • 不要預先去爲性能擴展,出現問題之後找到問題再尋擴展;
  • 不要想尋找到一個一勞永逸的方案,因爲你不知道下一個瓶頸在哪裏;
  • 訪問量大了,出了問題,修改架構,穩定運行,訪問量再大了,又出問題了,再修改,這個是解決問題的唯一方案。
Flickr是Lamp架構比較成功的案例之一,拋出Flickr的架構是因爲看到國內很多的架構設計盲目、迷信以及短視,不過相對於架構來說,程序的結構更讓人擔憂,後面的我會寫一些關於程序結構的文章,希望能和大家一起討論成長,好了,我們繼續Flickr的架構。
  • “Statelessness”設計,原文用的是這個詞,字面上的意思是“無國家的”,看了一些相關文檔,我覺得Statelessness的含義是“無界限的”設計,一個簡單的例子,現在很多架構設計用到分表,比如用戶信息表,怎麼分呢?直接hash分表,兩張表就按奇偶分,n張表就按n的模進行分,這種設計就是Statelessness的反向,你把你的用戶綁定在一張固定的表或者固定的機器上了,如果你的用戶裏面有付費用戶,你希望把他們的數據單獨存儲或者用專門的機器處理,你怎麼辦?你設計的太死了,你的付費用戶只能和免費用戶綁定在一起,提供一樣的服務器支持,當然,你可以騙用戶說他們的服務是有差別的。
  • 通過master-save的設計能解決一部分問題,但很快你就會發現不行了,常見的master-slave只能解決讀的問題,但存在單點失敗故障,而且當負載比較重的時候會存在複製延遲的問題,很多公司都會碰到。
  • 搜索功能由專門的服務器羣來支持,通過複製需要搜索的內容到搜索服務器去搜索,和App servers分開。


   集羣
1、分表:按照一定主鍵拆分數據表,比如按照用戶劃分;
2、一個用戶的所有信息在同一組服務器上
3、數據能夠在不同的服務器組上遷移(Statelessness)
4、一組中心服務器負責查詢,比如定位某個用戶在哪個服務器組



5、不要以用戶ID作爲分組的依據(Non-Statelessness)

服務器組中每臺服務保持50%的負載,當某臺服務器down機或者維護時,另外一臺服務器100%負載 訪問高峯時,每臺服務器的負載可能高於50%,現在Flickr通過增加服務器來讓服務器負載在50%以下 每個頁面大概有27~35個mysql query(夠高的),點擊數統計、API調用數據庫都是實時的(太恐怖了,估計只有Dathan Pattishall會這麼變態的使用mysql) 每組服務器處理40萬+的用戶數據,很多數據存儲了雙份,比如A用戶對B用戶的博客進行了評論,那麼評論的數據在A的數據表裏面和B的數據表裏面都存儲了一份,Flickr通過事務來保證同步。(這樣做的目的是保證同一個用戶的數據都存放在同一組服務器上,省去複製的成本。) Flickr的硬件設置:Intel EMT64處理器/紅帽RHEL4/16GB內存/6塊15000轉的硬盤做RAID-10/12TB用戶數據(僅僅是數據庫而不是圖片)/2U服務器,每個服務大概有120GB數據 備份:每天不同時刻跑cron,每天晚上做數據庫快照,專門的服務組來備份(和線上業務分開),交叉備份(比如每天、每週、每月) 每張圖片都有自己的檔案,檔案包括大小、尺寸、像素等等,儲存在數據中 每組服務器最多400個連接,45個線程緩存 Tag標籤,Flickr發現常見的數據庫結構不能很好的處理巨大的標籤庫,他們採用的是類似倒排索引以及大量的緩存來處理,並且Tag標籤不是實時的,他們會在線下進行統計 Flickr目標是所有的事務都做成實時的,沒有延遲(個人覺得倒是沒有這個必要)
Todd Hoff總結的經驗:
  • 不要把你的應用簡單的看成一個Web應用,可能會有REST APIs, SOAP APIs, RSS feeds, Atom feeds等等的應用
  • “無界限”設計,不要把你的用戶死死的綁定在某個服務器上
  •  產品設計時需要做擴容的計劃以及預算
  • 慢慢來,不要一開始就買一堆服務器
  • 實地考察,不要臆想,獲得實際數據之後再做決定
  • 內建日誌系統,記錄服務器和應用日誌
  • Cache,緩存是必不可少的
  • 抽象層,由於你的架構隨時可能變,架構的變化必定要帶來底層的變化,這就需要你在底層的基礎上根據業務封裝一層中間層,這樣底層的改動不至於影響業務(這個太重要了,不要因爲擴展把原來的程序推倒重來)
  • 迭代開發,隨時改進
  • 忘記那些調優的小技巧吧,比如很多人對與PHP裏面的require和require_once的性能差別,這些性能的差異和架構上的短板比起來根本不足爲道
  • 在線上測試你的效果
  • 忘記用工具測試出來的結果,這些結果只能給你一個大概的印象而已
  • 找出你的系統短板,一臺服務器的最大處理能力是多少?現在離最大負載還有多遠?mysql的瓶頸在哪裏?是不是磁盤IO?memcache的瓶頸在哪裏?CPU還是網絡傳輸?
  • 注意你的用戶使用規律,比如Flickr發現每年的第一個工作日比平時多20%~40%的上傳量,週日的訪問量比平時要多40%~50%
  • 要注意指數型的增長
  • 你的計劃是爲你訪問的峯值設計的
補充:閱讀完原文的評論,有一個評論翻譯出來給大家分享:
Flickr如何存儲圖片的呢?
標準的Flickr圖片Url是這樣的http://farm1.static.flickr.com/104/301293250_dc284905d0_m.jpg,其中farm1是Flickr的服務器羣,static.flickr.com是Flickr靜態圖片服務器,104是服務器ID,301293250是圖片ID,dc284905d0是Flickr的加密串,防止盜鏈,m表示圖片的尺寸。m表示中等尺寸
後記:
終於“翻譯”(姑且用這個詞)完了,看到原文的一個評論是”Hmm… i can not beleive flickr written on php…”,借用好像也是Flickr的人說的一句話:擴展的不是語言,而是架構。國內很多大的企業都在用PHP(比如我所在的sina),PHP總給人是草根語言的感覺,是因爲沒有人肯分享自己的架構,以及程序員寫程序的時候不注意自己的結構(設計模式),好的架構只能讓你的程序跑的更快,好的結構讓你的程序更易於維護,更容易讓別人看的懂,更容易團隊合作。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章