這篇文章主要描述的是Prismatic公司系統架構,作者是Todd Hoff,本文出自Todd對Prismatic的程式設計師Jason Wolfe的郵件專訪。

關於Prismatic,首先有幾個事情要說明下。他們的創業隊伍很小,僅僅由4個電腦科學家構成,其中的三個都是年輕有為的史丹佛以及伯克利博士。他們是在用智慧解決資訊超載這個問題,然而這些博士也同時擔任著程式設計師的角色:開發網站、iOS程式、大資料以及機器學習需要的後臺程式。Prismatic系統架構的亮點是如和使用機器學習實時地解決社交媒體流的處理問題。由於商業機密的原因,他沒有透露他們的機器學習技術,但是我們可以通過架構看個大概。Prismatic創始人之一Bradford Cross把Prismatic的系統簡潔地描述為:“它是一個提供大規模、實時以及動態的個性化資訊排名、分類以及分組功能的綜合系統。”接下來就把這個系統的架構展現給大家。

Prismatic主要功能是發現我們的興趣,為我們推薦閱讀

今天你應該讀點什麼呢?任何一個現代人每天都會陷入這個困境,大家通常使用一些很隱祕的途徑去找到自己想要讀的東西:Twitter、RSS、Facebook、Pinterest、G+、email以及Techmeme等這些資訊源。Prismatic回答了“今天我應該讀什麼?”的問題,Jason Wolfe慷慨的同意並且詳細地描述下他們正在使用的解決方案,言語中包含了許多時髦的技術名詞,例如機器學習,社交圖譜,大資料,過程化程式設計以及事實需求等等。然而結果是他們的方法更隱祕,但和其他一些相似應用不一樣的地方在於他們會發掘你的興趣,無論這些興趣在你的資訊中藏得有多深。

正如大家預料的,他們的做法有點特別。他們選了Clojure做為開發語言,它是一個編譯成Java bytecode的現代Lisp語言。主要目的是充分利用過程化語言去構建具有豐富粒度,結構自由的程式,從而滿足各種問題帶來的特殊需求。列舉兩個他們用到的過程化語言的優點的例子:第一個是他們幾乎每個地方都使用相簿。對於每個使用者來說,他們的圖形計算可以被稱為低延遲,流程化的map-reduce任務集;另外一個例子是他們使用子圖實現了模組化的服務配置。

他們把系統設計的焦點放在過程化開發上來,避免了使用像Hadoop那樣的巨型框架,轉去使用小型的,這使得系統更可靠,更容易糾錯,更容易擴充套件以及更容易理解。Prismatic的機器學習做法的難點在於要求一個非常長的訓練週期。需要指出的是:首先,獲得優質分析源內容並不需要多少時間;其次,使用基於機器學習的推薦系統需要對使用者從幼兒到現在的一生的所有資料進行訓練;這個可擴充套件的思維數字模擬系統扮演著資訊的收集者以及生產者雙重的角色。

圖:越來越多的應用開始關注使用者的閱讀推薦

統計資料

  • 現在每天有幾千萬篇文章、部落格以及其他一些內容通過Twitter,Facebook,Google Reader以及網際網路釋出。
  • 但是僅僅需要使用者登入時的那幾秒鐘,Prismatic就能夠使用他們之前的閱讀歷史進而去分析使用者的興趣,然後推薦閱讀,使用使用者在社交網路上的活動,從而將聯絡人發表的、符合使用者胃口的文章推薦過來。同時,Prismatic也會記錄使用者在它本身上的動作,也將它做為分析的一個來源。
  • Prismatic只需要數十秒鐘去訪問使用者的個人主頁,通過和使用者興趣模型對比,便可以分析出使用者最感興趣的東西。
  • 現在每週有數百萬的優秀文章通過Prismatic成功分享給使用者。

平臺

  • Prismatic的主機託管在AWS的EC2上,使用Linux作業系統。
  • Prismatic99.9%的後臺通道和API服務都用Clojure開發。
  • Prismatic所有的重量級框架部署在JVM中。
  • Prismatic使用MongoDB儲存伺服器引數和使用者分析資料。
  • Prismatic使用了MySQL。
  • Prismatic使用了S3。
  • Prismatic使用了Dynamo。
  • Prismatic將重點放在開發能解決特殊問題產生的需求的程式碼上。

資料儲存和輸入輸出

  • 和典型的結構不同,Prismatic的服務都圍繞著資料而設計,可以提供實時讀寫資料的能力。
  • 大部分資料都直接在後端管道之間傳輸,不會和磁碟發生I/O。
  • Prismatic把資料保持在離CPU儘可能近的地方,這樣就讓API的請求幾乎沒有IO延遲,同時把API繫結到CPU上,巧妙的擴充套件了系統的規模。
  • Prismatic使用了許多現成的解決方案:MongoDB,MySQL以及Amazon的S3和Dynamo。每個都是經過對實際需求仔細研究的,包括規模,接入模式和資料儲存相關的其他特性。

