WhatsApp的Erlang世界

rick 的兩個ppt整理

下載:2012 2013  ,使用半年erlang後,從新看這兩個ppt才發現更多值的學習的地方,從ppt中整理以下:前端

 

- Prefer os:timestamp to erlang:nownode

  應該禁止使用erlang:now(),稍微用得多,整個node的%si 飆滿,且總體性能數量級降低。git


- Implement cross-node gen_server calls without  using monitors (reduces dist traffic and proc link lock contention)
github

  能夠實現本身的rpc 模塊,不是每次調用都monitor - call - demonitor,消耗太大。能夠第一次調用就永久性monitor。redis

 

- Partition ets and mnesia tables and localize access to smaller number of processes數據庫

  爲減小鎖爭用,對 ets,mnesia 作拆分,而且儘可能少的進程去訪問同一個ets/mesia,高併發訪問時嚴重影響性能且佔用CPU。後端

  whatsapp 限制訪問單ets或者mnesia進程的數量到8,這會讓鎖爭用處於控制當中。緩存

 

- Small mnesia clusters服務器

   使用小的mnesia 集羣,從ppt看出whatsapp 所有采用優化過的 async_dirty 操做mneisa表,不使用事務,並且通常集羣只有兩個節點(一主一備,只操做主)。網絡

   mnesia 集羣有很是好的集羣效果,但大的集羣對性能影響太大。曾經測試過20個節點集羣,在其中一個節點執行幾十字節行的:read-update transaction,8K/s 居然把node的千M網卡跑滿了。

 

- Offloaded SSL termination to stud

    whatsapp 的多媒體文件下載使用的是https,yaws服務前使用 stud: https://github.com/bumptech/stud  做爲ssl 的proxy。

    曾經測試,16G機器最多20w鏈接 2500/s 新建鏈接速度,ssl新建鏈接處理爲CPU密集型,純 erlang實現過於低效,性能在大量短鏈接狀況並不樂觀。不過使用大量loopback 地址解決64K tcp port 問題,若是鏈接數太高的話,也帶來內存消耗,也許能夠在stud將請求rpc 化轉給後端處理也能解決。

 

-  chat message encrypt

  https://github.com/davidgfnet/wireshark-whatsapp/blob/master/protocol-spec.txt

      ssl 流程過於複雜,鏈接速度慢;使用密碼+random code 做爲rc4密鑰加密,連密鑰交互過程都省了。

 

   whatsapp 存儲方案:

  - mnesia memory(相似redis 當作 cache用,相比好處嘛,更靈活):

內存Mnesia數據庫使用大約2TB的RAM,跨16個分片存儲180億條記錄。

只存儲正在發佈的消息和多媒體,可是在多媒體發佈時,會將信息儲存在數據庫中。

由於whatsapp 不會長期存儲全部的用戶消息記錄,而是接受完後就刪除。每條消息都被用戶快速的讀取,60秒內完成50%。

所以設計全部消息先存儲在 內存Mnesia,若是必定時間被接收完了,就直接刪除。長時間未收取才落地。

 

  - mnesia disc(用戶信息,離線消息):

圖片、音視頻文件索引信息,實際文件存儲在磁盤上面(ppt上每臺機器存儲189G * 16 Node,不是說每臺機器500GB內存麼)。

用戶信息、消息等

 

[轉] WhatsApp的Erlang世界 (很是棒的一篇文章)

 http://www.csdn.net/article/2014-04-04/2819158-how-whatsapp-grew-to-nearly-500-million-users-11000-cores-an/1

在以前咱們有分享過HighScalability創始人Tod Hoff總結的WhatsApp早期架構,其中包括了大量的Erlang優化來支撐單服務器200萬併發鏈接,以及如何支撐全部類型的手機並提供一個完美的用戶體驗。然而時過境遷,兩年後WhatsApp又是如何支撐10倍於以前的流量,以及應用的飛速擴展,這裏咱們一塊兒看Tod帶來的總結。

 

這裏總結了一些WhatsApp兩年內發生的主要變化:

1. 從任何維度上均可以看到WhatsApp的鉅變,可是工程師的數量卻一直未變。當下,WhatsApp有更多的主機、更多的數據中心、更多的內存、更多的用戶以及更多的擴展性問題,然而最引覺得豪的倒是那支10人工程團隊——每一個工程師平均負責4000萬個用戶。固然,這也是雲時代的勝利:工程師只負責軟件的開發,網絡、硬件及數據中心運維所有假手於人。

