storm 學(xué)習(xí)(一)介紹

一、Storm是什么

Storm是一個(gè)免費(fèi)并開源的分布式實(shí)時(shí)計(jì)算系統(tǒng)。利用Storm可以很容易做到可靠地處理無限的數(shù)據(jù)流,像Hadoop批量處理大數(shù)據(jù)一樣,Storm可以實(shí)時(shí)處理數(shù)據(jù)。Storm簡單,可以使用任何編程語言。
  在Storm之前,進(jìn)行實(shí)時(shí)處理是非常痛苦的事情: 需要維護(hù)一堆消息隊(duì)列和消費(fèi)者,他們構(gòu)成了非常復(fù)雜的圖結(jié)構(gòu)。消費(fèi)者進(jìn)程從隊(duì)列里取消息,處理完成后,去更新數(shù)據(jù)庫,或者給其他隊(duì)列發(fā)新消息。
  這樣進(jìn)行實(shí)時(shí)處理是非常痛苦的。我們主要的時(shí)間都花在關(guān)注往哪里發(fā)消息,從哪里接收消息,消息如何序列化,真正的業(yè)務(wù)邏輯只占了源代碼的一小部分。一個(gè)應(yīng)用程序的邏輯運(yùn)行在很多worker上,但這些worker需要各自單獨(dú)部署,還需要部署消息隊(duì)列。最大問題是系統(tǒng)很脆弱,而且不是容錯(cuò)的:需要自己保證消息隊(duì)列和worker進(jìn)程工作正常。
  Storm完整地解決了這些問題。它是為分布式場景而生的,抽象了消息傳遞,會(huì)自動(dòng)地在集群機(jī)器上并發(fā)地處理流式計(jì)算,讓你專注于實(shí)時(shí)處理的業(yè)務(wù)邏輯。

二、Storm的特點(diǎn)

Storm有如下特點(diǎn):

  1. 編程簡單:開發(fā)人員只需要關(guān)注應(yīng)用邏輯,而且跟Hadoop類似,Storm提供的編程原語也很簡單
  2. 高性能,低延遲:可以應(yīng)用于廣告搜索引擎這種要求對(duì)廣告主的操作進(jìn)行實(shí)時(shí)響應(yīng)的場景。
  3. 分布式:可以輕松應(yīng)對(duì)數(shù)據(jù)量大,單機(jī)搞不定的場景
  4. 可擴(kuò)展: 隨著業(yè)務(wù)發(fā)展,數(shù)據(jù)量和計(jì)算量越來越大,系統(tǒng)可水平擴(kuò)展
  5. 容錯(cuò):單個(gè)節(jié)點(diǎn)掛了不影響應(yīng)用
  6. 消息不丟失:保證消息處理
    不過Storm不是一個(gè)完整的解決方案。使用Storm時(shí)你需要關(guān)注以下幾點(diǎn):
  7. 如果使用的是自己的消息隊(duì)列,需要加入消息隊(duì)列做數(shù)據(jù)的來源和產(chǎn)出的代碼
  8. 需要考慮如何做故障處理:如何記錄消息隊(duì)列處理的進(jìn)度,應(yīng)對(duì)Storm重啟,掛掉的場景
  9. 需要考慮如何做消息的回退:如果某些消息處理一直失敗怎么辦?

三、Storm的應(yīng)用

跟Hadoop不一樣,Storm是沒有包括任何存儲(chǔ)概念的計(jì)算系統(tǒng)。這就讓Storm可以用在多種不同的場景下:非傳統(tǒng)場景下數(shù)據(jù)動(dòng)態(tài)到達(dá)或者數(shù)據(jù)存儲(chǔ)在數(shù)據(jù)庫這樣的存儲(chǔ)系統(tǒng)里(或數(shù)據(jù)是被實(shí)時(shí)操控其他設(shè)備的控制器(如交易系統(tǒng))所消費(fèi))
  Storm有很多應(yīng)用:實(shí)時(shí)分析,在線機(jī)器學(xué)習(xí)(online machine learning),連續(xù)計(jì)算(continuous computation),分布式遠(yuǎn)程過程調(diào)用(RPC)、ETL等。Storm處理速度很快:每個(gè)節(jié)點(diǎn)每秒鐘可以處理超過百萬的數(shù)據(jù)組。它是可擴(kuò)展(scalable),容錯(cuò)(fault-tolerant),保證你的數(shù)據(jù)會(huì)被處理,并且很容易搭建和操作。

