1. 程式人生 > >【Storm歷史篇】Storm是如何成為Apache頂級專案的

【Storm歷史篇】Storm是如何成為Apache頂級專案的

Apache Storm是一個免費、開源的分散式實時計算系統,不久前剛剛升級為Apache頂級專案。近日,該專案建立者Nathan Marz撰文回顧了Storm的發展歷史以及相關的經驗教訓。他認為,任何專案要想取得成功必須具備如下兩個條件:
1、解決了某一類需求;
2、專案建立者需要讓別人知道該專案是相關需求的最佳解決方案。

Nathan認為,許多開發人員並沒有認識到達成第二個條件與構建專案本身一樣困難和有趣。他希望,讀者在瞭解了Storm的歷史後能夠對這一點有一個清晰的認識。

建立Storm之前

Storm源於Nathan在分析平臺創業公司BackType的工作。在那裡,他們構建分析產品,幫助企業瞭解其在社交媒體上的影響,其中包括歷史資料分析和實時資料分析。在建立Storm之前,實時資料分析部分是使用一種標準的佇列和工作程序的方法。這種方法在構建應用程式時非常繁瑣。業務邏輯不得不處理訊息的傳送/接收、序列化/反序列化等問題,而實際的業務邏輯只佔程式碼庫的一小部分。

第一次思考
2010年12月,Nathan首先提出將“流(Stream)”作為一個分散式的抽象概念,然後又提出了“spouts”和“bolts”的想法,前者生成全新的流,而後者以流作為輸入,並生成流作為輸出。Bolts只需訂閱它們需要處理的流,並指明作為輸入的流應該如何劃分。最後,他提出了最上層的抽象概念“拓撲(Topology)”,它是一個由spouts和bolts組成的網路。
之後,Nathan在BackType的應用場景中對上述概念進行了測試,發現它們非常適合這些場景。傳送/接收訊息、序列化、釋出這些他們先前需要處理的繁瑣工作實現了自動化。
為了在更多的應用場景中驗證他的想法,在開始構建Storm之前,Nathan發了一條Tweet徵集應用場景。在進一步證實了這些概念的合理性之後,他開始構建Storm,但很快就遇到了麻煩,他沒能找到一種在spouts和bolts之間傳遞訊息的理想方法。最初,他想模擬先前的佇列和工作程序的方法,使用一個類似RabbitMQ的訊息代理傳遞中間訊息。為此,他花了很多時間研究RabbitMQ,但總覺得這一方案不夠理想,於是就暫停了構建過程。

第二次思考
Nathan最初認為需要訊息代理,是因為他覺得這可以為訊息處理提供保障。如果bolt處理訊息失敗,那它可以從獲取訊息的代理那裡重新開始處理過程。但使用中間訊息代理有諸多不妥之處:

  1. 它們隨著Storm擴充套件會非常複雜。
  2. 它們會導致一些難以處理的情況。比如,在拓撲重新部署後,代理上的中間訊息可能與新版本的拓撲不相容,那麼這些訊息就需要清理/忽略。
  3. 它們會使容錯更難實現。既要處理工作程序終止的情況,還要處理單個代理終止的情況。
  4. 它們會降低速度。
因此,Nathan希望在spouts和bolts之間直接傳遞訊息,同時又能為訊息處理提供保障。在經過數週的思考之後,他基於隨機數和XOR開發了一個演算法。該演算法只需20個位元組就可以跟蹤每個spout“元組(Tuple)”,而不管它在下游觸發了多少個處理過程。它不僅避免了上述問題,而且效能更好。

構建第一個版本


在接下來的五個月裡,Nathan用Clojure構建了Storm的第一個版本。為了將來開源,Storm的所有API都是用Java編寫的。這也可以確保Storm有大量的潛在使用者。
其次,為了使非JVM語言能夠使用Storm,Nathan將拓撲定義為Thrift資料結構。拓撲使用Thrift API進行提交。此外,Nathan還設計了一種協議,使spouts和bolts可以用任何語言實現。他認為,其它語言可以使用Storm使該專案可以為更多人所用,而且向Storm遷移的過程也會變得更簡單,因為他們不需要用Java重寫現有的實時處理程式碼。
Nathan是Hadoop的忠實使用者,他相信使用已有的Hadoop知識可以更好地設計Storm。比如,Hadoop會產生“殭屍程序”,這些程序會不斷的累積佔用資源,並最終摧毀叢集。產生這個問題的根本原因是,在Hadoop中,終止工作程序的任務由工作程序本身負責。但出於各種原因,它們可能會無法終止。所以,在Storm的設計中,工作程序由啟動工作程序的Storm守護程序負責。這使Storm更健壯,永遠不會產生殭屍程序。
他還指出了Hadoop的另一個問題。如果JobTracker因為某個原因死掉了,那麼任何正在執行的作業都將終止。Storm無法承受這種情況,因為拓撲需要永遠執行。因此,Nathan為Storm設計了“程序容錯能力”:Storm的守護程序被殺死並重啟不會影響正在執行的拓撲。
此外,在Storm開發之初,他就安排實習生Jason Jackson開發了一個在AWS上部署Storm的自動化工具。這極大地加快了迭代速度。