2. 在以前,面對負載的激增,他們必須讓單服務器支撐儘量多的鏈接數,可是如今他們已經步出了那個時代。固然,基於整體成本的控制,他們仍然須要控制主機的數量並讓SMP主機更效率的運行。

3. 瞬時的好處。鑑於如今的架構已經囊括多媒體、圖片、文本、音頻,無需保存這些大致積格式的信息讓系統大大的簡化,架構的重心被放在吞吐量、緩存以及分片等。

 4. Erlang的世界。即便他們打造的仍然是一個分佈式系統,碰見的問題也大同小異,可是從始至終都在說Erlang確實值得稱道。

 5. Mnesia,這個Erlang數據庫彷佛已成爲他們問題的主要來源。所以,不得不懷疑一味的緊抓Erlang會不會比較盲目,是否有其餘更好的替代方案。

 6. 如此規模下問題之多你能夠想象。海量鏈接數的保持、隊列因優先級操做變得太長、計時器、不一樣負載下的代碼表現問題、高負載下高優先級消息得不處處理、一個操做被另外一個操做意外打斷、故障致使的資源問題以及不一樣用戶平臺的兼容性等,巨型架構的打造絕非一朝一夕。

 7. Rick的發現和處理問題能力讓人讚歎,也能夠說是吃驚。

 Rick的分享老是很是精彩,他樂於分享許多細節,其中有許多隻能在生產環境出現。下面是他 最新分享總結:

 

-統計

 

月4.65億用戶

平均每日接收190億消息,發送400億消息

6億張圖片,2億條語音,1億段視頻

峯值期間1.47億的併發鏈接數——電話鏈接到系統

峯值期間每秒23萬次登錄操做——手機上線及下線

峯值期間每秒32.4萬信息流入,71.2萬的流出

約10個工程師致力於Erlang,他們肩負了開發與運維

節日的峯值

平安夜流出達146 Gb/s,至關多的帶寬用於服務手機

平安夜視頻下載達3.6億次

新年夜圖片下載約20億(46 k/s)

新年夜有張圖片下載了3200萬次

 

-堆棧

 

Erlang R16B01(打了本身的補丁)

FreeBSD 9.2

Mnesia(數據庫)

Yaws

使用了SoftLayer雲服務和實體服務器

 

-硬件

 

大約550個服務器+備份

150個左右的Chat服務器(每一個服務器處理大約100萬的手機、峯值期間1.5億的鏈接)

250個左右的多媒體信息服務器

2x2690v2 Ivy Bridge 10-core(總計40的超線程技術)

數據庫節點擁有512GB的內存

標準計算節點搭載64GB內存

SSD主要用於可靠性,存儲資源不足時還用於存儲視頻

Dual-link GigE x2(公共的面向用戶,私有的用於後端系統)

Erlang系統使用的核心超過1.1萬個

 

-系統概況

 

獨愛Erlang

很是棒的語言,適合小工程團隊。

很是棒的SMP可擴展性。能夠運行高配的主機,而且有益於減小節點。運維複雜性只與節點數有關,而不是核心數。

能夠飛快的更新代碼。

擴展性就像掃雷,可是他們總能夠在問題爆發以前發現並解決。世界級事件至關於作系統的壓力測試,特別是足球賽,會帶來很是高的峯值。服務器故障(一般是內存)、網絡故障以及差的軟件的推送都考驗着系統。

傳統的架構

手機客戶端鏈接到MMS(多媒體)

Chat鏈接到瞬態離線存儲,用戶之間的消息傳輸經過後端系統控制。

Chat鏈接到數據庫,好比Account、Profile、Push、Group等。

發送到手機的消息

文本消息

通知:羣組消息,我的簡介照片改變等

狀態消息:輸入狀態、離開狀態、在線或離線狀況等

多媒體數據庫

內存Mnesia數據庫使用大約2TB的RAM,跨16個分片存儲180億條記錄。

只存儲正在發佈的消息和多媒體,可是在多媒體發佈時,會將信息儲存在數據庫中。

當下單服務器只運行100萬的併發鏈接,而在兩年前這個數字是200萬,由於如今服務器要作的事情更多了:

隨着用戶量的增多,WhatsApp指望每一個服務器上預留更多的空間以應對峯值。