例如Nathan Marz提供的例子,產(chǎn)生Twitter的趨勢(shì)信息。Twitter從海量推文中抽取趨勢(shì)信息,并在本地區(qū)域和國家層級(jí)進(jìn)行維護(hù)。這意味者一旦一個(gè)案例開始出現(xiàn),Twitter的話題趨勢(shì)算法就能實(shí)時(shí)的鑒別出這個(gè)話題。這個(gè)實(shí)時(shí)的算法就是通過在Storm上連續(xù)分析Twitter數(shù)據(jù)來實(shí)現(xiàn)的。

三、Storm模型

Storm實(shí)現(xiàn)了一個(gè)數(shù)據(jù)流(data flow)的模型,在這個(gè)模型中數(shù)據(jù)持續(xù)不斷地流經(jīng)一個(gè)由很多轉(zhuǎn)換實(shí)體構(gòu)成的網(wǎng)絡(luò)。一個(gè)數(shù)據(jù)流的抽象叫做流(stream),流是無限的元組(Tuple)序列。元組就像一個(gè)可以表示標(biāo)準(zhǔn)數(shù)據(jù)類型(例如int,float和byte數(shù)組)和用戶自定義類型(需要額外序列化代碼的)的數(shù)據(jù)結(jié)構(gòu)。每個(gè)流由一個(gè)唯一的ID來標(biāo)示的,這個(gè)ID可以用來構(gòu)建拓?fù)渲懈鱾€(gè)組件的數(shù)據(jù)源。
  如下圖所示,其中的水龍頭代表了數(shù)據(jù)流的來源,一旦水龍頭打開,數(shù)據(jù)就會(huì)源源不斷地流經(jīng)Bolt而被處理。圖中有三個(gè)流,用不同的顏色來表示,每個(gè)數(shù)據(jù)流中流動(dòng)的是元組(Tuple),它承載了具體的數(shù)據(jù)。元組通過流經(jīng)不同的轉(zhuǎn)換實(shí)體而被處理。
  Storm對(duì)數(shù)據(jù)輸入的來源和輸出數(shù)據(jù)的去向沒有做任何限制。像Hadoop,是需要把數(shù)據(jù)放到自己的文件系統(tǒng)HDFS里的。在Storm里,可以使用任意來源的數(shù)據(jù)輸入和任意的數(shù)據(jù)輸出,只要你實(shí)現(xiàn)對(duì)應(yīng)的代碼來獲取/寫入這些數(shù)據(jù)就可以。典型場景下,輸入/輸出數(shù)據(jù)來是基于類似Kafka或者ActiveMQ這樣的消息隊(duì)列,但是數(shù)據(jù)庫,文件系統(tǒng)或者web服務(wù)也都是可以的。


Paste_Image.png

四、概念

1. 拓?fù)?Topologies)

一個(gè)Storm拓?fù)浯虬艘粋€(gè)實(shí)時(shí)處理程序的邏輯。一個(gè)Storm拓?fù)涓粋€(gè)MapReduce的任務(wù)(job)是類似的。主要區(qū)別是MapReduce任務(wù)最終會(huì)結(jié)束,而拓?fù)鋾?huì)一直運(yùn)行(當(dāng)然直到你殺死它)。一個(gè)拓?fù)涫且粋€(gè)通過流分組(stream grouping)把Spout和Bolt連接到一起的拓?fù)浣Y(jié)構(gòu)。圖的每條邊代表一個(gè)Bolt訂閱了其他Spout或者Bolt的輸出流。一個(gè)拓?fù)渚褪且粋€(gè)復(fù)雜的多階段的流計(jì)算。

2. 元組(Tuple)

元組是Storm提供的一個(gè)輕量級(jí)的數(shù)據(jù)格式,可以用來包裝你需要實(shí)際處理的數(shù)據(jù)。元組是一次消息傳遞的基本單元。一個(gè)元組是一個(gè)命名的值列表,其中的每個(gè)值都可以是任意類型的。元組是動(dòng)態(tài)地進(jìn)行類型轉(zhuǎn)化的--字段的類型不需要事先聲明。在Storm中編程時(shí),就是在操作和轉(zhuǎn)換由元組組成的流。通常,元組包含整數(shù),字節(jié),字符串,浮點(diǎn)數(shù),布爾值和字節(jié)數(shù)組等類型。要想在元組中使用自定義類型,就需要實(shí)現(xiàn)自己的序列化方式。

3. 流(Streams)

