Medium開發團隊談架構設計_轉

轉自:Medium開發團隊談架構設計前端

 背景android

  說到底,Medium是個社交網絡,人們能夠在這裏分享有意思的故事和想法。據統計,目前累積的用戶閱讀時間已經超過14億分鐘,合兩千六百年。nginx

  咱們支持着每月兩千五百萬的讀者以及每週數以萬計的文章發佈。咱們不想Medium的文章以閱讀量爲成功的依據,而是觀點取勝。在Medium,文章的觀點比做者的名頭更重要。在這裏,對話促進想法,而且很看重文字的力量。git

  我是Medium開發團隊的負責人,此前在Google工做,負責開發Google+和Gmail,還創立了Closure項目。業餘時間我喜歡滑雪跳傘和叢林冒險。github

  團隊介紹golang

  提及團隊我很是自豪,這是一羣富有好奇心並且想法豐富的天才,你們湊到一塊是想作大事的。web

  團隊以跨功能的任務驅動,這樣每一個人既能夠專攻,又能夠毫無壓力的對整個架構有所貢獻。咱們的理念就是接觸的方面越多,對團隊的鍛鍊越大。更多關於團隊的理念見此數據庫

  在工做組織方面,咱們有着很大的自由度,固然做爲一個公司組成,咱們仍是有季度目標的,而且鼓勵敏捷開發模式。咱們使用GitHub進行code review和問題跟蹤,用Google Apps做爲郵件、文檔和表單系統。跟不少團隊習慣使用Trello不一樣,咱們是Slack和slack機器人的重度用戶。後端

  原始架構緩存

  最開始的時候,Medium部署在EC2上,用Node.js實現,後來公測的時候遷移到了DynamoDB

  其中有個節點用來處理圖片,負責將複雜的處理工做轉向GraphicsMagick。還有一個節點用做後臺的SQS隊列處理。

  咱們用SES處理郵件,S3作靜態元素服務器,CloudFront作CDN,nginx做爲反向代理,Datadog用來監控,Pagerduty用來告警。

  在線編輯器用了TinyMCE。上線以前咱們已經開始使用Closure編譯器以及部分的Closure庫,可是模板仍是用的Handlebars

  當前架構

  雖然Medium表面看起來很簡單,可是瞭解其後臺的複雜性後,你會大吃一驚。有人會說,這就是個博客啊,用Rails之類的一週就能搞定了。

  總之,閒話很少說,咱們自底向上介紹之後再作判斷。

  運行環境

  Medium目前運行在Amazon虛擬私有云,使用Ansible作系統管理,它支持配置文件模式,咱們將文件歸入代碼版本管理,這樣就能夠隨時回滾隨時掌控。

  Medium的後臺是個面向服務的架構,運行了大概二十幾個產品服務。劃分服務的依據取決於這部分功能的獨立性,以及對資源的使用特性。

  Medium的主體仍然是Node.js完成,方便前端和後端的代碼共享,主要是文章編輯和發佈這個過程。Node大部分時候不錯,但阻塞event循環的時候會有性能問題。爲了緩解,咱們在每臺機器上啓動多個Node實例,將對性能要求比較高的任務分配給專門的實例。同時咱們還深刻V8運行時環境查看更加細節的耗時,基本上是JSON去串行化的時候的對象具體化耗時較多。

  咱們還用Go語言作了一些輔助服務。由於Go很是容易編譯打包和發佈。相比Java語言的冗長羅嗦和虛擬機,Go語言在類型安全方面作的很到位。就我的習慣來說,我比較喜歡在團隊內部推廣強類型語言,由於這類語言可以提升項目的清晰度,不糾結。

  目前靜態元素大部分是經過CloudFlare提供的,還有5%經過Fastly,5%經過CloudFront,這麼作是爲了讓二者的緩存獲得更新,用於一些緊急的狀況。最近咱們在應用流量上也使用了CloudFlare,當時主要是爲了防止DDOS攻擊,但隨之而來的性能提高也是咱們願意看到的。

  咱們使用Nginx和HAProxy作反向代理和負載均衡,來知足咱們所需功能的維恩圖。

  咱們仍然使用Datadog來監控,Pagerduty來告警。如今又增長了ELK(ElasticsearchLogstashKibana)來進行產品問題調試。

  數據庫

  DynamoDB仍然是咱們的主力數據庫,可是用起來也不是毫無問題。目前遇到的比較棘手的是大V用戶展開和虛擬event過程當中的熱鍵問題。咱們專門在數據庫前面作了一個Redis緩存集羣,來緩解這些問題。到底爲開發者優化仍是爲產品穩定性優化的問題一般會引起爭執,咱們也一直在嘗試中和二者的矛盾。

  目前咱們開始在存儲新數據上使用Amazon Aurora,它能夠提供更靈活的查詢和過濾功能。

  咱們使用Neo4J存儲Medium網絡中實體之間的關係,運行在有兩個副本的主節點上。用戶、文章、標籤和收藏都屬於圖中的節點。邊則是在實體建立和用戶進行推薦高亮等動做時生成。咱們經過在圖中游走來過濾和推薦文章。

  數據平臺

  早期咱們對數據很是渴望,不斷嘗試數據分析框架來輔助商業和產品決策。最近咱們則是利用一樣的框架來反饋產品系統,支持Explore等數據驅動功能。

  咱們採用Amazon Redshift做爲數據倉庫,爲生產工具提供可變存儲和處理系統。咱們持續將諸如用戶和文章等核心數據從Dynamo導入Redshift,還將諸如文章被瀏覽被滾動等event日誌從S3導入Redshift。

  任務經過一個內部調度和監控工具Conduit調度。咱們用了一個基於斷言的調度模型,只有條件知足的時候,任務纔會執行。從產品角度來說,這是不可或缺的:數據製造方應該與數據消費方隔離,還要簡化配置,保持系統的可預見和可調試性。

  Redshift的SQL檢索目前運行不錯,但咱們時不時須要讀取和存儲數據,因此後期增長了Apache Spark做爲ETL,Spark具備很好的靈活性和擴展能力。隨着產品的推動,估計後面Spark會成爲咱們數據流水線的主要工具。

  咱們使用Protocol Buffers做爲schema來確保分佈式系統的各層次間保持同步,包括移動應用、web服務和數據倉庫等。經過定製化的選項,咱們將schema標記上更加細化的配置,如帶有表名和索引,以及長度等校驗約束。

  用戶也須要保持同步,這樣移動端和網頁端就能夠保持日誌的一致性了,同時方便產品科學家們用一樣的方式解析字段。咱們幫助項目成員從.proto文件中生成消息、字段和文檔等內容,進而利用所得數據開展研究。

  圖片服務器

  咱們的圖片服務器如今用Go語言實現,採用瀑布型策略來提供處理過的圖片。服務器使用groupcache,是memcahce的替代品,能夠幫助減輕服務器之間的重複工做。而內存級緩存則是用了一個S3的持續緩存。圖片的處理是請求來觸發的。這給了咱們的架構設計師靈活改變圖片展現的自由度,爲不一樣平臺優化,並且避免了大量的生成不一樣尺寸圖片的操做。

  目前Medium對圖片主要支持放縮和裁剪,但原始版本中還支持顏色清洗和銳化等操做。處理動圖很痛苦,具體後續能夠寫一篇文章來解釋。

  文本標註

  文本標註是個有意思的功能,用了一個小型Go服務器,跟PhantomJS接口造成渲染進程。

  我一直想要把渲染進程換到Pango,可是在實踐過程當中,能在HTML中擺放圖片的能力的確更靈活。而從功能的使用頻率來看,這意味着更容易開發和管控。

  自定義域名

  咱們容許用戶爲其Medium文章設置個性化域名。咱們想作成單點登陸且HTTPS全覆蓋,所以實現起來很有難度。咱們專門準備了一批HAProxy服務器用來管理證書,並向主要應用服務器引導流量。初始化一個域的時候須要一些手動的工做,可是經過與Namecheap的定製化整合,咱們將其大部分轉換爲自動化。證書驗證和發佈連接由專門服務負責。

  網站前端

  網頁端這塊,咱們有自主研發的單網頁應用框架,使用Closure標準庫。咱們使用Closure模板渲染客戶端和服務端,而後使用Closure編譯器來縮減代碼並劃分模塊。編輯器是咱們網頁端應用最複雜的部分,具體參見Nick此前的文章。

  iOS

  咱們的兩個應用都是原生的,儘可能避免使用網頁視圖。

  在iOS上,咱們使用了一系列的自建框架,以及系統原生組件。在網絡層,咱們用NSURLSession發起請求,用Mantle解析JSON並映射到模型。咱們還有一層基於NSKeyedArchiver的緩衝層。對於將條目渲染爲共同主題的列表,咱們有一個通用方法,這讓咱們可以快速爲不一樣類型的內容構建新列表。文章界面是一個定製佈局的UICollectionView。咱們使用共享組件來渲染全文界面和預覽界面。

  應用代碼的每一次提交都會編譯後推送給Medium員工,這樣咱們可以很快嘗試新版本。應用商店的版本是滯後於新版本的,但咱們也一直在嘗試更快的發佈,雖然可能僅僅是幾處小更新。

  對於測試,咱們使用XCTest和OCMock。

  Android

  在Android方面,咱們與當前的SDK和支持庫版本保持一致。咱們並無使用任何複雜的框架,而是傾向於爲重複出現的問題構建持續性的模式。咱們利用guava彌補Java中全部的缺失。另外一方面來說,咱們也傾向於使用第三方庫來解決特別的問題。咱們還利用protocol buffers定義了API,用以生成應用中的對象。

  咱們利用mockitorobolectric。咱們會開發一些高層測試來運轉activity和poke:剛添加screen或要重構的時候,先建立一些基本的版本,隨着咱們復現bug它們也會進化。咱們還會開發一些底層測試,來檢測一個特定的類:隨着新功能的增長咱們會建立測試,這可以幫助咱們思考和設計底層是如何交互的。

  每一個提交都會做爲alpha版本自動推送到play商店,而後到Medium員工(包括咱們的Hatch,Medium內部版)。推送大部分發生在週五,咱們會把alpha版本發送給測試小組,請他們用整個週末進行測試。而後,週一咱們會從beta版推動至正式產品版。由於最近一批代碼老是隨時能夠推送,所以一旦發現很嚴重的bug,咱們就能夠當即修復正式產品版。當咱們懷疑某些新功能的時候,能夠給測試小組更長的時間。開發比較亢奮的時候,也可能發佈地更加頻繁。

  AB測試及其餘

  咱們全部的客戶端都用了服務器端提供的功能標記,稱爲variants,用於AB測試以及指導未完成功能的開發。

  剩下還有一些框架相關的內容我沒有說起:Algolia讓咱們在搜索相關功能上快速迭代,SendGrid處理郵件,Urban Airship用來發送提醒,SQS用來處理隊列,Bloomd用做布隆過濾器,PubSubHubbubSuperfeedr用做提供RSS等等。

  編譯、測試和部署

  咱們積極擁抱持續集成技術,隨時隨地準備發佈,使用Jenkins來負責相關事宜。

  咱們曾經使用Make做爲編譯系統,可是後來遷移到Pants

  測試方面咱們採用單元測試和HTTP層面功能測試二者結合的方式。全部提交的代碼都須要經過測試纔可以合併。咱們跟Box團隊合做,利用Cluster Runner來分佈式運行測試,保證效率,並且可以和GitHub很好的整合在一塊兒。

  咱們大概不到15分鐘就能夠把某階段的系統部署,順利編譯經過,留做正式產品的備選。主應用服務器一般一天要部署五次,多的時候十次。

  咱們採用藍綠部署。正式產品版本的流量發送給一個canary實例,發佈進程會監控部署過程的錯誤率,必要時候經過調整內部DNS回滾。

  面向將來

  到此,講了足夠多的乾貨!爲了重構產品,得到更好的閱讀體驗,還有很長的路要走。咱們仍然在努力爲做者和發佈者設計更多的功能。打比方來說,線上閱讀仍是一片綠地,面對它有着無限可能,咱們始終抱着開放的心態設計和實現功能。將來咱們會努力用各類功能爲用戶提供高質量內容和價值。

相關文章
相關標籤/搜索