Twitter收購BackType
2011年5月,Twitter與BackType開始了收購談判。期間,Nathan在BackType的部落格上向外界介紹了Storm,希望以此提升Twitter對BackType的估值。Twitter對此很感興趣,他達到了目的。同時,他在博文中將Storm描述為“實時的Hadoop”,這吸引了很多人的注意。這張意外得來的名片非常有益於Storm的後續發展。

開源Storm
2011年7月,正式加入Twitter後,Nathan立即就開始計劃釋出Storm。釋出開源軟體有兩種方式。一種是大肆宣傳,並在釋出時儘可能地增加曝光。這種方式的風險在於,如果產品質量不高或者資訊傳達不準確,那麼就會在一天之內損失大批的潛在使用者。另一種是悄悄地釋出程式碼,讓軟體慢慢的為人們所接受。這種方法的缺陷在於,人們可能把它看成不重要的專案而忽視它。
Nathan選擇了第一種方式。他認為Storm是一款高質量的、有用的軟體。而且,基於其第一個專案Cascalog的開源經驗,他有信心傳達正確的資訊。開發佈會有如下好處:

  1. 有助於市場營銷和推廣;
  2. 可以集中地向潛在的早期使用者進行演講,而他們會立即發部落格/Tweet/電子郵件,極大地增加曝光;
  3. 可以在會議上大肆宣傳,構建人們的專案預期,並保證釋出當日能有大量的人關注專案。

因此,他選擇了這種方式,並開始了準備工作。首先,他準備在9月份的Strange Loop大會上以《Storm釋出》為主題做演講。在演講描述部分,他使用了Twitter的品牌。接著,他通過Twitter公佈了Storm的郵件列表,希望以此獲得社會認同。社會認同有多種形式,比如專案實際使用情況的文件、GitHub關注者、郵件列表活躍度、郵件列表訂閱人、Twitter粉絲、關於專案的博文等等。Nathan指出,如果他在釋出當天開啟郵件列表,那人們會看到它的活躍度為0,而且幾乎沒有人訂閱。提前公佈郵件列表非常有利。如果有人提問和訂閱,那他可以藉此構建社會認同;如果沒人提問和訂閱也沒關係,因為專案還沒釋出。
Nathan提到,他在這裡有一個失誤,就是沒有為專案開啟Twitter賬戶,因為微博是一個很好的保持專案曝光率的方法。
在會議開始之前這段時間裡,Nathan把大部分時間都用在了編寫Storm的文件上。他認為文件很重要,人們不瞭解它,就無法使用它。
一切都按計劃進行。2011年9月19日,專案釋出當天Storm便獲得了大量的關注,在GitHub上有1000多人關注了該專案。專案立即成為了Hacker News的頭條。演講結束後,他就在Hacker News、郵件列表和Twitter上線上回答問題。
釋出餘波
四天內,Storm就成了GitHub上檢視最多的Java、Scala或Clojure專案。不到兩週,spider.io就宣佈已經在生產環境中使用了Storm。
Storm釋出之後,Nathan開始收到使用者的反饋。為了使他們獲得儘可能好的使用體驗,他在第一個周裡就釋出了三個小版本。此外,他還在Storm裡增加了日誌資訊,以便使用者反饋時可以向他提供。之後,有一年多的時間,他每天都要花1到2個小時回答郵件列表裡的問題。
在這一年多的時間裡,Nathan在會議、聚會及企業中做了超過25場關於Storm的演講,使Storm獲得了越來越多的曝光。2012年1月,他做過一項調查。結果顯示,已經有10個使用者在生產環境中使用了Storm,有15個使用者即將使用,還有30家企業正在試驗。
Nathan為Storm建立了一個“客戶案例”頁面,以完成社會認同的最後一塊拼圖。該頁面不僅列出了使用Storm的企業,還簡單描述了他們的用法。這樣,人們就可以瞭解更多Storm的應用場景,從而可以進一步擴充套件其應用場景。

