Reddit: 從擴展到每月10億頁面瀏覽量的過程中的各種失誤中學到的經驗教訓

jopen 9年前發布 | 36K 次閱讀 Reddit

Jeremy Edberg,reddit正式聘用的第一位員工,在RAMP大會上做了一個極其精彩的演講,傳授了許多如何創建一個成功社交網站的經驗。各位可點擊Scaling Reddit from 1 Million to 1 Billion–Pitfalls and Lessons(將reddit訪問量從一百萬提升到十個億-陷阱與教訓)的鏈接來觀看演講視頻。

jeremy借用了褒貶參雜的方式來總結經驗教訓,他分享了在推廣Reddit過程中所犯的比比錯誤,但也讓我們看到他們做出的正確抉擇。不過有點令人吃驚的是,jeremy現在是Netflix[3]的可靠性架構師。所以從他的演講中也可感受Netflix的一些觀點。

令我印象深刻的幾個教訓是:

  • SSD看做是便宜的內存(RAM),而不是昂貴的硬盤。當reddit因為數據庫的緣故從機械型硬盤升級到固態硬盤(SSD)后,其服務器數量從12臺降為1臺,且還有極大的空間富余。SSD雖比機械式硬盤貴了四倍,但是你會得到16倍的性能提升,真是物有所值。

  • 給用戶一點點權力,看看他們怎么做,然后把其中的好點子變為網站的功能。reddit從用戶那里所學極為豐富,且其網站的流暢運作很大程度上倚賴其用戶,這是我獲得的最大收獲。用戶會告訴你很多你不知道的事情,reddit gold就是個很好的例子,剛開始它只是社區里大家開的玩笑,reddit將其兌現為產品,并深得用戶喜愛。

  • 項目開始時就建設一個可擴展性架構是不必要的。開始時你并不會知道網站將來的功能集,所以你也不會知道你有哪些擴展方面的問題。等到你的網站開始壯大時,你自然就可以了解網站會在哪些方面有擴展問題。

  • 把未登錄用戶當作二等公民。通過總是給未登錄用戶返回緩存內容的做法,reddit將包袱扔給了Akamai而自身的流量暢通,這種做法使其網站性能大大提升。

Jeremy的分享遠不止于此。從reddit擴展初期的錯誤中我們能學到的經驗教訓良多,這里是我對Jeremy演講的一些釋讀:

