LinkedIn架構這十年

jopen 9年前發布 | 23K 次閱讀 LinkedIn 軟件架構
 

2003年是LinkedIn元年,公司成立的目標是連接你的個人人脈以獲得更好的的工作機會。上線第一周才有2700個會員注冊,時光飛梭,LinkedIn的產品、會員數量、服務器負載都極大的增長了。

今天,LinkedIn全球用戶已經超過3.5億。我們每秒有數十萬個頁面被訪問,移動端流量已占到50%以上 (mobile moment)。所有這些請求都從后臺獲取數據,而我們的后臺系統可以處理每秒上百萬次查詢。

問題來了: 所有這些是怎么做到的呢

早期

Leo

和現在很多站點開始的時候一樣, LinkedIn使用一個應用程序做所有的工作。 這個應用程序被稱之為 “Leo”。它包含所有的Java Servlet頁面, 處理業務邏輯, 連接少量的LinkedIn數據庫。

*

哈!早年網站的樣式-簡單實用*

Member Graph (會員關系圖)

開始的工作之一就是管理會員之間關系的社交網絡。我們需要一個系統通過圖遍歷(graph traversals)的方式來查詢關系數據, 同時需要將數據駐留內存以便獲得高效和性能。從這個不同的使用特征來看, 很明顯這需要一個獨立于Leo的系統以方便擴大規模,于是一個叫做”Clould”專門用于會員關系圖(member graph)的獨立系統誕生了。這是LinkedIn的第一個服務系統。為了和Leo系統分離,我們使用Java RPC來進行通訊。

也大約在此期間我們需要增加搜索服務的能力。我們的會員關系圖服務也提供數據給一個基于Lucene的搜索服務。

Replica read DBs (多個只讀數據庫副本)

隨著站點的增長, Leo系統也在擴大, 增加了更多的角色和職能, 也更加復雜。 通過負載均衡可以運行多個Leo實例,但是新增的負載也影響到LinkedIn的最關鍵系統-會員信息數據庫。

一個最容易的解決方案就是垂直擴展 – 在其上增加更多的CPU和內存。這雖然可以支撐一段時間,但是將來我們還是會遇到規模擴展的問題。會員信息數據庫既處理讀又處理寫。 為了擴展,我們引入了復制從庫(replica slave DB)。 復制數據庫是會員數據庫的一個拷貝, 使用 databus (現已開源)的最早版本來進行同步。這些復制從庫處理所有的讀請求, 并且增加了保證主庫和從庫數據一致性的邏輯。

*主從讀寫分離的方案之后,我們轉向了數據庫分區的解決方案*

當站點遇到越來越多的流量時,單一的Leo系統經常宕機,而且很難排查和恢復, 發布新代碼也很困難。 高可用性對LinkedIn至關重要, 很明顯我們需要”干掉” Leo, 把它分解成多個小的功能模塊和無狀態的服務。

*”Kill Leo”這個咒語在內部傳頌了好多年*

Service Oriented Architecture (面向服務的架構)

工程師開始抽取出一些微服務, 這些微服務提供API和一些業務邏輯, 如搜索,會員信息, 通訊和群組平臺。接著我們的表現層也被抽取出來了,比如招聘產品和公共信息頁。新產品,新服務都獨立于Leo。 不久,各個功能區的垂直棧完成了。

我們構建了前端服務器, 可以從不同的域獲取數據,處理展示邏輯以及生成HTML (通過JSP)。我們還構建了中間層服務提供API接口訪問數據模型以及提供數據庫一致性訪問后端數據服務。到2010年,我們已經有超過150個獨立的服務,而今天,我們已經有超過750個服務。

因為無狀態, 規模擴展可以通過堆疊任意服務的新實例以及在它們之間進行負載均衡來完成。我們給每個服務設定了警戒紅線, 知道它的負載能力, 提供早期預警和性能監控。

cache (緩存)

LinkedIn可預見的增長促使我們要進一步的擴展。我們知道通過添加更多的緩存層以減少負載壓力。很多應用開始引入中間緩存層如 memecached 或者 couchbase。 我們還在數據層增加了緩存, 并且在適當的時候使用 Voldemort 提供預先計算的結果。

之后,我們實際上去掉了中間緩存層。中間緩存層存儲來自多個域的數據。雖然開始時緩存看起來是減少壓力的一種簡單方式,但是緩存數據失效的復雜性和調用圖(call graph)變得無法控制。將緩存更可能地接近數據層可以降低延遲, 使我們可以水平擴展,降低可知的負載(cognitive load)。

Kafka

為了收集日益增長的數據,LinkedIn開發了很多定制的數據通道來流水化和隊列化數據(streaming and queueing)。 比如, 我們需要將數據放入數據倉庫,我們需要將一批數據放入Hadoop工作流以便分析,我們從每個服務中中聚合了大量日志, 我們收集了很多用戶追蹤事件如頁面點擊, 我們需要隊列化inMail消息系統中的數據, 我們需要保證用戶更新完個人信息后搜索數據也是最新的等等。