Storm的技術演進
在釋出後的一年半時間裡,Nathan及其團隊繼續開發Storm,以便它能在Twitter內部推廣。
大企業對技術的要求不同於創業公司。在創業公司,一個小型團隊負責開發、運維和釋出所有這些工作。而在大公司,這些工作由多個團隊完成。因此,Nathan意識到,他們需要建立一個大型的、共享的叢集,可以執行許多獨立的應用程式。該叢集既要確保應用程式可以得到足夠的資源,又要保證一個應用程式出現問題不會影響叢集中的其它應用程式。這就是“多租戶”。
在建成共享集群后,他們又發現了一個問題。使用者總是為他們的拓撲配置遠遠超出實際需要的資源。這降低了叢集效率,使用者也失去了優化拓撲的動力。Nathan通過開發“隔離排程器(isolation scheduler)”解決了這些問題。
隨著Twitter內部Storm使用者的增多,他們又發現,使用者需要用指標監控他們的拓撲。為此,他們開發了Storm的監控指標API,使使用者可以收集任意完全自定義的指標,然後把它們傳送給任意監控系統。
Storm的另一大技術躍進是Trident。它是Storm上的一個“微批處理(micro-batching)”API,提供了“僅執行一次”的處理語義。這使Storm可以應用到許多新的場景裡。
此外,在使用體驗和效能方面還有許多重要的改進。在第一年裡,他們平均一個月釋出一個版本。每個版本的釋出都會提升Storm的知名度。而且,這也從側面反映出,專案團隊能夠及時響應使用者的問題。

構建開發者社群
Nathan認為,構建社群並使開發人員為專案做貢獻是構建開源專案最難的部分。
在Storm釋出後的一年半時間裡,Nathan推動了Storm的所有開發,所有的變更都要經過他的認可。這樣做的好處是,他可以控制專案的每個細節,確保它的質量、使用體驗及發展方向。但是,“智者驅動(visionary-driven)” 的開發有一個很大的缺點,就是難以建立一個活躍的開發者社群。首先,Nathan控制著一切,其他人鮮有機會做出重大貢獻。其次,他本人成了專案的瓶頸。隨著“拉請求(pull request)”越來越多,他疲於處理,這延長了反饋/合併週期,打擊了貢獻者的積極性。
還有一個缺點是,使用者會把他看成是專案的單點故障點。這會限制Storm的發展。
最後,這種方式最糟糕的一方面是Nathan本人承擔了太多的工作。其他人無法深入瞭解整個程式碼庫,從而不可避免地會產生預想不到的變更結果。
離開Twitter
2013年3月,Nathan離開了Twitter。幾個月後,他認識到“共識驅動(consensus-driven)”的開發會更利於Storm的發展。
他認為,在專案的解決方案尚未明確之前,智者驅動的開發是最好的。因為一些關鍵的設計問題只有對整個專案有深入瞭解的人才能解決好。但到他離開Twitter的時候,Storm的解決方案已經比較明確了。此後的許多創新工作,如從ZeroMQ切換到Netty、實現安全/身份驗證、改進效能/擴充套件性、提高拓撲視覺化等,都是意料之中的。
在Nathan離開Twitter之前四個月,Yahoo!的Andy Feng就極力建議他將Storm提交給Apache。其時,他也恰巧在考慮這個問題。他與Hadoop建立者Doug Cutting進行了交談,從他那裡瞭解了Apache的運作,以及提交到Apache的優缺點。Doug的建議使他真正瞭解了共識驅動的工作機制。
在Storm最初切換到共識驅動模型時,大部分提交者對程式碼庫的整體把握都非常有限。這是前期智者驅動的結果。但模型切換後,隨著時間推移,部分提交者會學習程式碼庫的更多部分,從而在整體上有一個更深層的理解。
Nathan曾擔心,轉到共識驅動模型會降低軟體質量。實際上,也確實有些變更引入了Bug。但這不是大問題,下個版本可以修復這些問題。其實,智者驅動的開發也是如此。
提交給Apache
在離開Twitter後,Nathan的精力都用在了新的創業公司上。他需要為Storm選一個長遠的家。而之所以選擇Apache,是因為它能為Storm提供一個強大的品牌、堅實的法律基礎以及共識驅動的模型。
Storm使用ZeroMQ庫進行內部程序通訊,但ZeroMQ的許可協議與Apache基金會的政策不一致。因此,Yahoo!幾名開發人員(後來成為了Storm的提交者)基於Netty建立了替代方案。
在形成Storm最初的提交者列表時,Nathan選擇了一些已經為專案做過較大貢獻的公司裡的開發人員,其中包括其時尚在Health Market Science的Taylor Goetz。他現在就職於Hortonworks,專門從事Storm方面的工作,並擔任Storm專案管理委員會主席。
2014年9月,在Andy Feng的幫助下,Nathan向Apache提交了Storm孵化申請。
Apache孵化
Nathan寫道,Storm進入孵化狀態後,他不再是專案瓶頸,開發速度變得越來越快。提交/反饋週期的縮短,這對提交者來說也是一種激勵。同時,他會邀請做出重要貢獻的人加入提交者行列。
2014年9月17日,Storm正式畢業,升級為頂級專案,而此時離Storm開源尚不足三年。