流是Storm中的核心抽象。一個(gè)流由無限的元組序列組成,這些元組會(huì)被分布式并行地創(chuàng)建和處理。通過流中元組包含的字段名稱來定義這個(gè)流。每個(gè)流聲明時(shí)都被賦予了一個(gè)ID。只有一個(gè)流的Spout和Bolt非常常見,所以OutputFieldsDeclarer
提供了不需要指定ID來聲明一個(gè)流的函數(shù)(Spout和Bolt都需要聲明輸出的流)。這種情況下,流的ID是默認(rèn)的“default”。

4. Spouts

Spout(噴嘴,這個(gè)名字很形象)是Storm中流的來源。通常Spout從外部數(shù)據(jù)源,如消息隊(duì)列中讀取元組數(shù)據(jù)并吐到拓?fù)淅铩pout可以是可靠的(reliable)或者不可靠(unreliable)的。可靠的Spout能夠在一個(gè)元組被Storm處理失敗時(shí)重新進(jìn)行處理,而非可靠的Spout只是吐數(shù)據(jù)到拓?fù)淅?,不關(guān)心處理成功還是失敗了。
  Spout可以一次給多個(gè)流吐數(shù)據(jù)。此時(shí)需要通過OutputFieldsDeclarer的declareStream函數(shù)來聲明多個(gè)流并在調(diào)用SpoutOutputCollector提供的emit方法時(shí)指定元組吐給哪個(gè)流。
  Spout中最主要的函數(shù)是nextTuple,Storm框架會(huì)不斷調(diào)用它去做元組的輪詢。如果沒有新的元組過來,就直接返回,否則把新元組吐到拓?fù)淅?。nextTuple必須是非阻塞的,因?yàn)镾torm在同一個(gè)線程里執(zhí)行Spout的函數(shù)。
  Spout中另外兩個(gè)主要的函數(shù)是ack和fail。當(dāng)Storm檢測到一個(gè)從Spout吐出的元組在拓?fù)渲谐晒μ幚硗陼r(shí)調(diào)用ack,沒有成功處理完時(shí)調(diào)用fail。只有可靠型的Spout會(huì)調(diào)用ack和fail函數(shù)。更多細(xì)節(jié)可以查看Storm Java文檔和我的另外一篇文章:Storm如何保證可靠的消息處理

5. Bolts

在拓?fù)渲兴械挠?jì)算邏輯都是在Bolt中實(shí)現(xiàn)的。一個(gè)Bolt可以處理任意數(shù)量的輸入流,產(chǎn)生任意數(shù)量新的輸出流。Bolt可以做函數(shù)處理,過濾,流的合并,聚合,存儲(chǔ)到數(shù)據(jù)庫等操作。Bolt就是流水線上的一個(gè)處理單元,把數(shù)據(jù)的計(jì)算處理過程合理的拆分到多個(gè)Bolt、合理設(shè)置Bolt的task數(shù)量,能夠提高Bolt的處理能力,提升流水線的并發(fā)度。
  Bolt可以給多個(gè)流吐出元組數(shù)據(jù)。此時(shí)需要使用OutputFieldsDeclarer的declareStream方法來聲明多個(gè)流并在使用OutputColletor的emit方法時(shí)指定給哪個(gè)流吐數(shù)據(jù)。
  當(dāng)你聲明了一個(gè)Bolt的輸入流,也就訂閱了另外一個(gè)組件的某個(gè)特定的輸出流。如果希望訂閱另一個(gè)組件的所有流,需要單獨(dú)挨個(gè)訂閱。InputDeclarer有語法糖來訂閱ID為默認(rèn)值的流。例如declarer.shuffleGrouping("redBolt")訂閱了redBolt組件上的默認(rèn)流,跟declarer.shuffleGrouping("redBolt", DEFAULT_STREAM_ID)是相同的。
  在Bolt中最主要的函數(shù)是execute函數(shù),它使用一個(gè)新的元組當(dāng)作輸入。Bolt使用OutputCollector對(duì)象來吐出新的元組。Bolts必須為處理的每個(gè)元組調(diào)用OutputCollector的ack方法以便于Storm知道元組什么時(shí)候被各個(gè)Bolt處理完了(最終就可以確認(rèn)Spout吐出的某個(gè)元組處理完了)。通常處理一個(gè)輸入的元組時(shí),會(huì)基于這個(gè)元組吐出零個(gè)或者多個(gè)元組,然后確認(rèn)(ack)輸入的元組處理完了,Storm提供了IBasicBolt接口來自動(dòng)完成確認(rèn)。
  必須注意OutputCollector不是線程安全的,所以所有的吐數(shù)據(jù)(emit)、確認(rèn)(ack)、通知失敗(fail)必須發(fā)生在同一個(gè)線程里。更多信息可以參照問題定位。

