Facebook技術總監:如何管理10億使用者的資料?

DinK發表於2013-01-28

譯文來源:騰訊科技

[導讀]Facebook資料庫中有超過1萬億物件,每秒處理10億次請求,管理這些資料是極大的挑戰。

Facebook使用者數量,已經突破10億大關。Facebook在發展期間,所實現的技術成就,成為了IT行業工程師關注的話題。究竟Facebook取得了哪些技術成就呢?Facebook前工程部門總監,在問答網站Quora上,對這一問題作出回答。無論對於IT行業的投資者還是使用者,這些回答都有著指導意義。

Facebook技術總監:如何管理10億使用者的資料?

以下是文章全文:

我在Facebook的基礎架構軟體開發團隊,工作了5年,並且參與了多數專案的開發。我認為在Facebook時,最偉大的成就是Memcache/MySQL叢集。一年前,我離開Facebook的時候,這個叢集中已經擁有超過1萬億物件(沒錯是萬億),每秒請求數量超過10億,處理時間通常不超過1毫秒。這一叢集,在多個資料中心之間,保持了良好的一致性,並且很少出現停機的情況。

實際上,我們取得的真正成就,與Memcache和MySQL並沒有多大的關係——隨著時間的推移,這些都將會被新的“技術”所取代,但是這裡真正重要的技術,是讓數量如此龐大的機器,快速、可靠的協同工作。這並不同於通常意義上,人們在詢問“你用的是什麼樣的技術?”時,所指代的東西,但是這一方面確實會出現很多有趣的創新。

這包括演算法方面的技巧,如分片(Shard)、分割槽(Partition)、快取資料,以及保持分散式資料的一致等。雖然像“部署和監控”這樣的事情,聽上去似乎有些很普通,但是當一切到了Facebook這樣大的規模,就變的不再簡單。

以下是我們面臨的一些具體的挑戰:

1. 資料中心間的一致性

Facebook是一個實時的應用程式,這也就意味著,無論世界哪一個角落的資料發生改變,都需要立即顯示到所有其他的地方。因此這對一致性有著令人驚訝的高要求。

常常有人說,“哦,Facebook只是一個讓人覺得挺有趣的社交網站,一致性並沒有那麼重要。”但是如果資訊出現的時間順序有問題,或者有的訊息會憑空消失,那麼這些情況就很容易惹惱使用者。以下是我們在2007年,建立首個地理分佈資料中心時的老部落格:《Scaling Out Facebook》

現在回頭看,雖然這個方案聽起來有些嚴格,但是它真的很有用,而且幫助讓我們達到了現在這個巨大得規模。而現在的設定顯然已經變得更為複雜。

2. 網路流

Facebook的頁面,需要很多小塊的資料,而這些往往並不容易聚集。所以我們經常看到的一個模式,是一臺伺服器,會從大量其他的伺服器處,要求大量小的物件。而這裡的問題在於,如果所有的伺服器都在同時進行回覆,你就會通過請求伺服器的rack switch和網路介面卡(NIC)突然獲得大量的資料包,然後就會有資料包被丟棄。這就是學術文獻中所謂的“TCP incast”,而我們解決這個的方法,是對機器上傳送的請求進行截流。

而當故障(failure)出現的時候,網路問題往往會變得更加糟糕。大多數軟體在沒有從另一個伺服器獲得迴應時,都會重新傳送另外一個資料包。不幸的是,大多數時候,沒有獲得回覆的原因,恰恰是另外一個伺服器已經過載。因此,當一個伺服器過載嚴重,而無法作出及時回覆時由於大量請求會重新傳送,它的資料流量會瞬時增長一倍。

我們投入了大量的時間用於演算法研究,並希望無縫處理“重試”(retry)可以解決的小問題,但是也需要確保不會在出現大故障的時候失去控制,因為那時候重試只會讓事情變得更糟。

3. 快取記憶體配置

這裡有很多東西需要平衡——如果你有大的物件,你希望通過機器進行傳遞開,這樣你就可以進行並行處理;但是如果是小的物件,你則希望它們可以同時出現,這樣在RPC呼叫會給你帶來多個物件。而Facebook需要的往往是後者,因此我們在改善“每RPC物件數量”方面,使用了很多的技巧。

很多情況都需要分離不同工作負載的物件,進行不同的調整。我們還花了大量的的時間,搞清楚是什麼記憶體之中最具有成本效益的東西,以及何時非規範化能有用(實踐中的大多數時候,非規範化並沒有什麼實質性的幫助)。

4. 失敗處理

正如前面網路部分所提到的,有的時候一些方法能夠解決小問題,但往往會讓大問題變得更糟。例如,我有一個演算法,給隨機伺服器傳送請求,如果它沒有得到答覆,就會把請求重新傳送到另一個不同的隨機伺服器上,直到它得到一個答覆才會停止。如果你只有一兩個機器出現問題的時候,這種方法顯然會表現很好。但是如果你一半的機器都出現問題,那麼就成了一場災難。

這時,所有其他的機器的負荷都會突然加倍,而如果一半的機器都出現問題,很有可能意味著有著負載已經過高。這時候,你需要做的事情,是檢測過載情況,並且減少負載。重要的是,要記住電腦科學意義上的實時系統,意味著:一個遲到的迴應,就是一個錯誤的迴應。

放棄一個請求的時候,人們往往會感覺不好,不過這往往是最好的處理方式——在出現問題的時候,最大化正確答案的數量才是最正確的。

另一種常見的模式是,當有些東西變慢的時候,就建立一個較大的佇列(queue),然後讓所有事情慢下來,減少負載。這可以是一個很棘手的演算法,因為你可能在正常操作中也需要一個深佇列,來處理瞬間突發流量。

5. 提升Memcache和MySQL

我們討論到資料庫/快取叢集的時候,人們總會想到Memecache和MySQL。我們在Memcache方面做了大量的工作,以提升吞吐量——大量的分析和解決方法,這大多數都是在網路棧中。因此很多這樣的工作,實際上是在Linux核心中發生的。

在MySQL中,則是關於以一種合理的方式,獲得磁碟上的資料,並且把記憶體中最有用的東西放到快取裡。馬克·卡拉漢(Mark Callaghan)的部落格中,有著大量的資訊:《高可用性MySQL》( http://mysqlha.blogspot.com/)。

6. Meta

在這篇文章中,我記錄了我們所遵循的原則:《讓Facebook的使用者超過5億》

相關文章