服務

從外部來看,Prismatic的系統被分成了10個獨立的服務模組,大致可以歸總為5種型別:資料採集;新使用者管理;API;其他客戶機服務;批處理。每個服務都是為一個功能而設計,通過一種特殊的方式進行橫向擴充套件,通常受1到2個特殊資源限制(IO,CPU,RAM)。

  • 資料採集——後臺

每天都會有大量內容(包括文章,部落格和網頁等)產生,Prismatic想要儘可能多的捕捉到他們。為了讓使用者可以評論每個內容,並和自己興趣相投的朋友進行分享,Prismatic必須識別每個內容的作者,分享者以及一些比較有價值的評論。做這些的第一步就是收集和分析內容和關係資料

首先在採集通道入口執行下面這些步驟:通過喜好在RSS上找到新文章;通過API將使用者Twitter和Facebook上的最新評論和動態收集上來。執行這些功能的服務非常簡單,而且沒有狀態資訊,唯一的狀態和有意思的地方是如何確定哪些資訊是已經收集過的了和怎樣智慧的分析接下來該收集哪個資訊。其中最難的就是前者,因為有些人他可能在多個地方發過同一個資訊。

接著,把RSS、Twitter以及Facebook等資訊源收集上來的資料送入到一個過濾器中,讓它決定哪些需要進入通道進行分析。首先把垃圾郵件和其他垃圾資訊丟掉,URL將被送到管道中去,此時會有很多有趣的事情發生,Prismatic會建立一個URL佇列,將每個佇列送入一個圖運算中,使用它將URL進行詳細描述,抓取它的HTML程式碼,使用機器學習的演算法把文章的內容抓取出來,識別最好的圖片,抓取出作者,標籤以及話題等等。為了讓這些過程儘可能快速進行,能夠裝入記憶體以及提高表現力,他們投入了很大一部分時間,當然,處理這些URL的方式是高度併發的。

最後是文件控制器,它的作用是接收上面處理好的詳細的文章和社交內容,將他們進行匹配,把文章集整理成故事系列,決定把哪些設為當前要處理的文件,並且管理這些API相關的機器目錄。

  • 新使用者管理——後臺

新使用者管理模組主要負責收集新註冊的使用者的資訊。它主要由兩個部分構成:通過使用者的Twitter,Facebook以及GoogleReader找出他喜歡的主題以及喜歡的文章來源;分析他的社交圖譜,找出他最喜歡哪些朋友分享的文章。

執行這些功能的服務也是高度並行的。社交圖譜分析非常複雜,關鍵是這些服務如何能夠實現如此低的延遲以及如此可靠的吞吐量:對於Twitter,Facebook和Google Reader的活躍使用者來說,準確找出數百個使用者喜歡的話題對於Prismatic來說只需要15秒,甚至更少。使用者授權以後,Prismatic就可以非常快地分析出使用者的興趣,使用者常常在註冊的時候(填寫密碼和點選確認的過程中)這個工作就已經完成了。看看在這15秒內,發生了什麼:Prismatic把使用者最近在Twitter和Facebook上發表的內容以及Google Reader中標記為喜歡的東西都抓取進來,這一般是10秒鐘左右;然後把使用者和他的聯絡人等共享的1000個URL收集上來;再將這些資料送入上面提到的文件控制器,使用相同機器學習堆疊進行採集/分析的通道;這些分析結果經過聚合,後期處理,最終都儲存到DynamoDB和S3裡去。

這個過程對延遲的要求非常嚴格,所以這些程式不能序列,必須併發執行,所以他們不得不盡可能多地使用通道和並行處理的技術。這個過程對吞吐能力要求和很高,因為每個程式並不小,同時一旦有許多使用者同時來註冊,要想降低延遲你就必須做更多的事情。這裡也是Prismatic的獨到之處,他們的流處理和聚合類都將重量級降了下來,把效能做到了極致,達到了每個使用者使用一個低延遲map-reduce任務的效果。對於多個使用者的情況,他們系統使用的併發處理幾乎發揮了機器的全部效能。

API——面向客戶機

資料採集和新使用者管理都部署在API機器上。系統主要的設計目標和挑戰是:最近的文章必須被編入索引並且可以滿足低延遲的需求,索引並不算小(常常是許多GB),而且必須實時更新,只有這樣才能把最近更新的文章傳遞給使用者,這些需要為使用者設計跨機器的負載均衡,同時要求必須能快速簡單地將任務劃分到新機器(當然還有關閉合並);如果要想找到使用者的真正需求,僅僅使用索引是不夠的,同時還需要使用者的“指紋”(他們的愛好,社交關係,最近讀過的文章等),這些指紋資料非常大而且在不斷髮生變化。