6. 任務(wù)(Tasks)

每個(gè)Spout和Bolt會(huì)以多個(gè)任務(wù)(Task)的形式在集群上運(yùn)行。每個(gè)任務(wù)對(duì)應(yīng)一個(gè)執(zhí)行線程,流分組定義了如何從一組任務(wù)(同一個(gè)Bolt)發(fā)送元組到另外一組任務(wù)(另外一個(gè)Bolt)上。可以在調(diào)用TopologyBuilder的setSpout和setBolt函數(shù)時(shí)設(shè)置每個(gè)Spout和Bolt的并發(fā)數(shù)。

7. 組件(Component)

組件(component)是對(duì)Bolt和Spout的統(tǒng)稱

8. 流分組(Stream Grouping)

定義拓?fù)涞臅r(shí)候,一部分工作是指定每個(gè)Bolt應(yīng)該消費(fèi)哪些流。流分組定義了一個(gè)流在一個(gè)消費(fèi)它的Bolt內(nèi)的多個(gè)任務(wù)(task)之間如何分組。流分組跟計(jì)算機(jī)網(wǎng)絡(luò)中的路由功能是類似的,決定了每個(gè)元組在拓?fù)渲械奶幚砺肪€。
  在Storm中有七個(gè)內(nèi)置的流分組策略,你也可以通過實(shí)現(xiàn)CustomStreamGrouping接口來自定義一個(gè)流分組策略:
1. 洗牌分組(Shuffle grouping): 隨機(jī)分配元組到Bolt的某個(gè)任務(wù)上,這樣保證同一個(gè)Bolt的每個(gè)任務(wù)都能夠得到相同數(shù)量的元組。
2. 字段分組(Fields grouping): 按照指定的分組字段來進(jìn)行流的分組。例如,流是用字段“user-id"來分組的,那有著相同“user-id"的元組就會(huì)分到同一個(gè)任務(wù)里,但是有不同“user-id"的元組就會(huì)分到不同的任務(wù)里。這是一種非常重要的分組方式,通過這種流分組方式,我們就可以做到讓Storm產(chǎn)出的消息在這個(gè)"user-id"級(jí)別是嚴(yán)格有序的,這對(duì)一些對(duì)時(shí)序敏感的應(yīng)用(例如,計(jì)費(fèi)系統(tǒng))是非常重要的。
3. Partial Key grouping: 跟字段分組一樣,流也是用指定的分組字段進(jìn)行分組的,但是在多個(gè)下游Bolt之間是有負(fù)載均衡的,這樣當(dāng)輸入數(shù)據(jù)有傾斜時(shí)可以更好的利用資源。這篇論文很好的解釋了這是如何工作的,有哪些優(yōu)勢(shì)。
4. All grouping: 流會(huì)復(fù)制給Bolt的所有任務(wù)。小心使用這種分組方式。在拓?fù)渲?,如果希望某類元祖發(fā)送到所有的下游消費(fèi)者,就可以使用這種All grouping的流分組策略。
5. Global grouping: 整個(gè)流會(huì)分配給Bolt的一個(gè)任務(wù)。具體一點(diǎn),會(huì)分配給有最小ID的任務(wù)。
6. 不分組(None grouping): 說明不關(guān)心流是如何分組的。目前,None grouping等價(jià)于洗牌分組。
7. Direct grouping:一種特殊的分組。對(duì)于這樣分組的流,元組的生產(chǎn)者決定消費(fèi)者的哪個(gè)任務(wù)會(huì)接收處理這個(gè)元組。只能在聲明做直連的流(direct streams)上聲明Direct groupings分組方式。只能通過使用emitDirect系列函數(shù)來吐元組給直連流。一個(gè)Bolt可以通過提供的TopologyContext來獲得消費(fèi)者的任務(wù)ID,也可以通過OutputCollector對(duì)象的emit函數(shù)(會(huì)返回元組被發(fā)送到的任務(wù)的ID)來跟蹤消費(fèi)者的任務(wù)ID。在ack的實(shí)現(xiàn)中,Spout有兩個(gè)直連輸入流,ack和ackFail,使用了這種直連分組的方式。
8. Local or shuffle grouping:如果目標(biāo)Bolt在同一個(gè)worker進(jìn)程里有一個(gè)或多個(gè)任務(wù),元組就會(huì)通過洗牌的方式分配到這些同一個(gè)進(jìn)程內(nèi)的任務(wù)里。否則,就跟普通的洗牌分組一樣。這種方式的好處是可以提高拓?fù)涞奶幚硇?,因?yàn)閣orker內(nèi)部通信就是進(jìn)程內(nèi)部通信了,相比拓?fù)溟g的進(jìn)程間通信要高效的多。worker進(jìn)程間通信是通過使用Netty來進(jìn)行網(wǎng)絡(luò)通信的。

