轉(zhuǎn)載自個(gè)人博客
1佃扼、集群架構(gòu)
JStorm從設(shè)計(jì)的角度趟脂,就是一個(gè)典型的調(diào)度系統(tǒng),簡(jiǎn)單集群的架構(gòu)如下圖所示抢韭,其中Nimbus可增加一個(gè)備節(jié)點(diǎn)薪贫,多個(gè)Supervisor節(jié)點(diǎn)組成任務(wù)執(zhí)行集群。
1.1刻恭、Nimbus
Nimbus是作為整個(gè)集群的調(diào)度器角色瞧省,負(fù)責(zé)分發(fā)topology代碼扯夭、分配任務(wù),監(jiān)控集群運(yùn)行狀態(tài)等鞍匾,其主要通過ZK與supervisor交互交洗。可以和Supervisor運(yùn)行在同一物理機(jī)上橡淑,JStorm中Nimbus可采用主從備份构拳,支持熱切。
1.2梁棠、Supervisor
Supervisor 是集群中任務(wù)的執(zhí)行者置森,負(fù)責(zé)運(yùn)行具體任務(wù)以及關(guān)閉任務(wù)。其從ZK中監(jiān)聽nimbus的指令符糊,然后接收分發(fā)代碼和任務(wù)并執(zhí)行凫海、監(jiān)控反饋任務(wù)執(zhí)行情況。
1.3 男娄、Zookeeper
ZK是整個(gè)系統(tǒng)中的協(xié)調(diào)者行贪,Nimbus的任務(wù)調(diào)度通過ZK下發(fā)至Supervisor來執(zhí)行。
2模闲、Topology編程模型
Topology是一個(gè)可以在JStorm中運(yùn)行的任務(wù)的抽象表達(dá)建瘫,在JStorm的topology中,有兩種組件:spout和bolt尸折。下面是一張比較經(jīng)典的Topology結(jié)構(gòu)圖啰脚。每一個(gè)topology,既可以有多個(gè)spout翁授,代表同時(shí)從多個(gè)數(shù)據(jù)源接收消息拣播,也可以多個(gè)bolt晾咪,來執(zhí)行不同的業(yè)務(wù)邏輯收擦。一個(gè)topology會(huì)一直運(yùn)行直到你手動(dòng)kill掉,JStorm自動(dòng)重新分配執(zhí)行失敗的任務(wù)谍倦。
在JStorm中有對(duì)于流stream的抽象塞赂,流是一個(gè)不間斷的無界的連續(xù)tuple,注意JStorm在建模事件流時(shí)昼蛀,把流中的事件抽象為tuple即元組宴猾。
我們可以認(rèn)為spout就是一個(gè)一個(gè)的水龍頭,并且每個(gè)水龍頭里流出的水是不同的tuple叼旋,我們想拿到哪種水tuple就擰開哪個(gè)水龍頭仇哆,然后使用管道將水龍頭的水tuple導(dǎo)向到一個(gè)水處理器(bolt),水處理器bolt處理后再使用管道導(dǎo)向另一個(gè)處理器或者存入容器中夫植。
JStorm將上圖抽象為Topology即拓?fù)涠锾蓿負(fù)浣Y(jié)構(gòu)是有向無環(huán)的油讯,拓?fù)涫荍storm中最高層次的一個(gè)抽象概念,它可以被提交到Jstorm集群執(zhí)行延欠,一個(gè)拓?fù)渚褪且粋€(gè)數(shù)據(jù)流轉(zhuǎn)換圖陌兑,圖中每個(gè)節(jié)點(diǎn)是一個(gè)spout或者bolt,圖中的邊表示bolt訂閱了哪些流由捎,當(dāng)spout或者bolt發(fā)送元組到流時(shí)兔综,它就發(fā)送元組到每個(gè)訂閱了該流的bolt。
2.1狞玛、spout
JStorm認(rèn)為每個(gè)stream都有一個(gè)stream源软驰,也就是原始元組的源頭,所以它將這個(gè)源頭抽象為spout为居,spout可能是連接消息中間件(如MetaQ碌宴, Kafka, TBNotify等)蒙畴,并不斷發(fā)出消息贰镣,也可能是從某個(gè)隊(duì)列中不斷讀取隊(duì)列元素并裝配為tuple發(fā)射。
JStorm框架對(duì)spout組件定義了一個(gè)主要方法:nextTuple膳凝,顧名思義碑隆,就是獲取下一條消息。執(zhí)行時(shí)蹬音,可以理解成JStorm框架會(huì)不停地調(diào)這個(gè)接口上煤,以從數(shù)據(jù)源拉取數(shù)據(jù)并往bolt發(fā)送數(shù)據(jù)。
Tuple是一次消息傳遞的基本單元著淆,tuple里的每個(gè)字段一個(gè)名字,并且不同tuple的對(duì)應(yīng)字段的類型必須一樣劫狠。tuple的字段類型可以是: integer, long, short, byte, string, double, float, boolean和byte array。還可以自定義類型永部,只要實(shí)現(xiàn)對(duì)應(yīng)的序列化器独泞。
JStorm中與spout相關(guān)的接口主要是ISpout和IRichSpout、IBatchSpout苔埋,后兩接口實(shí)現(xiàn)了對(duì)ISpout接口的上層封裝懦砂。
ISpout接口主要方法:
open:
在worker中初始化該ISpout時(shí)調(diào)用,一般用來設(shè)置一些屬性:比如從spring容器中獲取對(duì)應(yīng)的Bean组橄。
close:
和open相對(duì)應(yīng)(在要關(guān)閉的時(shí)候調(diào)用)荞膘。
activate:
從非活動(dòng)狀態(tài)變?yōu)榛顒?dòng)狀態(tài)時(shí)調(diào)用。
deactivate:
和activate相對(duì)應(yīng)(從活動(dòng)狀態(tài)變?yōu)榉腔顒?dòng)狀態(tài)時(shí)調(diào)用)玉工。
nextTuple:
JStorm希望在每次調(diào)用該方法的時(shí)候羽资,它會(huì)通過collector.emit發(fā)射一個(gè)tuple。
ack:
jstorm發(fā)現(xiàn)msgId對(duì)應(yīng)的tuple被成功地完整消費(fèi)會(huì)調(diào)用該方法遵班。
fail:
和ack相對(duì)應(yīng)(jstorm發(fā)現(xiàn)某個(gè)tuple在某個(gè)環(huán)節(jié)失敗了)屠升。和ack一起保證tuple一定被處理瞄勾。
2.2、bolt
JStorm將tuple的中間處理過程抽象為Bolt弥激,bolt可以消費(fèi)任意數(shù)量的輸入流进陡,只要將流方向?qū)蛟揵olt,同時(shí)它也可以發(fā)送新的流給其他bolt使用微服,這樣一來趾疚,只要打開特定的spout(管口)再將spout中流出的tuple導(dǎo)向特定的bolt,然后bolt對(duì)導(dǎo)入的流做處理后再導(dǎo)向其他bolt或者目的地以蕴。
bolt代表處理邏輯糙麦,bolt收到消息之后,對(duì)消息做處理(即執(zhí)行用戶的業(yè)務(wù)邏輯)丛肮,處理完以后赡磅,既可以將處理后的消息繼續(xù)發(fā)送到下游的bolt,這樣會(huì)形成一個(gè)處理流水線(不過更復(fù)雜的情況應(yīng)該是個(gè)有向圖)宝与;也可以直接結(jié)束焚廊。
bolt組件主要方法:execute,這個(gè)接口就是用戶用來處理業(yè)務(wù)邏輯的地方习劫。
通常一個(gè)流水線的最后一個(gè)bolt咆瘟,會(huì)做一些數(shù)據(jù)的存儲(chǔ)工作,比如將實(shí)時(shí)計(jì)算出來的數(shù)據(jù)寫入DB诽里、HBase等袒餐,以供前臺(tái)業(yè)務(wù)進(jìn)行查詢和展現(xiàn)。Bolts可以發(fā)射多條消息流谤狡, 使用OutputFieldsDeclarer.declareStream定義stream灸眼,使用OutputCollector.emit來選擇要發(fā)射的stream。
在保證不丟消息的場(chǎng)景中墓懂,在bolts必須要為它處理的每一個(gè)tuple調(diào)用OutputCollector的ack方法焰宣,以通知JStorm這個(gè)tuple被處理完成了,從而通知這個(gè)tuple的發(fā)射者spouts拒贱。 一般的流程是: bolts處理一個(gè)輸入tuple, 發(fā)射0個(gè)或者多個(gè)tuple, 然后調(diào)用ack通知JStorm自己已經(jīng)處理過這個(gè)tuple了宛徊。JStorm提供了一個(gè)IBasicBolt會(huì)自動(dòng)調(diào)用ack佛嬉。
JStorm中與Bolt相關(guān)的接口主要是IBolt逻澳,IRichBolt,IBasicBolt和IBatchBolt暖呕,后面接口實(shí)現(xiàn)了對(duì)IBolt接口的上層封裝斜做。
IBolt接口的主要方法:
prepare:
在worker中初始化該IBolt時(shí)調(diào)用,一般用來設(shè)置一些屬性:比如從spring容器中獲取對(duì)應(yīng)的Bean湾揽。
cleanup:
和prepare相對(duì)應(yīng)(在顯示關(guān)閉topology的時(shí)候調(diào)用)
execute:
處理jstorm發(fā)送過來的tuple瓤逼。
2.3笼吟、Tuple
JStorm將流中數(shù)據(jù)抽象為tuple,一個(gè)tuple就是一個(gè)值列表value list霸旗,list中的每個(gè)value都有一個(gè)name贷帮,tuple可以由任意類型組合而成,因?yàn)閟torm是分布式的诱告,所以它需要知道在task間如何序列化和反序列化數(shù)據(jù)的撵枢。storm使用Kryo進(jìn)行序列化,Kryo是java開發(fā)中一個(gè)快速靈活序列器精居。默認(rèn)情況下锄禽,storm可以序列化基礎(chǔ)類型,比如字符串靴姿,字節(jié)沃但,數(shù)組,ArrayList, HashMap, HashSet和 Clojure 集合類型佛吓,如果需要使用其他類型宵晚,需要自定義序列器。拓?fù)涞拿總€(gè)節(jié)點(diǎn)都要說明它所發(fā)射出的元組的字段的name维雇,其他節(jié)點(diǎn)只需要訂閱該name就可以接收處理坝疼。
在spout和Bolt組件中,使用declareOutputFields方法定義發(fā)射出的tuple的字段名谆沃。
3钝凶、小結(jié)
本文主要講述了JStorm中集群的架構(gòu)以及Topology編程模型方面的概念知識(shí),后續(xù)會(huì)更深入的寫一些實(shí)踐唁影、運(yùn)維耕陷、原理等方面的文章。