像Apache Storm一樣簡單的分布式圖計算
摘要:本文從計算機領域的“祖師爺”艾倫·圖靈提出的圖靈機概念開始,介紹了圖形計算的概念,并以示例介紹了apache storm,基于apache storm如何進行分布式圖形計算。apache storm是一個免費開源的分布式實時計算系統,具有簡單易用、快速、可擴展、容錯等優點。
介紹
計算可能很復雜。對我們來說,這種復雜主要就是軟件世界的人類驅動力。甚至有一個學科整個都圍繞著問題解決和計算——計算機科學。
當一個人開始學習計算機科學時,會被介紹一些術語和概念,這些術語和概念都是圍繞著試圖以可證明,恰當的方式對問題的解決方案進行建模和表達而形成的。
艾倫·圖靈
艾倫·圖靈 天才地提出了 圖靈機 的概念。這些“機器”使我們能夠以數學證明的方式恰如其分地描述解決方案,同樣也適用于解決計算機科學領域遇到的問題。
圖片由 維基本科 提供。
從那時起,圍繞抽象計算機(包括圖靈機)的整個研究發展起來,名為 自動機理論的研究 。
自動機理論的領域是廣泛的,也是在不斷增長和最流行的 — 因為它可以生成能夠解決現實生活中問題的模型。
圖片由 維基本科 提供。
在一定程度上,自動機理論與 圖論 是密切相關的。
結合這兩種理論的優點,我們能夠設計出可證明的、分布式的、有效的解決問題的方案,否則這些問題將會太過于復雜,難以表達和解決。
在本文中,將介紹 Apache Storm (從現在開始使用術語“Storm” – 通常是指Apache的Storm版本。storm中的spout譯為“噴嘴”,bolt譯為“螺栓”),作為分布式圖形計算基礎架構的實現。
接下來就開始吧!
圖形計算作為降低系統復雜度的一種方式
在介紹了圖靈機、自動機理論和圖論之后,圖形計算可以作為一種降低系統復雜度的方式嗎?
答案是肯定的。
依靠一個經過測試和證明的模型,并不一定意味著 使用 這個模型和 證明 它一樣復雜。
例如下面的表達式:
1 + 1 = 2
大家都“知道”它是正確的,并且能夠使用它,因為已經有人 證明 它是正確的。
在本文的例子中,試圖將一個已知的問題轉化為一個圖形計算,其中每個 頂點 都是一個計算單元。根據連接它們的邊,在頂點之間“移動”。
接下來看下面的例子:
想要實現一個應用程序執行以下任務:
- 它接收一個訂單請求作為輸入。
- 如果訂單有效,就會向倉庫發送包裝和運輸請求,并通知客戶訂單成功。
- 如果訂單無效,則通知客戶。
把手頭的任務看作是一個圖形計算,可以將其描述如下:
以圖形的方式思考問題有一些好處。
首先,有了圖形以后,人類的思維更容易理解,不至于那么抽象了。
其次,鼓勵我們遵循良好務實的軟件設計原則,如 關注點分離 原則。每個頂點只做一件事。
再次,它使我們看到每個頂點所做的事,并將其外包給基礎架構。
例如,每個頂點接收并可能發送消息。以 容錯 的方式負責 外包 處理 傳入和傳出消息 是非常可取的。
部署也可以通過這種方式變得 更加靈活 — 例如,可以部署一臺單獨計算機的每個計算單元,并讓基礎架構去負責固有的消息傳遞和分發。
負載均衡和 可擴展性 如何?可以依靠“外部”消息傳遞系統來管理同一計算單元的多個實例嗎?答案是肯定的!
如果在訂單驗證過程中遇到瓶頸,是否可以實例化一個額外的驗證計算單元并讓它處理一些工作呢?可以的。
現在請記住,我們已經在圖中描述了應該如何處理每個輸入消息。還沒有描述過如何部署它。
所以 我們也分開 考慮了軟件的 正確性 和軟件的 部署 問題。
可能的情況是,除了將實例化兩個計算單元的驗證頂點之外,還為每個“邏輯”圖形頂點實例化一個物理計算單元,如下圖所示:
前面提到的關于關注點分離的提示,利用適當的基礎架構,可以處理進程間的通信,給出不同的部署需求(每個組織/個人),以容錯和可擴展的方式,旨在找準問題。
圖形計算確實是有用的,幫助我們考慮軟件解決方案,同時把軟件部署排除在外 —只要有適當的基礎架構,就可以做到這一點。
Apache Storm提供了以圖形方式編寫計算的能力,同時提供了一個固有的基礎架構,使我們能夠可靠高效地完成這些計算。
Apache Storm的方式
Apache Storm中,主要應用程序被稱為拓撲(topology),也就是Storm拓撲。
每個拓撲代表一個永遠在線的應用程序,它可以接收來自被稱為 噴嘴 (spout)的數據源的輸入。
噴嘴是輸入消息的來源,稱為 元組 。元組是動態類型的,它的成員可以是任何類型 —只要Storm“知道”如何序列化和反序列化這些類型。
元組正在按照拓撲的定義在 螺栓 ( bolt)之間傳遞。每個螺栓都可以傳遞元組到其它螺栓,只要它們連接到它。一個螺栓可以修改一個元組或者創建一個新的元組。它也可以按原樣傳遞傳入的元組,或者根本不傳遞任何東西。
元組通過噴嘴的元組流向被稱為 流 。多個流可以共存于一個拓撲中。每個數據流都與其它數據流并行處理。稍后將會再講到這一點。
Storm極具融合性,并與其它技術很好地集成。它能夠使用 Elasticsearch , Mongodb , Kafka , Redis , Kinesis 等基礎架構。如果需要自定義的東西,這也是可能的,Storm有一個很大的并在不斷發展的庫生態系統。
所以,如果想用一句話總結一下“Storm方式”的話,我會說:
Apache Storm是一種分布式技術,旨在允許開發人員利用圖形計算模型為問題同時提供“底層”(例如消息負載均衡)和“頂層“(例如準備使用Kafka Spout - 只需配置和使用來自Kafka的數據)的邏輯解決方案。
Apache Storm概述
為了更好地了解Storm如何工作,需要暫時縮小范圍。
本文不會對技術本身進行深入地研究。但是,如果想更好地了解該技術,包括部署的演示,與其它技術的集成和監控,請參閱我的課程, 在這里 。
從宏觀上看看Storm集群是如何建立的。這將有助于了解它是如何提供上述基礎架構的,比如計算圖形部分之間的可靠消息傳遞,以及某種程度的并行性,文章將在后面作進一步解釋。
首先,storm集群是由(不足為奇)…節點構建而成的。這些節點可以采用任何一個主節點的形式運行 Nimbus 守護進程或者采用 工作進程(worker)節點的形式 —運行 Supervisor 守護進程。它采用主從架構方式,主節點是Nimbus,從節點是Supervisor,有關調度相關的信息存儲在Zookeeper集群中。
主節點負責在工作節點之間分配工作。分配什么工作呢?實現圖形計算的實際代碼作為拓撲傳遞給Storm集群。
主節點和工作節點如何相互認知?通過 Zookeeper 。Zookeeper是一個分布式服務,作為一個可靠的配置和同步提供者。要了解更多關于Zookeeper的信息,包括安裝和集成演示,請看看 這里 。
所以說主節點負責將代碼分發給工作節點。但是,這里還有一個額外的抽象層: 工作進程 。
一個工作 進程 負責執行拓撲的一個子集。每個工作進程將實例化執行 任務 實例的執行器線程。這些任務可以是 噴嘴 或 螺栓 。
雖然理解起來可能相當困難,但是這種結構確實具有在各種物理機器,進程和線程之間分配邏輯計算圖形的能力,從而使storm集群在硬件故障的情況下 保持邏輯計算完整性 。
一個工作進程掛了?沒問題 —主節點會將其工作分配給另一個工作節點。
請注意,看起來主節點似乎是一個單點故障點。事實并不是這樣。即使主節點發生故障或崩潰,拓撲仍將繼續執行。顯然,我們將無法向集群提交新拓撲,因為主節點有責任在工作節點之間進行代碼共享,但是在線計算將繼續下去。
這種不希望發生的情況可以通過在Storm集群(又名Nimbus H / A)中定義多個主節點來彌補。這樣的話,一個失敗的主節點將會被一個健康的主節點替換。
現在應該能夠更好地理解Storm是如何將計算圖形和 物理 硬件層(主節點和工作節點,zookeeper,執行進程中的工作進程和任務)的 邏輯 概念完全分離開來的(拓撲結構是由噴嘴和螺栓與元組之間的流動建立起來的)。
這種架構是團隊之間關注點分離的推動者。可以將處理邏輯層的任務分配給開發人員,也可以將處理物理層的任務分配給DevOps工程師。
開發Storm的工程師考慮了上述關注點分離的概念,并向開發人員提供了在開發人員的機器上 本地運行拓撲 的思路。
談論開發人員—不如看一些代碼?
示例拓撲—讓我們看一些代碼
好吧,有些人可能以為在進行訂單驗證,包裝和裝運時,這個例子并不太適合演示圖形計算。
我不這么認為。圖形計算,就像任何其它模型一樣都是一個工具。作為開發人員,軟件架構師和/或研發副總裁,都需要決定這個工具是否適合手頭上的任務。我認為對于高吞吐量的電子商務網站,Storm實際上非常適合作為一個穩定的后臺。
接下來看看如何將上述用例作為一個Storm的拓撲實現。
首先,需要建立一個新的項目,就用一個Maven項目來展示。已經將以下依賴項添加到 pom.xml 文件中:
首先創建一個使用由Storm提供的 TopologyBuilder 的拓撲:
為了設置拓撲噴嘴,調用 TopologyBuilder 實例上的 setSpout 方法,傳遞一個噴嘴ID和一個噴嘴實例。
這是進入圖形計算的切入點。這也可能是一個 KafkaSpout 。
現在有信息進入系統,就想消化它。有時間在拓撲中添加一些螺栓。
把每一個螺栓連接到拓撲,將提供如下信息:
- 在拓撲中唯一標識它的螺栓ID。
- 它在拓撲中的前身,以及首選的分組方法。
- 一個可選的流ID。
2和3很快就會提到。
那么接下來看看帶有所有螺栓的拓撲:
每一次添加一個螺栓到拓撲,都調用 setBolt 。
然后,給螺栓命名,并為該螺栓提供一個實例。該實例是根據每個螺栓所需邏輯實現的類。接下來看一下這樣的螺栓。
每個螺栓,已經連接到另一個螺栓或噴嘴,并提供輸入。
在驗證螺栓的情況下,有兩種可能的結果(有效的或無效的),根據每個可能的結果,已經創建了一個只在特定流(驗證螺栓正在向其發送消息)上偵聽消息的螺栓。
現在來觀察一個螺栓的實現。為了符合Storm的架構,需要執行什么?
這里可以看到已經擴展了 BaseRichBolt 類。為了符合其定義,必須實現三種方法。
正如它名字暗示的那樣,這個 prepare 方法是一個占位符,一旦元組到達它,就可以執行螺栓所需的任何必要的初始化,以實現恰當的功能。在大多數情況下,至少會將輸出收集器引用保存到局部變量中。輸出收集器允許發出新的元組到下面的螺栓。
它也允許 確認 一個元組。Storm會將任何未確認的元組視為一個未處理的數據結構,以便重新處理。
execute 方法在每個元組傳遞時(由Storm基礎結構)調用一次。在execute方法中將使用元組,在需要的情況下發出任何新的元組,最后,確認傳入的元組。
當想要傳遞一個特定的字段到下一個螺栓時, declareOutputFields 方法是必需的。例如, PackageGenerationBolt 傳遞以一個字段名為“ShipmentRequest”的裝運請求到下一個螺栓(ShipmentRequestBolt)時,要知道如何引用:
最后,將拓撲提交到集群并運行它。在這個例子中,提交給一個專門為調試而開發的本地集群:
一旦拓撲經過測試和調試,就可以安全地將其部署到 “真實”的Storm集群。
這可以通過幾種方式來完成。
一般來說,需要將拓撲連同所有相關的依賴項打包到jar文件中,并將其傳遞給Storm集群。通過使用命令行來完成更簡單。
如果想看到一個“真實的”的demo,請查看 這里 。
如何進行分布式計算?
太神奇了!現在明白了,把許多計算分解成圖形的邏輯和物理形式并不是很難,因為頂點以“標準”形式(序列化元組)進行通信。
現在也知道代碼是如何在Storm集群上執行的。
在將拓撲提交給集群后,打包成一個jar文件,拓撲組件(即spouts和bolt)被部署到各個storm工作節點(由主節點決定),并在工作節點中實例化——封裝在任務線程中,存在執行過程中。
Storm基礎架構知道拓撲內流動的數據流。這個基礎架構還通過螺栓跟蹤元組確認,為我們提供了可靠的消息傳遞系統。
內在的并行性:作為并行度的流
圖形計算的好處之一是,可以在應用程序中清晰地顯示單獨的計算路徑。
看看這里:
有什么東西阻止并行處理兩種不同的數據流嗎?當然沒有,這是Storm的完美任務!
流是 Storm中的 一種并行的程度 。所有的流元組都將流經相關的螺栓(如拓撲所描述的那樣),而不知道拓撲中的其它流。
螺栓(bolt)的實例
這是一個好的開始,是不是?不同的流可以分別單獨處理。然而,還有另外一種并行度—在 任務層面 的并行度。作為一個優秀的學生,應該記住任務可以是噴嘴或螺栓的形式。
定義拓撲時,可以聲明每個噴嘴或螺栓所需的并行度。
請注意,不希望任務沒有控制的按需產生!太多的任務(即線程)會引入過度并行,并可能導致集群“慢下來”,最終讓應用程序變得無法響應。
在使用Storm的并行度功能之前,請考慮 想達到的并行度 , 并提供可用的資源 。
假設有3個Storm工作進程節點,并且部署了一個具有一個并行度設置為2的單個噴嘴的拓撲,以及5個并行度設置為2的螺栓 — storm將為噴嘴生成2個任務,每個螺栓生成5 * 2 = 10 個任務。
這意味著將有12個任務,storm集群將試圖均勻地分布在3個工作節點上(下圖沒有畫出所有的線以避免混亂)。
作為內部“秩序者”的分組
還是回到 分組 的概念。
之前已經看到,當創建一個螺栓時,已經指定了它的“輸入”螺栓:
但是這樣做的方式還不清楚,正如我們所說的那樣,需要一個“隨機分組”
奇怪,不是嗎?分組與之前建立的圖形拓撲有什么關系?難道不是所有的流元組都只是從一個螺栓流到另一個螺栓嗎?
那么請記住,噴嘴和螺栓可以有多個實例,以便進行分布式并行計算。
雖然 噴嘴 或 螺栓 在邏輯上是一個原子計算單元,但它的物理實現并不一定。
分組是定義兩個不同拓撲元素之間的元組流的方式。它將定義輸入實體和目標實體的實例(任務)之間的元組是如何流動的。
例如,“shuffleGrouping”將隨機發送元組到螺栓實例。
提醒一下,在討論分組時,討論的是兩個實體之間的數據流,并且只有兩個實體。
在這里,可以看到每個元組是如何隨機地轉移到一個螺栓實例(任務),從PackageGenerationBolt到ShipmentRequestBolt。
一個最有趣的分組選項是“字段”分組,在這個分組中指定要將元組分組的特定字段。例如,分組 ShipmentRequestBolt 到基于字段“WarehouseId”的 PackageGenerationRequest 。由于這種“字段”的分組策略,所有帶有相同 WarehouseId 值的元組,在輸入元組時始終被定向到相同的 ShipmentRequestBolt 任務實例。
還有其它有趣的分組方法可以在 這里查看 。
結論
感謝大家與我一起度過這段短暫的旅程,總體地回顧了圖形計算的概念和Apache Storm更具體的細節。在寫這篇文章的時候,我一直牢記“保持簡單”,假設一旦“理解了”這個想法并理解了這個工具,將能夠決定你是否需要對Storm進行更深入的研究。這也是我提到額外的閱讀和我的Pluralsight課程的原因。
我們從理解圖形計算是什么以及它起源于何處開始了這一旅程。特別是理解了它在計算機科學領域是多么深奧的概念。
一旦確信(希望),我們已經開始討論支持基礎架構的好處,以便可靠地將應用程序作為圖形計算實現。
我們介紹了Apache Storm這樣一種技術。
storm在邏輯層、拓撲層和物理層——物理集群本身進行了回顧。
理解了拓撲如何在整個集群中傳播,并在物理層的最終抽象層(任務)中執行。
然后討論了Storm如何提供并行度— 無論是在流級別和還是在特定任務級別(噴嘴或螺栓)。
看一些代碼,我試圖傳遞使用storm的簡單和美麗。
希望已經成功地吸引了你。
來自:http://www.iteye.com/news/32830