下載: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內存麼)。
用戶信息、消息等
在以前咱們有分享過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更新,在安裝後他們須要一個個的重啓集羣中的節點而後更新。也存在熱補丁的狀況,可是很罕見,一般的升級都很是麻煩。