Reddit月瀏覽量從百萬擴容到十億的陷阱和教訓
英文原文:Reddit: Lessons Learned from Mistakes Made Scaling to 1 Billion Pageviews a Month
Reddit[1] 是一個社交新聞網站。用戶可以將互聯網上搜集或原創的圖片或材料以帖子形式發布于網站上。而后其他用戶可以投票,投票的結果將作為帖子排名的依據。
Reddit 網站的第一位領薪雇員杰里米·埃德伯格在 RAMP[2] 討論會上做了一次出色的演講 ,他教給我們很多關于如何創建一個成功的社交網站。杰里米使用一種美德和罪惡的方法,分享在擴展 Reddit 時的錯誤例子。事實證明,他們也做了很多好東西。不過有點令人吃驚的是,杰里米現在是 Netflix[3] 的可靠性架構師。所以我們在這篇文章中,也可免費得到一些 Netflix 的觀點。
我完全認可的一些經驗教訓:
- 把 SSD[4] 看做是便宜的內存[5],而不是昂貴的硬盤。當 reddit 把數據庫從旋轉磁盤轉移到 SSD 后,服務器數量從 12 個降低到 1 個,并且還有很多余量。SSD 雖貴了 4 倍,但是你會得到 16 倍的性能,這個花銷值得。
- 給用戶一點權力,看他們用來做什么,然后把好的東西轉換成功能。對我最大的啟示之一是 reddit 從它的用戶學到了很多,網站能順利運作,很大程度上依靠了用戶。用戶會告訴你很多你不知道事情。例如,reddit gold 在社區里以笑話開始,后來他們把它做成產品,并得到用戶的喜愛。
- 沒有必要從一開始就建立一個可擴展的架構。一開始時你不知道什么會是你的功能集,所以你也不知道你會有哪些擴展問題。隨著你的網站增長,你可以了解哪里將是擴展問題。
- 把未登錄用戶當作二等公民。未登錄的用戶訪問的緩存內容,Akamai[6] 抗住了著 reddit 的流量沖擊。巨大的性能提升。
還有很多,這里是我談話的注釋,我們從早期擴展 reddit 的錯誤中學到許多經驗教訓:
數據統計
- 流量大約每 15 個月增加 1 倍。
- 上個月(8 月份),reddit 有來自 177 個不同國家的 73,293,644 名獨立訪客,查看了 4,885,611,148 個頁面。在大約 10 億次瀏覽量時結束了這次談話。不清楚現在的架構有何不同。
- 28 名雇員。
- 每名雇員應對大約 240 萬獨立訪客。(鏈接)
- 成千上萬的志愿者版主
- 截至 2012 年,他們有 240 臺服務器,支持每月 20 億頁面瀏覽量和 Postgres[7] 里的 2TB 數據。所有高流量的數據被移出 EBS[8],并上傳至本地臨時磁盤。
起源故事
- Reddit 始于 2005 年。他們帶著通過文字來點餐的想法去了 Y Combinator[9],結果被拒絕了。回來跟保羅·格雷厄姆商討,想建設互聯網網頁,這就是 reddit。那時他們并不知道 Digg[10]。
- 開始在數據中心,然后把功能部分轉移到 EC2[11]。
- 最初在 2006 年開始使用 S3[12] 存儲和供應標識。
- 2007 年為縮略圖使用 S3。
- 2008 年使用 EC2 經由 V*N[13] 通道到數據中心進行批處理。
- 2009 年 EC2 用于整個網站。傳輸數據到 EC2 能讓網站癱瘓一整天。稍后會談到著名的數據重力例子。
EC2
- 遷移到 EC2 上的動機
- 堆疊機架不好玩。不想租用更多的機柜和購買更多的服務器。
- 增長過快的數據中心,在初期增長是不可預知的。
- 4 人一組的使用情況下成本是有效的。EC2 比在舊金山的數據中心便宜 29%。
- EC2 不是靈丹妙藥。你要經受更高的網絡延遲和嘈雜的鄰居,所以計劃好應對方案。好處是你可以按照你所需要的增長。
- 在 EC2 上跟蹤資源限制
- 所有資源都有賬戶限制。
- 亞馬遜甚至不知道他們的一些限制是什么。
- 跟蹤限制,并在需要它們之前提出警示。
- 捕獲異常去發現已達到異常。
架構
- Reddit 的架構很簡單。用戶連接到跟應用層對話的網絡層。應用層跟 memcache[14],Cassandra[15],以及 Postgres 對話。Postgres 使用主從配置。批處理系統使用 Cassandra 和 Postgres。
- 相比之下,Netflix 使用面向服務的架構,組件間使用 REST[16] 應用程序接口相互交談。
- 優點:更容易自動調節,因為只是服務有問題需要調節;更容易計劃規模;更容易識別問題,因為它們在 REST 調用背后都是孤立的;縮小變動的影響;更有效的本地緩存。
- 缺點:需要多個開發團隊或工作在多個服務上的開發者,因此你需要更多的人;需要一個共同的平臺以防重復工作;對剛起步的小團隊來說太多的間接支出。
- PostgreSQL 是一個出色數據庫。它建立了一個美好的,真地很快的鍵值存儲。
- 電子郵件是一個很難的問題。很難正確送達。從使用自己的電子郵件服務器開始,但是今天可能會去選擇電子郵件服務提供商。
- 隊列是個救世主。組件之間傳遞工作時,把它放到一個隊列。你會得到一個不錯的小緩沖區。(Reddit 使用 RabbitMQ[17] 作為消息隊列。)
- 混合 HAProxy[18] 和 Nginx[19]。一些流量被引導到它們中的一個。在嘗試 Niginx(遇到故障)后,負載均衡會選擇 HAProxy。它進行 L7[20] 負載均衡。Nginx 仍被用來終止 SSL[21],并提供靜態內容。
代碼
- 框架。從開始使用一個基于 Python 架構的 Pylons[22](Django[23]太慢了)。Pylons 很容易上手,不過最終因為跟用例不匹配,失敗了。對 Pylon 做了很大改動,結果最后使得它難以升級到新版本(現在修復了)。會將再次使用金字塔的(Pylons 的新名字)。
- 基于線程的事件?基于線程可以提前以排列大小,但大小可能是錯誤的。基于事件可以處理更多連接。但是當你碰壁時就只能碰壁。你想花更多時間來規劃你得線程池大小,還是就突然碰壁?
- 開源很不錯。Reddit 建立在開源基礎上。不用為軟件付錢很不錯,特別是在起步階段。
數據
- 數據是公司最重要的資產。非死book,Google 和 Flickr[24] 等公司建立在數據之上。
- 數據重力。你把數據放在將需要的地方,接近你的應用。思路是把所有你想要的應用圍繞在數據周圍。數據創建一個重力井,其他東西需要在它附近,因為數據是最難移動的。數據集越大就越難移動。目前移出 EC2 的成本太大了。這就是為什么 EC2 允許你免費導入數據,當你導出時向你收費。他們希望你把你所有的數據放在云中。
- 關系與非關系。Reddit 里的大部分數據是以鍵值方式存儲在 Postgres。為了處理和更容易分析,一切涉及金錢交易的數據被保存在關系數據庫。
- Postgres 很穩定。它堅如磐石,他們從未有過自身問題。如果他們有問題,那也是它周圍事物的問題,例如用 Python 編寫的應用系統。(所以)很難找到 Postgres 專家。
- Postgres 被選為鍵值存儲,因為當時還木有 Cassandra。另外,Postgres 的速度非常快,而且現在原生地支持鍵值(KV)。
- 分區。寫入被分割的四個主數據庫:鏈接,帳戶,subreddits[25],評論,投票,以及雜項。
- 每個都有從屬。表決數據庫有一個主數據庫,一個從屬數據庫。注釋數據庫有一個主數據庫和 12 個從屬數據庫。
- 如果可能的話避免從主數據庫讀取,而是直接從從屬數據庫讀取,以保持主數據庫專門進行寫操作。
- 客戶端庫將在從屬數據庫之間進行負載平衡,如果一個從屬數據庫處于忙狀態,則嘗試新的一個。
- 寫數據庫訪問層叫做“事情”。
- 這種方法工作了很長一段時間。分片相結合的數據庫,讀取從屬,跟蹤閱讀從屬的負載均衡性能。
- Cassandra。
- 快速寫入,快速反查詢,簡單的增量可擴展性,無單點故障。
- 在 Netflix 數據被分布在三個不同的區域。所有數據的副本在所有三個區域。即使一個區域丟失了,它們仍然可以運行。
- 在 Cassandra,切換投票數據是 reddit 的一個巨大成功。Cassandra 的布隆過濾器(Bloom Filters[26])真正激活快速反查詢。它能很快識別哪個評論你沒有投票,所以否定的回答很快回來。(更多關于這個話題)
社交
- 2008年 reddit 是開源的
- 用戶可以讀取代碼,得知他們沒有篡改投票。
- 用戶可以添加他們總是想添加的功能,reddit 會接受它。這個行不通,因為人們并不真的想寫代碼。
- 招聘。其他人知道這代碼,所以更容易雇人。
- 蠕蟲事件。有人想出了如何通過注入額外的 JavaScript 頁面編寫一個蠕蟲病毒。它確實無意,但是失控了。在創始人之一結婚的當天,整個團隊乘一架飛機從婚禮回來。但一個用戶已經回應了一個補丁,將中止蠕蟲蔓延。代碼開源,讓社區在危機時刻幫了忙。
Reddit 如何掙錢?
- 側欄廣告,自助式廣告,商品,reddit gold,市場。
- 需要注意的是 reddit 是尚未盈利(鏈接)。這帶來了一個問題,像 reddit 這樣的網站,什么時候能在云端盈利?
- 還要注意的是,reddit 已不屬于 Condé Nast[27] 了,所以它是獨立的。(鏈接)
錯誤
- 沒有考慮到遷移到 EC2 后增加的延遲。在數據中心,他們有亞毫秒級的機器之間訪問,所以進行 1000 次調用來 memache 一個頁面負載時可行的。在 EC2 上并非如此。 Memcache 訪問時間增加了 10 倍到毫秒級,使他們的老辦法也不用上了。修復方法就是批量調用以 Memcache 一個請求內如此大量的服務。
- 只是承諾。亞馬遜并不總是兌現承諾,并圍繞承諾工作。繞過故障,而不是試圖解決這些問題的設計。 (這里沒有提到,也許 EBS?)
- 在生產中使用尖端產品。Cassandra 仍在其開發早期就被使用。現在真的是出色,但那時它是有問題的。
- 本應該更早卸載很多工作給客戶端。服務器做了很多的頁面渲染,本應該交給客戶端去做。 非死book 是這方面的大師。你得到一個有很多分區的矩形,API 被調用來填充所有分區。這就是他們起初所希望的 reddit。它本可以擴展得更好。它還有助于調試,因為很容易確定哪個 API 調用出了問題。
- 不具備足夠的監控性,使用的監控系統的虛擬化不夠友好。一開始用的是 Ganglia[28],倒是有很好的圖形界面,但很難使用,而且變化太快。
- 數據沒有過期期限。 你可以在 reddit 挖墳看早期的評論回復。他們已經開始限制,所以你不能給舊評論投票,或給舊帖添加評論。否則會導致數據隨著時間的推移不斷增長,使得在數據庫保存熱點數據的難度越來越大。
- 沒有使用一致的哈希。當哈希到一個緩存,問題是如果你需要添加更多的緩存,你會被卡住,因為所有的數據是在一個或者許多你正在哈希的緩存。當增加緩存時你無法在此平衡。一致的哈希是一種解決這個問題的方法。遷移到 Cassandra 解決了它。
經驗教訓
- 擴展的關鍵是在你的用戶之前找到瓶頸。
- 使用代理是擴展的巨大福音。用戶可以根據他們擊中的 URL 被路由。 Reddit 有一個系統,監控每個 URL 用多久得到服務。人們被放進不同的線路。慢流量去一個地方,快的去另一個。基于平均響應速度的流量分割是一個巨大的促進。
- 所有的事情自動化。如果你對待你的基礎設施如同對待你的代碼,你的生活會容易得多。一切都應該自動開啟,并自動進行配置。
- 沒有必要從一開始就建立一個可擴展的架構。一開始時你不知道什么會是你的功能集,所以你也不知道你有會有哪些擴展問題。隨著你的網站增長,你可以了解哪里將是擴展問題。
- 剛起步時不要使用面向服務的架構。記住,當發展到中等規模時你可以去實現它;否則只會有太多的開銷。
- 不要跟隨潮流。有時候跟潮流是對的,例如 node.js。
- 給所有東西加個限制。給反復發生的事情設置一個上限,并根據需要提高或降低限制。如果超過限制,阻止用戶以保護正常服務。例如為 subreddits 上傳文件標識。用戶想到了他們可以上傳真正的大文件,這會損害系統。也不要接受巨大的文本。會有人 hi 想給你發送 5GB 的文本。
- 長遠計劃。在設計時總是假設將有一大堆你在做的。應用服務器,數據庫,緩存。總是假定你打算從一開始有一個以上的。這將在未來更容易橫向擴展。
- 用C重寫 Python 函數。在 reddit 擴展中為獲取速度,他們找出 Python 代碼里最重復的函數,并用C重寫。特別是過濾器,markdown 渲染,memcache 調用。Python 的好處是容易和高效地調用C。
- 盡可能保持無結構模式。這樣的話,可以很容易地增加新的功能。你所要做的就是添加新的屬性,而無需改變表格。
- 數據過期。鎖定舊帖和創建一個完全渲染的頁面并緩存它。這是如何應對有可能要淹沒你的數據庫的所有舊數據。同時,不要允許在舊的評論上投票,或給舊帖添加評論。用戶很少會注意到。
- 把 SSD 當作便宜的內存,而不是昂貴的磁盤。 當 reddit 的數據庫從旋轉磁盤轉到 SSD 時,服務器的數量從 12 個減少到 1 個,還有很大的余量。SSD 是貴了 4 倍,但你會得到 16 倍的性能,物有所值。在 Netflix 和 Reddit 上一些最大的 Cassandra 節點都是在 SSD 上,這作出了巨大的改善。
- 每個工具都有不同的使用情況。Memcache 沒有保證持久性,但是非常快,所以投票數據存儲在那里,以使渲染頁面盡可能的快。Cassandra 持久,快速,并能提供快速的反查詢,因為其布隆過濾器,所以它適合存儲不在 memchche 里的持久投票數據副本。 Postgres 是堅如磐石而且是關系型的,所以這是一個很好的地方作為備份 Cassandra 投票(如果需要,Cassandra 中的所有數據可以從 Postgres 生成),也做批量處理,有時這需要關系的能力。
- 將未登錄用戶當作二等公民。未登錄用戶登占據約 80% 的流量,現在是接近 50%。總是給未登錄用戶緩存內容,Akamai 承受了 Reddit 流量的消耗。有了巨大的性能改進。附帶的好處是如果 reddit 宕機,你不登錄的話,你可能永遠不會知道。
- 把一切都放入一個隊列。投票,評論,創建縮略圖,預計算查詢,郵件處理和更正。隊列通過監控隊列長度允許你知道什么時候有一個問題。附帶的好處是隊列隱藏用戶的問題,因為諸如投票請求的事情都在排隊,如果它們不被立即應用無人注意。
- 在多個可用區保存數據。
- 避免在單一實例上保存狀態。
- 得頻繁快照 EBS 磁盤。
- 不要在實例上保存密鑰。亞馬遜現在服務向你提供實例鍵。
- 基于安全組分解功能。
- 提供 API。程序員將會在你的平臺上做東西。例如,reddit 的 iPhone 應用程序,就是其他人用公開的 API 制作的。
- 在自己的社區活躍。Reddit 的用戶喜歡 reddit 的管理員在自己網站上活躍,并與他們互動。
- 讓用戶為你工作。有用戶輸入的網站的問題總是有作弊、垃圾郵件和欺詐。Reddit 大部分管理的工作是由成千上萬的志愿者來完成的,比如他們處理大多數的垃圾郵件問題。這種方式工作得非常好,是 reddit 的可以保持小團隊的原因之一。
- 給用戶一點權利,看他們用它做什么,把好東西變成功能。例如,當添加了給 subreddits 增加 CSS 的能力時,他們看到人們在做什么,增加了許多通用的東西作為大家的功能。這也使得用戶能在 Reddit 上做東西而興奮,因為他們喜歡那種操控感。有很多其他的例子。
- 傾聽你的用戶。用戶會告訴你很多你不知道但是你可能想知道的東西。例如,reddit gold 在社區里以一個笑話開始。后來他們把它做成了產品,用戶也很喜歡。
譯注:
1. Reddit 是一家美國社交新聞網站 Reddit.com。
2. RAMP 是一個所有創業者在擴大經營規模前想要參加的討論會。
3. Netflix 是一家美國公司,提供互聯網隨選流媒體播放、在線出租業務。
4. SSD 即 Solid State Disk 固態硬盤。
5. RAM 即 Random Access Memory 隨機訪問存儲器。
6. Akamai 是一家美國內容分發網絡(CDN)服務商。
7. Postgres 即 PostgreSQL, 是一個自由的對象-關系數據庫服務器(數據庫管理系統)。
8. EBS 即 exclusion basis system,動態密鑰管理方法。
9. Y Combinator 是一家以投資種子階段初創公司為業務的創投公司。
10. Digg 即“掘客”,或者“頂格”,美國公司,2012 年被紐約科技開發公司 Betaworks 收購。
11. EC2 即亞馬遜彈性計算云(Elastic Compute Cloud),是一個讓使用者可以租用云端電腦運行所需應用的系統。
12. S3 即亞馬遜簡易存儲服務(Simple Storage Service),由亞馬遜網絡服務系統提供的在線存儲服務。
13. V*N 即虛擬專用網絡(Virtual Private Network),是在公用網絡上建立專用網絡的技術。
14. Memcache 是一個高性能的分布式的內存對象緩存系統。
15. Cassandra 是一套開源分布式 NoSQL 數據庫系統。
16. REST 即表征狀態轉移(Representational State Transfer)是 Roy Fielding 博士在 2000 年博士論文中提出來的一種軟件架構風格。
18. HAProxy 提供高可用性、負載均衡以及基于 TCP 和 HTTP 應用的代理。
19. Nginx 即 engine x,是一個高性能的 HTTP 和反向代理服務器。
21. SSL 即 Secure Sockets Layer 安全套接層,是為網絡通信提供安全及數據完整性的一種安全協議。
22. Pylons 是一個開放源代碼的 Web 應用框架,使用 python 語言編寫。
23. Django 是一個開放源代碼的 Web 應用框架,使用 python 語言編寫。
25. Subreddit 是 reddit 上一個定制的子論壇。
26. Bloom Filter 即布隆過濾器,是一個很長的二進制向量和一系列隨機映射函數。
27. Condé Nast 即康泰納仕,是一個總部位于美國紐約市的國際期刊出版集團。