對於前幾個問題需要用到文件控制器(上面提到了)。文件控制器組織當前的文件集,對他們進行預處理,每隔幾分鐘就把剛剛做好的的索引集儲存S3中去。當一個新的API機器啟動時,文件控制器首先讀取這些檔案,將他們放入記憶體,再將最新的索引副本傳遞給它。文件控制器也負責將所有索引的改動(新增文件/新增評論/刪除等)實時地傳遞給所有正在執行的API機器上去。其他一些API機器常用的功能也由文件控制器從S3中讀入記憶體,週期性的更新到S3,如果資料超過了S3的儲存大小限制,就將它存入DynamoDB。

剩下的問題就是如何在保證延遲需求前提下,提取和更新每個請求裡的使用者“指紋”。Prismatic這裡使用的方法是使用粘性會話(Session),把使用者繫結到一臺API機器上。當使用者第一次登入的時候,就把他的資訊存入一個具有有效期的回寫式快取中。在使用者會話的生命期週期內,把其中的資料放入記憶體進行興趣分析。在這個過程中使用者進行的所有操作都會通過同一個API機器進行處理,對於那很小的一部分不關鍵的使用者指紋,每隔幾分鐘,會話到期或者關閉時再分批進行更新。更多的關鍵指紋直接進行同步或者至少使用一個直寫式快取進行更新。

其他的服務——面向客戶機

  • 公共興趣功能,主要是為沒有登入的使用者服務,通過常規的API收集他們的需求,按照年齡分割槽,將不同的需求放在不同的頁面上。
  • 使用者功能,管理建立賬戶,登入等功能。通常就部署在SQL資料庫上,儲存使用者的主要資料,但這些常常需要週期性地拍下快照並且進行備份。
  • URL簡化服務
  • 批處理以及其他服務
  • 另外還有一些其他的服務,用於機器語言訓練,資料歸檔和事件追蹤和分析。

相簿

這是一個宣告性的描述圖形計算的好方法,充分發揮了Clojure的優點。一個圖就是一個Clojure示意圖,在裡面定義鍵值對,鍵裡儲存的是關鍵詞,值裡存的是使用示意圖中其他方法對關鍵詞計算後得到的功能,這樣就達到了外部引數的效果。

這個方法幾乎在所有的地方得到了應用。例如文件分析通道就是一個圖,其中每個檔案中的核心內容都依賴於它(舉個例子,如果要定義某個文件的主題,前提是先要提取它的文字內容);訂閱生成程式就是一個由查詢和排名兩個步驟組成的圖;每個訂閱生成服務本身就是一個圖,其中的每個資源(如資料儲存,記憶體,HTTP控制器等)就是這個圖一個節點,他們互相依賴。這樣就為下面這些工作提供了方便:

模組化對服務配置進行簡潔描述(例如使用子圖);使用進行和服務之間的相互依賴關係繪製出圖表;測量每個節點在進行像文件分析,或者在每個複雜服務(例如API)的資源上進行的活動等複雜運算時,所需要的計算時間和發生的錯誤;智慧為每個計算的不同執行緒規劃節點(在理論層面甚至到機器層面);通過用模擬的方式替換掉圖中的一些節點,從而可以對全部生產服務進行簡單的測試。

Prismatic把機器學習的技術用於了文件和使用者這兩個領域。

機器學習用於文件

對於HTML文件的處理:提取出頁面中的核心文字(而不是它的側欄,頁尾,評論等),標題,作者,有用的圖片等;確定文件相關的一些特點(例如文章是關於什的,主題等)。這些任務的模式很典型。模型通過其他機器大型批任務進行訓練,首先將資料從S3讀入,然後再把學到的引數檔案儲存S3上,之後在內容提取通道中將S3中的模型讀入(同時也要定期重新整理)。所有從系統輸出的資料也會反饋給通道,這樣就對了解使用者的興趣更有幫助,做到了隨時從錯誤中學習。

Prismatic研發的框架“flop”庫是軟體工程師最感興趣的,它實現了最先進的機器學習訓練和推理程式碼,它和普通的漂亮的Clojure程式碼非常相似,但確編譯(使用神奇的巨集)成低階的陣列執行迴圈,這使得它和Java中的metal非常相似,不用藉助於JNI便可以使用這個框架。

這個程式碼框架比一個重量級的Java更簡潔,更容易讀懂,同時和Java的執行速度基本持平。Prismatic將大部分的功夫都花在建立一個能快速執行的故事機器元件上了。

機器學習用於使用者