統計數據

  • 訪問流量大約每15個月翻一番。

  • 上個月,來自177個不同國家的 67,328,706名獨立訪客瀏覽了reddit網站上 4,692,494,641個頁面。這個演講是在reddit的第10億頁面瀏覽節點完成時進行的,其目前架構與之前架構的差異無法確認。

  • 28名雇員。

  • 每名雇員應對大約240萬獨立訪客。(鏈接

  • 數以千計的志愿者版主。

  • 在2012年時,他們用240臺服務器來支撐每月20億的頁面瀏覽量和Postgres里的2TB數據。所有高訪問率數據都從EBS轉移到本地臨時磁盤(以保證網站運行流暢)。

公司源起

  • Reddit始于2005年。創始人首先帶著“通過短信點餐”的點子去尋求Y Combinator的資金支持但被拒絕,他們回頭和Paul Graham(Y Combinator的創始人,美國著名程序員、風險投資家、博客和技術作家)討論并產生了開發互聯網網頁建設的點子,即reddit。那時他們并不知道掘客(Digg)的存在。

  • 從數據中心開始,隨后逐漸將功能轉移至亞馬遜彈性計算云(EC2)。

             2006年,開始通過EC2使用S3提供存儲和服務標志。

             2007年,開始使用S3支持縮略圖服務。

             2008年,以V*N通道連接數據中心的方式在EC2上進行批處理。

             2009年,整站使用EC2服務。網站停運整整一天,將數據全部遷移到EC2。這是《數據引力》的重大案例,隨后還會談到。

EC2

  • 遷移到EC2的原因

  1. 不斷堆疊機柜并不有趣。不想租用更多的機柜,買更多的服務器。

  2. 建立數據中心,早期數據的增長是無法預測的。

  3. 對于一個4人小組而言,成本相對降低了。亞馬遜的EC2比他們在San Francisco的數據中心價格便宜了29%。

  • EC2不是萬能的。如果你受夠了高網絡延遲和鄰居發出的噪音,考慮下遷移到EC2上。一個好處是網站可以自由的壯大。

  • 熟悉EC2上的資源限制

  1. 所有的資源對每個帳號都有限制。

  2. 亞馬遜也不清楚其中的一些限制是什么。

  3. 跟蹤限制,在你需要的時候擴大限制范圍。

  4. 捕獲異常以發現何時臨界條件被觸發。

架構

  • Reddit的架構是很直觀的。**用戶連接到一個可以與應用紐帶直接通話的網絡紐帶。這個應用紐帶又與 memcache, Cassandra, 還有 Postgres通話,Postgres使用的是一個主從關系網絡。這是一個使用Cassandra 和 Postgres的批處理系統。

  • 相比較而言,Netfli使用的是一個服務型的架構,各部分通過REST API相互之間通話。

    • 優點:方便自適應規模,因為只有服務器需要調整規模;更容易規劃容量;錯誤更容易找出,因為他們在REST框架里是獨立的;變化效果十分精確;本地緩存更加高效。

    • 缺點:需要多個Dev或者Dev團隊在多個服務器上工作,所以人工成本增加;需要一個公共開發平臺避免重復工作;對于一個小團隊來說,管理成本很大。

  • Postgres是一個非常優秀的數據庫**他可以創造出十分優秀,快速鍵值儲存的數據庫。

  • 郵件系統是一個大問題** 信息傳送很難弄好,開始的時候可以用他們自帶的郵件系統,但是現在可能要用專門郵件系統提供商的服務了。

  • 隊列是救世主** 在組件至今傳遞任務的時候,放入一個隊列里。你將會得到一個短小精悍的緩沖器。(Reddit用的是[RabbitMQ](http://www.rabbitmq.com/))

  • 混用HAProxy和Nginx** 有些阻塞是相互的。對于負載均衡嘗試Nginx無效之后可以試試HAProxy(在負載均衡崩潰的時候)。他對于L7負載均衡很有用,Nginx仍然可以用來終止SSL和服務靜態內容。

代碼

  • 框架。 使用Pylons (Django太慢了),它就是一個基于Python的框架。從一開始,它就很容易上手。由于不匹配你的用例,最終它們總會出問題。Pylon最終做出了很多改變,(原來)它升級到新版本是很困難的(現在已經修復這個問題)。(現在)可以使用Pyramid (Pylons的新名字)。

  • 基于線程的事件? 基于線程可以提前依大小排列,但是排列可能是錯誤的。基于事件可以處理更多的連接而不必在遇到瓶頸時繼續陷在瓶頸中。你希望花更多的時間去規劃線程池的尺寸或處理突然遭遇到的瓶頸嗎?

  • 開源有益。 Reddit是在開源代碼上構建的。 不需要付費的軟件不錯,尤其是在開始的時候。

數據

  • 數據將是你的公司最重要的資產非死book, Google和Flickr這樣的公司的根本就是數據。

  • 沉重的數據。當你把數據放在一個地方,你就需要在這個地方放置你的應用。所有的應用都是圍繞數據進行的。數據形成了一個引力中心,其他東西都要向它靠近,因為數據最難移動,而且數據量越大越難移動。目前,把數據移出EC2非常的貴。這就是 EC2 存儲數據免費,遷移數據收費的原因。他們想要你把所有的數據都存放在云服務器上。

  • 關系型 VS 非關系型。reddit 的大部分數據都是鍵值對,存儲在Postgres數據庫中。所有涉及到金錢的數據存儲在關系型的數據庫中,因為可以使用事務和簡便地分析。

  • Postgres 是防彈的。它像巖石一樣堅硬,它自己從未出過問題。即使有問題,也是其他它周邊系統的問題,比如使用Python編寫的復制系統。很難找到熟悉Postgres的專家(因為它不需要專家解決奇怪的問題)。

    • 鍵值存儲選擇了Postgres而不是Cassandra是因為Cassandra當時并不存在,而且Postgres速度非常快,還已經原生支持鍵值。

  • 分庫分表。寫操作被拆分到四個主數據庫中:連接、帳戶、子自動、評論、投票、其它。

    • 每一個主數據庫都有從數據庫。投票數據庫只有一個主庫和一個從庫。評論數據庫有一個主庫和十二個從庫。

    • 如果可以,盡量避免直接從主庫讀取數據,從從庫讀取數據以使主庫專用于寫入數據。

    • 客戶端代碼負責從庫間負載均衡。如果一個從庫響應較慢,訪問另一個從庫。

    • 實現了一個數據訪問層,名稱為thing。

    • 這種方法已經使用了很長時間。混合使用數據庫分庫分表,主從讀寫分離,跟蹤數據讀取性能保持負載均衡。

  • Cassandra

    • 快速寫入,快速負查詢,簡單高可擴展性,無單點故障問題

    • 在 Netflix(美國一家視頻網站),數據分散地存儲在三個不同的區域。每一個區域都有全部區域的數據。即使一個區域的數據丟失了,網站仍然可以正常運行。

    • 把投票數據轉換后存入Cassandra 是 reddit 一次巨大的進步。Cassandra 的 bloom 過濾器顯著地提高了負查詢的效率。比如它可以很快查詢出你沒有投票過的意見,因此負查詢的結果顯示很快。(詳見這里

社會

  • 在2008年,reddit開源了

    • 用戶可以閱讀代碼,從而知道沒有人破壞投票結果

    • 用戶可以增加他們早就想增加的功能,reddit會提供運行平臺。開起來,用戶并不是不想寫代碼。

    • 招聘。別人會了解代碼,所以更容易招聘。推銷自己的想法來更好地合作

  • 蠕蟲事故。 有人指出了如何在一個網頁中注入多余的javascript代碼來寫一個蠕蟲的方法。這個方法并沒有打算被泄露出去,但是最終還是泄露了。在那一天,創始人之一正在結婚,整個團隊都在從婚禮返回的飛機上。但是,一個用戶已經快速響應,提交了一個阻止蠕蟲傳播的補丁。開源可以使得在危機時刻社區可以提供幫助。

reddit怎么賺錢?

  • 側邊條廣告,自助廣告,推銷,reddit幣,市場。

  • 注意,reddit還沒有實現盈利 (鏈接)。這帶來一個問題,像reddit這樣的云端站點能否實現盈利?

  • 另外,reddit現在不再屬于Condé Nast,它是獨立的 (link)。

錯誤

  • 沒有考慮遷移到EC2之后增加的延遲。 在數據中心,機器之間的訪問時間都是亞毫秒級,所以加載一頁可以調用1000次memcache。但是在EC2,情況發生了變化, Memcache的訪問時間增加了十倍,導致原來的方法行不通了。解決方案是批量調用memcache,這樣一次請求可以得到大量的結果。

  • 過于相信承諾。 Amazon并不總是按照承諾交付,所以有時要圓滑一些處理。設計的時候就要考慮錯誤,而不是試圖修復錯誤。(這里沒有參考文獻,也許EBS是個例子?)

  • 在生產環境中使用最新的產品。當Cassandra還處于開發周期的早期的時候,我們就開始使用它了。它現在很棒,但是當時有很多問題。

  • 早就應該把更多的工作量遷移到client端。 服務器端做了很多頁面渲染的工作,但是這些工作應該被推到客戶端。非死book是這方面的大師。你會得到一個矩形,和很多空的div,然后通過API 調用來填滿這些div。這就是他們早就希望reddit可以做的事情。這可以讓我們的規模更快地增長。而且這也對調試有好處,因為我們很容易知道哪個 API出了問題。

  • 沒有足夠的監控,而且用了一個可視化效果不太好的監控系統。 最開始我們使用Ganglia,它可以展示非常漂亮的圖表,但是它比較難用,而且變化太快,尤其是在一個實例進進出出的虛擬機環境中。

  • 沒有讓數據過期。 在reddit你能看到從最初開始的評論。后來他們開始增加一些限制,使得你不能對舊的評論投票,也不能回復舊的帖子。這會造成數據量越來越大,越來越難把熱數據放在數據庫里面。

  • 沒有使用一致性哈希算法。Not using consistent hashing. 當往cache中hash數據的時候,可能會出現這樣的問題,當你增加更多的cache的時候,你的數據還會被hash到原來的cache中,不管你有多少chache。這樣增加cache的時候,你無法保證負載均衡。一致性hash是解決問題的辦法。我們遷移到Cassandra來解決這個問題。

教訓總結

  • 最關鍵的是在用戶遇到問題之前就找到系統的瓶頸。

  • 使用代理服務器不再是拓展的良方。過去可以根據用戶訪問的URL來分流。Reddit曾經也有過一個系統用于監控每個URL上系統服務的時間。用戶請求會根據訪問的URL的不同,進入到不同的響應通道。但是整個系統的響應速度總是此起彼伏。根據平均響應時間來分流以達到系統的巨大提升,已經完成成為過去時了。

  • 讓一切自動化。 如果你能對你的基礎架構像對待你的代碼周全,可以擴展的。那么所有事情都應該是其他的所有工作也應該是可以自動化配置的。

  • 項目開始時就建設一個可擴展性架構是不必要的. 在項目開始的時候你不知道它會有什么特性,那么你只是想知道拓展會有什么問題。但是等到你的站點擴大后,你就能看到拓展的具體問題在什么地方。

  • 不要一開始就使用面向服務的架構。記住,面向服務對一個中大型網站來說是很好的。但如果是起步期的站點就有點太超前了。

  • 不要追求潮流。 只有一小部分的流行技術是可行的,比如,node.js這樣的。

  • 對所有的功能設限。 對所有會不斷重復發生的事件設限制,必要的時候放寬或降低限制標準。如果添加限制,會排斥出一部分用戶,但是保護了系統。舉個子版塊上傳文件的例子。有用戶指出他們上傳的文件數多到可以損壞系統。也不要允許上傳巨型文本。 其他人會教你怎么讓你接受5GB的文本文件。

  • 多手準備. 當在設計階段的時候就假定以后系統要不斷擴展的時候,那么開始的時候就不要只準備一臺應用服務器,一臺數據庫和一個緩存了。那么以后做橫向拓展的時候會容易的多。

  • 用C語言重新Python代碼。 隨著reddit的不斷拓展,大多數重復的功能都用C語言重寫了原來的Python代碼,且獲得了很大的速度提升。特別是過濾器、markdown標簽的渲染及memcache的調用。用C重寫Python代碼的優勢是簡單高效。

  • 保證數據庫設計盡可能的無模式。 這樣會使得在添加新特性的時候變得簡單。你所做的只是添加一些新的屬性而不用修改表結構。

  • 過期數據。 停用那些老舊的線程,創建好一個完整的頁面并添加到緩存中。這就是處理那些可能導致你數據庫奔潰的老舊數據的方式。同樣的,不要允許對很久以前的評論點贊或者加平路,用戶幾乎不會注意到的。

  • SSD看做是便宜的內存,而不是昂貴的硬盤 當reddit把數據庫的存儲設備從機械型硬盤升級到固態硬盤(SSD)后,服務器數量從12臺降為1臺,且響應還更快。SSD雖比機械式硬盤貴了四倍,但是你會得到16倍的性能提升,真是物有所值。Netflix板塊中的一些最大Cassandra節點都是采用的SSD存儲,性能得到了巨大的提升。

  • 每個工具都有不同的適用場景。 Memcache中的數據是不做持久化的,但是非常快,那么投票數據存在它里面可以是頁面的渲染以最快速度完成。Cassandra是持久化的,而且快,布隆過濾器的使用也是它可以找出沒有命中的查詢,所以使得它很適合存儲沒有在memcache中存儲的投票數據的副本。Postgres是非常可靠的關系型數據庫,可以用來存放Cassandra中投票數據的備份(Cassandra中的所有數據在必要的情況下可以從Postgre中獲取),在做批量操作的時候,有時也需要依賴關系數據庫的功能。

  • 把未登錄用戶當作二等公民。 過去80%的請求來自未登入的用戶,現在是接近50%。通過總是給未登錄用戶返回緩存內容的做法,reddit將包袱扔給了Akamai而自身的流量暢通,這種做法使其網站性能大大提升。附帶的好處是,如果reddit當機了,你沒登入的話你也許就察覺不到。

  • 使用隊列。 投票、評論、縮略圖、預查詢、垃圾評論處理及糾錯等等都放在隊列中處理。通過監控隊列的長度就能讓你發現問題。附帶好處是,使用隊列后有些問題對用戶會變得透明,像投票請求,即使系統沒有即時響應,用戶也不會察覺。

  • 將數據放在多個可訪問的域中。

  • 避免在一個實例中保存狀態。

  • 頻繁對EBS硬盤做數據快照。

  • 不要在實例中保存秘鑰。亞馬遜現在提供實例秘鑰服務(instance keys).

  • 按安全策略組分拆功能。

  • 提供API。開發人員可以在你的平臺上開發應用。像reddit手機應用,就是由公司外的開發人員通過調用API開發的。

  • 在你自己的社區做一個積極分子。

  • 讓用戶為你工作。 網上用戶的輸入總是充滿欺騙性、無用的、偽造的,但是對于reddit,處理這些垃圾信息的大部分工作都由志愿者完成了。這就是reddit能保持小團隊卻能把工作完成的出奇的好的原因。

  • 給用戶一點點權力,看看他們怎么做,然后把其中的好點子變為網站的功能。比如,當子版塊可以定制CSS的時候,他們看到用戶在干嗎,以及為其他所有用戶提供的一些功能。這也使用戶在reddit做一些事感到興奮,因為他們喜歡控制的感覺。還有很多這樣的例子。

  • 傾聽用戶的聲音。用戶會告訴你許多你可能想知道但是又不知道的事情。比如,reddit幣最開始就是社區里面的一句玩笑話。現在他們做成了產品,而且用戶很喜歡。

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