許多過去不是運行在這個服務器上的功能如今被移到上面,所以服務器更忙了。

 

-解耦

 

隔離瓶頸,讓之不會存在整個系統中

緊耦合會致使相繼故障

前端系統和後端系統首先要分離

隔離一切,讓組件間不會存在影響。

正在解決問題時,保持儘量多的吞吐量。

異步處理以最小化吞吐量延時

當延時不可預知及在不一樣點存在時,異步能夠儘量的保證吞吐量。

解耦可讓系統運行儘量的快。

避免HOL阻塞

線頭阻塞是首位處理會餓死隊列中其餘項目。

分離讀和寫隊列。特別是在表格上執行事務,寫入方面的延時不會影響讀取隊列,一般狀況下讀的速度會很快,所以任何阻塞都會影響讀性能。

分離節點內部隊列。若是節點或者網絡鏈接的節點出現問題,它可能會阻塞應用程序中其餘任務。所以,發往不一樣節點的消息會分配不一樣的進程(Erlang中的輕量級併發),所以只有當消息發送給問題節點時纔會作備份,這將容許消息自由的傳輸,問題被隔離開來,給Mnesia打補丁以保證async_dirty級響應時間。App發送消息後就會被解耦,所以當一個節點發生故障時,不會致使負載問題。

在不肯定延時場景下使用FIFO模型。

 

-Meta Custering

 

本節出如今講話的第29分鐘,不幸可是,信息量不大。

須要一種方法來控制單集羣體積,並容許他跨很長距離。

創建wandist,基於gen_tcp的分佈式傳輸,由許多須要相互通訊的節點組成。

1個基於pg2的透明路由層,創建一個單跳路由調度系統。

舉個例子:兩個數據中心的兩個主集羣,位於兩個不一樣數據中心的兩個多媒體集羣,以及兩個數據中心間一個共享的全局集羣,他們之間都使用wandist進行鏈接。

例子

使用async_dirty來避免Mnesia事務耦合,大部分狀況下不會使用事務。

只在從數據庫中恢復時才使用call,其餘狀況下都使用cast來維持異步模型。在Erlang,消息隊列會因等待handle_call響應而形成阻塞,handle_cast不會形成阻塞是由於它不關注結果。

Call使用超時而不是監視,減小遠端進程競爭以及分發時傳輸的數據。

若是隻是想追求最好的交付能力,爲cast使用nosuspend。這樣會阻止節點受到下游問題影響——無論是節點失敗仍是網絡問題(在這些狀況下,發送數據緩衝池會備份到發送節點上),進程發送的開始指令會被調度系統掛起,從而形成了相繼故障——你們都在等待,卻沒有操做正在被處理。

使用大的發送緩衝器,從而下降收來自網絡和下游系統的影響。

並行

 

-任務分配

 

須要在1.1萬個核心上分配任務

始於單線程的gen_server,而後創建了一個gen_factory負責多節點之間的任務傳遞。

在負載達到了必定程度,調度過程自己就變成了瓶頸,不只僅是執行時間問題。

所以創建一個gen_industry,位於gen_factory之上,從而並行的攝入全部輸入,而且有能力馬上給工做節點分配。

工做節點的尋址相似數據庫經過key查找,所以這裏存在不肯定延時,好比IO,因此爲了不線頭阻塞,這裏使用了一個FIFO模型。

 

- 分割服務

 

在2到32間進行分割,大部分服務都被分割成32個。

pg2 addressing,分佈式進程組,用於集羣上的分片尋址。

節點進行主從設置,用於容災。

限制訪問單ets或者mnesia進程的數量到8,這會讓鎖爭用處於控制當中。

 

- Mnesia

 

由於沒有使用事務去保證一致性,他們使用一個進程對一個節點上的記錄進行連續訪問。哈希到一個分片,會映射到1個mnesia fragment,最後會被調度到1個factory,隨後是節點。所以,對每一個單記錄的訪問都會被轉換成一個獨立的Erlang進程。

每一個mnesia fragment都只能在1個節點上的應用程序等級進行讀取,這樣複製流只須要在一處進行。

一旦節點間存在複製流,分片的更新速度上就會存在瓶頸。他們給OTP打補丁以實現多個事務管理器,用以實現async_dirty,從而記錄能夠並行的進行修改,這將產生更多的吞吐量。

