從Reddit學到的七條經驗
Steve Huffman,Reddit的共同創始人,分享了將Reddit從一個小型Web應用程序發展為大型社交網站過程中學到的主要經驗。
Steve Huffman和Alexis Ohanian在2005年創建了Reddit,當時在一臺機器上運行Web應用程序、應用服務器和數據庫。 發展至今,Reddit已經成長為每月750 萬用戶、2億7千萬PV的站點。
Huffman在一次演講 中談到 Reddit發展過程中學到的經驗, 他們犯的很多錯誤,以及他們是如何修復這些錯誤的。
1、宕機是家常便飯
起初他們經常宕機,Huffman常常睡在筆記本電腦旁邊,每隔幾個小時就醒一下,看看網站是否仍在運行。
當時的解決方案是使用 Supervise,那是一個能重啟崩潰應用程序的守護進程。 這帶來了一種很有趣的運行應用程序的方式:如果應用程序有內存泄露,或者消耗了太多的內存, 只需終止它隨后重啟即可。 這只是一個臨時方案,而非最佳方案,最終是基于日志內容修復了應用程序。
2、服務分離
Huffman建議將類似的進程集中在一臺機器或一組機器上,這樣可以避免頻繁的上下文切換,減少資源消耗。 他還提供了一個最佳實踐——在一個數據 庫中處理類似的數據,以此避免頻繁的索引緩存切換, 將其他類型的數據移到別的機器上去。
Huffman強烈建議避免使用線程,在Python中這就是“死亡之吻,緩慢之道”。 如果多個任務被分配到獨立的進程而非線程上,那在請求量上 升、需要更多資源的時候, 就可以方便地將它們移到不同的機器上。
這種做法的唯一問題就是進程間通信,除此之外都比使用線程要好,因為這樣的架構能更平滑地 進行擴展。
3、開放Schema
隨著數據庫的發展,每個要更新Schema的新特性都會帶來更多的問題。 向一個有1千萬行數據的表中增加一個新字段需要很多時間,尤其是有備份 (backup)和復制(replication)時。 他們當時雖然沒有備份,但也花了好多天,因為他們構建了一個副本(replica)。
解決方案是使用開放Schema或實體-屬性值,Key-Value存儲。現在每個數據類型有兩張表:
image
Thing 可以是用戶、鏈接、評論等,共享相同的Schema。 Data 表由大量數據構成,但里面只有3個字 段:ID、 Key和Value。 在新的Schema中添加新特性并不涉及Schema的變更,也不需要創建新表。 此外,再也沒有數據庫的join操作,這也易于數據 庫的拆分。
4、保持無狀態
所有Web應用程序都有一個共同的目標,它的每臺應用服務器都能處理任意請求。 這個目標在只有一臺機器時很容易達成(這是顯而易見的),但當使用多 臺服務器并緩存應用狀態時,情況就變得復雜了。 每臺服務器在訪問緩存數據時的復雜性都增加了,而且還加入了更多的緩存冗余。
此處的解決方案是切換到memcache并在所有應用服務器上不再使用狀態。 一個立竿見影的效果是一臺應用程序服務器宕機時不會影響其他服務器。 此外,可以簡單地通過增加更多服務器來進行擴展。
將緩存服務器與其他服務器隔離開是很重要的,這能避免資源爭奪。
5、Memcache所有內容
Reddit的所有內容都使用了memcache:數據庫的數據、會話數據、渲染的頁面、存儲的內部函數、預先計算的頁面、全局鎖。 它們還用 memcachedb進行數據持久化。
6、存儲冗余數據
“在你需要前,數據都保持正規化”會降低性能。
當用戶需要以特定格式來展現數據時,獲取原始數據隨即進行處理會延長響應時間,以至于用戶放棄等待結果。 解決方案是在內存和硬盤中保存數據的所有格式。這樣做對磁盤和內存有些影響,但對用戶請求的快速響應很有幫助。
對Reddit而言,速度的關鍵是“預先計算所有內容并放入memcache。”
7、脫機工作
當用戶發起請求時,系統要執行用于返回適當響應的必要工作,其他事情都放到隊列任務中脫機執行。
例如,脫機執行的工作包括:預先計算列表、獲取縮略 圖、檢測欺騙行為、刪除垃圾信息、計算獎勵以及更新搜索索引。 當用戶給某個鏈接投票時,他并不需要等待所有索引和列表更新完畢,這些任務可以在響應用戶后 再去執行。