9. 可靠性(Reliability)

Storm保證了拓?fù)渲蠸pout產(chǎn)生的每個(gè)元組都會(huì)被處理。Storm是通過跟蹤每個(gè)Spout所產(chǎn)生的所有元組構(gòu)成的樹形結(jié)構(gòu)并得知這棵樹何時(shí)被完整地處理來達(dá)到可靠性。每個(gè)拓?fù)鋵?duì)這些樹形結(jié)構(gòu)都有一個(gè)關(guān)聯(lián)的“消息超時(shí)”。如果在這個(gè)超時(shí)時(shí)間里Storm檢測到Spout產(chǎn)生的一個(gè)元組沒有被成功處理完,那Sput的這個(gè)元組就處理失敗了,后續(xù)會(huì)重新處理一遍。
  為了發(fā)揮Storm的可靠性,需要你在創(chuàng)建一個(gè)元組樹中的一條邊時(shí)告訴Storm,也需要在處理完每個(gè)元組之后告訴Storm。這些都是通過Bolt吐元組數(shù)據(jù)用的OutputCollector對(duì)象來完成的。標(biāo)記是在emit函數(shù)里完成,完成一個(gè)元組后需要使用ack函數(shù)來告訴Storm。
這些都在“保證消息處理”一文中會(huì)有更詳細(xì)的介紹。

10. Workers(工作進(jìn)程)

拓?fù)湟砸粋€(gè)或多個(gè)Worker進(jìn)程的方式運(yùn)行。每個(gè)Worker進(jìn)程是一個(gè)物理的Java虛擬機(jī),執(zhí)行拓?fù)涞囊徊糠秩蝿?wù)。例如,如果拓?fù)涞牟l(fā)設(shè)置成了300,分配了50個(gè)Worker,那么每個(gè)Worker執(zhí)行6個(gè)任務(wù)(作為Worker內(nèi)部的線程)。Storm會(huì)盡量把所有的任務(wù)均分到所有的Worker上。

五、Storm中用到的技術(shù)

ZeroMQ 提供了可擴(kuò)展環(huán)境下的傳輸層高效消息通信,一開始Storm的內(nèi)部通信使用的是ZeroMQ,后來作者想把Storm移交給Apache開源基金會(huì)來管理,而ZeroMQ的許可證書跟Apache基金會(huì)的政策有沖突。在Storm中,Netty比ZeroMQ更加高效,而且提供了worker間通信時(shí)的驗(yàn)證機(jī)制,所以在Storm0.9中,就改用了Netty。
  Clojure Storm系統(tǒng)的實(shí)現(xiàn)語言。Clojure是由Rich Hicky作為一種通用語言發(fā)明的,它衍生自Lisp語言,簡化了多線程編程。
  **Apache ZooKeeper **Zookeeper是一個(gè)實(shí)現(xiàn)高可靠的分布式協(xié)作的開源項(xiàng)目。Storm使用Zookeeper來協(xié)調(diào)集群中的多個(gè)節(jié)點(diǎn)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Storm 系統(tǒng)中包含以下幾個(gè)基本概念:拓?fù)洌═opologies)流(Streams)數(shù)據(jù)源(Spouts)數(shù)據(jù)...
    發(fā)光的魚閱讀 841評(píng)論 0 0
  • 什么是實(shí)時(shí)流計(jì)算? 主要的處理模式可以分為:流處理,批處理 流處理是直接處理,有時(shí)也分為在線,離線,近線(st...
    Bloo_m閱讀 5,087評(píng)論 1 1
  • 此頁面列舉了Storm的主要概念和資源連接。討論的概念有: 拓?fù)洌═opologies) 流(Streams) S...
    ximengchj閱讀 380評(píng)論 0 0
  • Storm版本:我們使用0.10.2的版本。Storm團(tuán)隊(duì)在2016年4月份發(fā)布了歷史性的版本升級(jí),終于到了1.0...
    編程回憶錄閱讀 622評(píng)論 0 0
  • 今天的主人公也是一個(gè)一線的觀測人員,他94年入伍,以那個(gè)小小的海島為家,堅(jiān)守著海島,2010年退伍,然后依舊在海島...
    小小_靜靜閱讀 172評(píng)論 0 0