打補丁容許Mnesia庫直接被分割到多個庫上,這就意味着它能夠寫多個驅動,這麼作能夠直接提高磁盤的吞吐量。這裏存在的問題是Mnesia達到峯值,經過多個磁盤來分攤IO,而爲了進一步提高可擴展性及性能,甚至會加入SSD。

將Mnesia「island」縮減到2個,每一個「island」都是一個Mnesia集羣。所以在表格被分割成32份時,將會有16個「island」支撐一個表格。從而,他們能夠進行更好的schema operation,由於只須要修改兩個節點。在同時打開1或2個節點時,能夠減小加載時間。

經過設置警報快速處理Mnesia中的網絡分片,讓它們繼續保持運行,而後手動的調節將它們整合。

 

-優化

 

在峯值狀況下,離線存儲系統曾是1個很是大的瓶頸,沒法更快的將消息推送到系統。

每條消息都被用戶快速的讀取,60秒內完成50%。

添加一個回寫緩存,這樣消息就能夠在寫入文件系統以前被交付,緩存命中率達98%。

若是IO系統由於負載而阻塞,緩存會對消息交付起到額外的緩衝做用,直到IO系統恢復。

給BEAM(Erlang VM打補丁)以實現異步文件IO來避免線頭阻塞問題,在全部異步工做線程上輪訓文件系統端口請求,在大型mailbox和緩慢磁盤的狀況下能夠緩解寫入。

讓大型的mailbox遠離緩存,有些用戶加入了大量的組,每小時收入數千消息。他們會影響整個緩存,並讓處理變慢。將它從緩存中驅除。須要注意的是,不成比例的大型用戶處理是每一個系統都存在的問題,其中包括Twitter。

使用大量的fragments下降mnesia表格的訪問速度

帳戶表格被分割成512份打入「island」,這就意味着用戶和這512個分片間存在一個稀疏映射,大部分的fragments都是空的和空閒的。

主機數量翻倍,可是吞吐量下降。記錄訪問變慢的緣由是當目標爲7時,哈希鏈的大小超過了2K。

這裏存在的一個問題是哈希模式會致使創建大量的空bucket,有些甚至會很是長。雙線的變化解決了這個問題,並將性能從4提高到1。

補丁

 

計時器輪上的競爭,當1個主機的鏈接數達到幾百萬,同時每一個連接上的手機發生變化時就會創建或重置計時器,從而致使了每秒數十萬的計時器。計時器輪上的鎖則是競爭的主要來源,解決方法就是創建多個計時器輪。

mnesia_tm 是個很是大的選擇循環,所以雖然負載未滿,也可能會形成事務的積壓,打補丁以收取事務流而且保存以做稍後處理。

添加多個mnesia_tm async_dirty發送者

存在許多的跨集羣操做,所以mnesia最好從附近的節點加載。

給異步文件IO加入循環調度。

使用ets哈希開防止w/ phash2的同時發生。

優化ets main/name table來應對規模

不要隊列mnesia dump,由於隊列中存在太多的dumps時,schema ops將不可行。

 

- 2月22日的停機

 

即便作了如此多的努力,停機仍然不可避免,並且發生在了最不該該發生的時候,在被Facebook收購後宕機了210分鐘。

負載的變化致使了問題的發生,這次宕機歸結於後端系統的路由問題。

路由器形成了一片局域網的癱瘓,形成了集羣中大量節點的斷開和重連。同時,在節點重連以後,集羣出現了史無前例的不穩定狀態。

最終,他們不得不停機修復,這種狀況在幾年內都未出現過。

在檢查中,他們發現了一個過分耦合的子系統。在斷開和重連時,他們發現pg2在作n^3的消息,消息隊列在數秒鐘內從0飆升到了400萬,爲此他們推出了1個補丁。

 

- 特性發布

 

沒法模擬如此規模的流量,特別是高峯期間,好比新年的鐘聲。所以,他們只能緩慢的發佈特性,先在小流量下發布,而後迅速迭代直到良好運行,接着再向其餘的集羣推廣。

上線是一個滾動的更新過程。冗餘一切,若是他們想作一個BEAM更新,在安裝後他們須要一個個的重啓集羣中的節點而後更新。也存在熱補丁的狀況,可是很罕見,一般的升級都很是麻煩。

相關文章
相關標籤/搜索