使用社交網路資料推測使用者都有哪些興趣並且使用應用中的明顯標誌(使用者增加一些或者刪除一些文章)去優化這些推測。

使用這些明顯標誌的問題很有意思,因為使用者的輸入必須要非常快速的在他們的訂閱中反饋。如果一個使用者將一個推薦的出版物中5個文章都刪除了,接著馬上就不要再把這個出版物中的其他文章給使用者繼續展示了,第二天也不要。這意味著沒有時間為所有的使用者執行另一個批處理任務,解決的辦法就是線上進行學習:當使用者提交了那些明顯的標誌時,立刻對使用者的模型進行更新。

使用者和應用互動時產生的原始資料流要儲存下來。這樣就可以稍後重新執行對使用者興趣進行機器學習所需要的原始流資料,同時還能避免由於脆弱的快取在上傳這些資料的過程中出現錯誤,從而導致這些資料丟失。引入線上學習可以糾正並且更加準確地對模型進行計算。

學到的東西

  1. 找到你的定位。仔細考慮下整個通道和流過它的所有資料。在眾多的挑戰上多做些工作,針對每個問題提出特定的解決方案。每個服務都有它自己的規模,同時服務間使用一個非常容易擴充套件的方式進行的通訊,這種方式還不能給其他的服務帶來太大的壓力。Prismatic沒有使用Hadoop構建系統,所有的資料都以原始資料的形式存在分散式資料庫和檔案系統中。
  2. 發現並充分利用高度並行的機會。
  3. 當使用者在等待時進行並行運算。新使用者註冊過程,例如新使用者上傳通道要在使用者等待時併發工作,這樣就可以實現在幾秒內就完成註冊。
  4. 使用過程化語言開發豐富粒度的,自由抽象的程式。這些抽象層次可以用於構成特殊問題的邏輯層。
  5. 避免重量級,大規模的框架,例如Hadoop。這樣產生的是較小的程式碼庫,相同條件下,更不容易出錯,更容易理解並且更容易進行擴充套件。構建自己的程式碼庫的理由很簡單,因為大部分開源的功能都被鎖入了重量級的框架中,很難進行程式碼複用,擴充套件和問題出現時很難進行除錯。
  6. 找到合適的人開發對系統很重要。目前Prismatic後臺服務開發團隊是由3個電腦科學博士組成,他們負責所有的開發工作,包括從機器學習的演算法研究到低層次的web和iPhone客戶端系統工程的所有程式碼。
  7. 將所有的程式碼儘早投入生產,儘管投資早期經常在構建和除錯工具,但這使建立和除錯產品服務變得簡單和有趣。
  8. 保持簡單。不要花太多精力在複雜的程式碼庫或者框架上,使用簡單的東西,當有一個更簡單的解決方案足夠好時就不要再幻想了。例如使用簡單的機遇HTTP的通訊協議,而不要再去考慮什麼流行的框架了。如果能夠工作,要很樂意去買一些現成的管理解決方案,例如S3或者Dynamo。
  9. 多在構建強大的開發工具和類庫上下些功夫。例如,Prismatic的“flop”庫,它允許他們寫出和Java處理速度一樣快,程式碼量只有十分之一的數字運算機器學習演算法;“Store”抽象了許多不重要的鍵值儲存細節,允許在各種環境下高度的對快取,批處理和傳遞流資料進行抽象;“graph”使的寫資料,測試和管理分散式流程式服務變得簡易可行。
  10. 對每一種資料型別要慎重考慮,不要期望能找到一個I/O和儲存的通用解決方案。(@康文博編譯)

最後分享下使用的感受:

我(譯者)登入到Prismatic首頁的時候,簡單大方的風格在我使用之前就感受到了技術氣息十足(這時系統會推薦大眾興趣)。當我點選註冊的時候,介面提示可以用Facebook賬號登入,輸入了使用者名稱和密碼的時候(這時他已經把我Facebook,Twitter和Google Reader裡的資料進行了分析),之後展現給我的是一篇一篇雲端計算和大資料的文章,當然也包含一些移動新聞等(果然實時的250ms不是吹噓的)。

這讓我想到了國內的應用,第一個是有道閱讀,用過的朋友都應該知道,它其實只提供了Prismatic未註冊使用者效果,即推薦了很多的大眾熱點興趣,然後要求使用者在裡面勾選。第二個我想到了的是網易郵箱,當你訂閱的關鍵詞比較準確時,他推薦的文章也大都比較符合使用者的口味。然而可惜的是Prismatic目前只支援Facebook,Twitter和Google Reader等國外的社交工具,內容抓取的範圍也僅是國外的知名出版物,所以我很期待國內能夠出現與之媲美的應用,將微博,QQ,人人等國內社交工具整合進來,將閱讀推薦做到每個人都不一樣,每篇文章都符合使用者的口味。