隨著網站還在壯大,更多的定制管道出現了。 因為網站規模需要擴展,每一個獨立的管道也需要擴展, 有些東西不得不放棄。 結果就是Kafka開發出來了, 它是我們的分布式的發布訂閱消息系統。Kafka成為一個統一的管道, 根據commit log的概念構建, 特別注重速度和擴展性。 它可以接近實時的訪問數據源,驅動Hadoop任務, 允許我們構建實時的分析,廣泛地提升了我們的站點監控和報警能力, 也使我們能夠可視化和跟蹤調用圖(call graph)。 今天, Kafka

每天處理超過5千億的事件。

Inversion(反轉)

擴展可以從很多維度來衡量,包括組織結構。 在2011年底, LinkedIn開始了一個內部創新,叫 “反轉” (Inversion)。我們暫停了新功能的開發, 允許整個工程部門專注于提升工具,部署,基礎架構和開發者生產力上。它成功地使我們可以敏捷地建立可擴展性新產品。

近幾年

Rest.li

當我們從Leao轉向面向服務的架構后,之前抽取的基于Java RPC的API, 在團隊中開始變得不一致了,和表現層耦合太緊,這只會變得更糟。為了解決這個問題, 我們開發了一個新的API模型,叫做 Rest.li. Rest.li 符合我們面向數據模型的架構, 確保在整個公司提供一致性的無狀態的Restful API模型。

基于HTTP的JSON數據, 我們新的API最終很容易地編寫非Java的客戶端。 LinkedIn今天仍然主要使用Java棧,但是也有很多使用Python, Ruby, Node.js 和 C++的客戶端,可能是自己開發的或者收購過來的。 脫離了RPC也讓我們將變現層和后端兼容型的問題中掙脫出來。另外, 使用Dynamic Discovery (D2)的Rest.li, 我們可以得到自動的基于負載均衡,服務發現和可擴展的API客戶端。

今天, LinkedIn有975 個Rest.li資源, 所有的數據中心每天有超過一千億級Rest.li調用。

Rest.li R2/D2 技術站

Super Blocks (超級塊)

面向服務的架構很好的解耦了域之間的聯系和可以獨立地擴展服務。但是也有缺點, 很多應用獲取各種類型的不同的數據, f(call graph)或者叫做”扇出” (fanout)。例如, 任意一次個人信息頁的請求就會獲取照片,會員關系, 組,訂閱信息, 關注,博客,人脈,推薦等信息。 這個調用圖很難管理,而且越來越難控制。我們引入了超級塊的概念。 為一組后臺服務提供一個單一的訪問API。這樣我們就可以有一個team專門優化這個塊,同時保證每個客戶端的調用圖可控。

Multi-Data Center (多數據中心)

作為一個會員快速增長的全球化公司,我們需要從一個數據中心進行擴展,我們通過幾年的努力來解決這個問題,首先,從兩個數據中心(洛杉磯 和 芝加哥)提供了公共個人信息,證明可行后,我們開始增強服務來處理數據復制、不同源的調用、單向數據復制事件、將用戶分配到地理位置更近的數據中心。

我們大多的數據庫運行在Espresso(一個新的內部多用戶數據倉庫)上。

Espresso支持多個數據中心,提供了 主-主 的支持,及支持很難的數據復制。

多個數據中心對于高可用性具有不可思議的重要性,你要避免的單點故障不僅僅是某個服務失效,更要擔心整個站點失效。今天,LinkedIn運行了3個主數據中心,同時還有全球化的PoPs服務。

LinkedIn’s operational setup as of 2015 (circles represent data centers, diamonds represent PoPs)

我們還做了哪些工作?

當然,我們的擴展故事永遠不會這么簡單。我們的工程和運維團隊這些年做了不計其數的工作,主要包括這些大的創新:這些年很多最關鍵系統都有自己豐富的擴展演化歷史,包括會員圖服務(Leo之外的第一個服務),搜索(第二個服務),新聞種子,通訊平臺及會員信息后臺。

我們還構建了數據基礎平臺支持長期的增長,這是Databus和Kafka的第一次實戰,后來用Samza做數據流服務,Espresso和 Voldemort作存儲解決方案,Pinot用來分析系統,以及其它自定義解決方案。另外,我們的工具也得到了提升,這樣工程師就可以自動化布署這些基礎架構。

我們還使用Hadoop和Voldemort數據開發了大量的離線工作流,用以智能分析,如“你可能認識的人”,“相似經歷”,“感覺興趣的校友”及“個人簡歷瀏覽地圖”。

我們重新考慮了前端的實現,增加客戶端模板到混合頁面(個人中心、我的大學頁面),這樣應用可以更加可交互,只要我們的服務器發送JSON或部分 JSON數據。此外,模板頁面通過CDN和瀏覽器緩存。我們也開始使用了BigPipe和Play框架,把我們的模型從線程化的服務器變成非阻塞異步的服務器。

除了代碼,我們使用了Apache Traffic Server做多層代理和用HAProxy做負載均衡,數據中心,安全,智能路由,服務端渲染等等。

最后,我們繼續提升服務器的性能,包含優化硬件,內存和系統的高級優化,使用更新的JRE。

下一步

LinkedIn今天仍在快速增長,仍有大量值得提升的工作要做,我們正在解決一些問題,看起來只解決了一部分 – 快來加入我們吧!

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!