構(gòu)建企業(yè)級批處理應(yīng)用

在現(xiàn)代企業(yè)應(yīng)用中汪厨,有很多應(yīng)用和系統(tǒng)需要在生產(chǎn)環(huán)境中使用批處理來執(zhí)行大量的業(yè)務(wù)操作包竹。那么如何實現(xiàn)高效的厉碟、穩(wěn)定的批處理任務(wù)就變得比較重要了躲雅。

本篇將介紹如何構(gòu)建企業(yè)級批處理應(yīng)用鼎姊,以及如何選擇具體的實現(xiàn),包含標(biāo)準(zhǔn)相赁、框架等相寇。然后會著重介紹java平臺下的幾種實現(xiàn),譬如jee7里包含的jsr-352钮科、spring-batch唤衫、easy-batch。

批處理是什么

企業(yè)應(yīng)用中經(jīng)常需要以極高的效率自動地對海量數(shù)據(jù)信息進(jìn)行各種復(fù)雜的業(yè)務(wù)邏輯處理绵脯。執(zhí)行這種操作通常需要根據(jù)時間事件(如月末統(tǒng)計佳励,通知或信件),或是定期處理那些業(yè)務(wù)規(guī)則超級復(fù)雜蛆挫、數(shù)據(jù)量非常龐大的業(yè)務(wù)赃承,也可能是從內(nèi)部/外部系統(tǒng)抓取到的各種數(shù)據(jù)。在這個過程中一般需要格式化悴侵、數(shù)據(jù)校驗瞧剖、以事務(wù)的方式進(jìn)行存儲。企業(yè)中每天處理的事務(wù)量多達(dá)數(shù)十億可免,這類工作就是批處理抓于。

批處理應(yīng)用有以下幾個特點

非交互式、面向批處理浇借、長時間運行

數(shù)據(jù)或計算密集型

順序或并行執(zhí)行

即時捉撮,計劃或按需執(zhí)行

批處理的流程分三個特定的階段

讀數(shù)據(jù),數(shù)據(jù)來源于不同的存儲或消息隊列

業(yè)務(wù)處理逮刨,格式化呕缭、合并、轉(zhuǎn)換等

歸檔結(jié)果數(shù)據(jù)修己,將輸出結(jié)果寫入不同的存儲或消息隊列

批處理設(shè)計原則

將對在線服務(wù)架構(gòu)影響降到最低恢总,盡可能使用公共模塊

盡可能簡化單個批處理應(yīng)用中的邏輯

盡可能在數(shù)據(jù)存儲的地方處理這些數(shù)據(jù)

盡可能少使用io這樣的資源,多使用內(nèi)存

監(jiān)控應(yīng)用程序io睬愤,避免不必要的物理io

在同一個批處理不要做兩次一樣的事

盡可能預(yù)先分配足夠的內(nèi)存

盡可能的加入數(shù)據(jù)校驗以保證數(shù)據(jù)完整性

盡可能早地在模擬生產(chǎn)環(huán)境下使用真實的數(shù)據(jù)量片仿,進(jìn)行計劃和執(zhí)行壓力測試

批處理包括

常規(guī)批處理

并發(fā)批處理

并行批處理

分區(qū)批處理

批處理健壯性需求

監(jiān)控,可以監(jiān)控執(zhí)行中的狀態(tài)

跳過尤辱,可以在任務(wù)執(zhí)行遇到異成巴悖或者故障時候厢岂,進(jìn)行選擇性的跳過

任務(wù)重啟,任務(wù)如遇到卡在某一步的時候阳距,可以試著重啟的方式繼續(xù)從故障點開始往后執(zhí)行

重試塔粒,在遇到某個異常的時候,可嘗試重試來完成任務(wù)要求

技術(shù)選型

上文對批處理有了一些了解筐摘,那么我們該如何去實現(xiàn)呢卒茬?選擇自己開發(fā)這樣一套涵蓋上述方方面面的框架,還是選擇開源的框架咖熟、或者也有的Java EE支持部分圃酵?既然要選擇,就應(yīng)該明曉哪些點是你所關(guān)注的部分馍管,以下介紹一些點以備選擇參考郭赐。

可測試性,是否可以更方面對每個環(huán)節(jié)進(jìn)行測試

組件化确沸,是否具備一套完備的組件支撐

可觀察性捌锭,是否方便監(jiān)控各種狀態(tài)

社區(qū)化,是否有良好的社區(qū)支持张惹,產(chǎn)品更迭速度舀锨,方便遇到問題能夠有較好的支持

可伸縮性岭洲,比如Multi-threaded宛逗、Partitioning、Parallel 盾剩、Remote 的支持

可配置性雷激,是否支持良好的xml配置、以及java annotation等

可擴展性告私,比如對啟動屎暇、重啟任務(wù)有更多的擴展接口支持

幾種實現(xiàn)

JSR-352、Spring Batch驻粟,Easy Batch根悼、JBatch IBM (Glassfish, JEUS)、JBeret (Wildfly)都有一套對batch processing的實現(xiàn)蜀撑,本文僅對Spring Batch的架構(gòu)挤巡、決策器、伸縮性(批處理選項)酷麦、健壯性等方面進(jìn)行介紹矿卑。

Spring Batch

SpringSource與Accenture合作開發(fā)了Spring Batch

Spring Batch借鑒了JCL(Job Control Language)和COBOL的語言特性

Spring Batch一款優(yōu)秀的、開源的大數(shù)據(jù)量并?處理框架

Spring Batch可以構(gòu)建出輕量級的健壯的并?處理應(yīng)?沃饶,?持事務(wù)母廷、并發(fā)轻黑、流程、監(jiān)控琴昆、縱向和橫向擴展氓鄙,提供統(tǒng)?的接口管理和任務(wù)管理

Spring Batch 3.x對jsr-352有支持。

分層架構(gòu)

(如圖业舍,整體架構(gòu)包含四個部分)


基礎(chǔ)設(shè)施層玖详,主要提供策略方面的支持,比如輸入勤讽、輸出蟋座、事務(wù)、重試等

批處理執(zhí)行環(huán)境脚牍,主要提供批處理需要各種領(lǐng)域?qū)ο笙蛲危热鏙ob、Step等

批處理核心組件诸狭,主要提供給應(yīng)用層需要的api支持

業(yè)務(wù)應(yīng)用層券膀,開發(fā)各式的批處理業(yè)務(wù)

上下文

外部控制器調(diào)用JobLauncher啟動一個Job,Job調(diào)用自己的Step去實現(xiàn)對數(shù)據(jù)的操作驯遇,Step處理完成后芹彬,再將處理結(jié)果一步步返回給上一層,這就是Batch處理實現(xiàn)的一個簡單流程叉庐。

執(zhí)行過程

(Spring Batch的執(zhí)行過程)


說明如下:

每個Batch都會包含一個Job舒帮。Job就像一個容器,容器里裝了若干個Step陡叠,Batch中實際干活的也就是這些Step玩郊,至于Step干什么活,無外乎讀取數(shù)據(jù)枉阵,處理數(shù)據(jù)译红,然后將這些數(shù)據(jù)存儲起來(ItemReader用來讀取數(shù)據(jù),ItemProcessor用來處理數(shù)據(jù)兴溜,ItemWriter用來寫數(shù)據(jù)) 侦厚。JobLauncher用來啟動Job,JobRepository是上述處理提供的一種持久化機制(它為JobLauncher拙徽,Job刨沦,和Step實例提供CRUD操作)。

簡單實現(xiàn)樣例:

commit-interval="1">

上面是一個最基本的配置斋攀,包含了批處理流程中的三個階段已卷,其處理流程如下圖:

從特定的數(shù)據(jù)源取出數(shù)據(jù)的時候,read()操作每次只讀取一條記錄淳蔼,之后將讀取的這條數(shù)據(jù)傳遞給processor(item)處理侧蘸,框架將重復(fù)做這兩步操作裁眯,直到讀取記錄的件數(shù)達(dá)到batch配置信息中”commin-interval”設(shè)定值的時候,就會調(diào)用一次write操作讳癌。然后再重復(fù)上圖的處理穿稳,直到處理完所有的數(shù)據(jù)。當(dāng)這個Step的工作完成以后晌坤,或是跳到其他Step逢艘,或是結(jié)束處理。

詳細(xì)的處理流程示意圖:

批量提交次數(shù)為1骤菠,commit-interval="1"它改。

(一個Spring Batch的基本工作流程)


下面介紹具體組件。

領(lǐng)域?qū)ο?/b>

Job

Job -- 由?組Step構(gòu)成,完成Batch數(shù)據(jù)操作的整個過程

Job Instance -- 特定的運行時Job實例,由Job launcher運行

Job Execution -- 某個Job實例的執(zhí)?信息,包括執(zhí)?時間商乎、狀態(tài)央拖、退出代碼等

Job實例和執(zhí)?數(shù)據(jù)、參數(shù)等元數(shù)據(jù)信息都由Job repository進(jìn)?持久化

啟動Job, jobLauncher.run(demoJob, jobParameterBulider.toJobParameters());

JobParameters

JobParameters鹉戚,就是Job運行時的參數(shù)鲜戒。可以表示不同的JobInstance和給job傳參數(shù)抹凳。

在啟動job時遏餐,設(shè)置參數(shù)的key/value即可。

jobLauncher.run(job, new JobParametersBuilder()

.addString("inputFilePath", "/tmp/index.txt").toJobParameters()

如代碼所示赢底,參數(shù)inputFilePath傳給Job了失都,在Job中如果需要使用參數(shù)信息,可以使用Spring注入的方式傳給不同的使用對象颖系。

需要設(shè)置Bean的scope屬性為step嗅剖。這是Spring Batch的一個后綁定技術(shù),就是在生成Step的時候嘁扼,才去創(chuàng)建bean,因為這個時候JobParameter才傳過來黔攒。如果加載配置信息的時候就創(chuàng)建bean趁啸,這個時候JobParameter的值還沒有產(chǎn)生,會拋出異常督惰。

JobParametersIncrementer

同一個Job在batch啟動后被多次調(diào)用的時候不傅,需要創(chuàng)建一個新實例。JobParametersIncrementer接口提供了getNext方法赏胚,可以為parameters添加一個自增的值访娶,以區(qū)分不同的Job實例。RunIdIncrementer就是Spring Batch框架提供一個實現(xiàn)類觉阅。使用方法如下:

class="org.springframework.batch.core.launch.support.RunIdIncrementer"/>

RunIdIncrementer的getNext方法實現(xiàn)如下:

public JobParameters getNext(JobParameters parameters) {

if (parameters == null) {

parameters = new JobParameters();

}

long id = parameters.getLong(key, 0L) + 1;

return new JobParametersBuilder(parameters).addLong(key, id).toJobParameters();

}

由代碼可以看出崖疤,通過id值加一的方式來保證了每次創(chuàng)建的jobInstance的唯一性秘车。

Step

Step是Job的一個執(zhí)行階段

Step通過tasklet和chunk元素控制數(shù)據(jù)的處理策略

一組Step可以順序執(zhí)行,也可以根據(jù)條件分段執(zhí)行

Step的執(zhí)?數(shù)據(jù)同樣由Job repository進(jìn)行持久化

DataSource

File

XML

Database

Message(JMS、AMQP)

決策器

前文的樣例部分介紹了一步步執(zhí)行的順序Job劫哼,那么如何按Step執(zhí)行結(jié)果來選擇后續(xù)的Step呢叮趴?這里介紹的Decision就是一種按分支來執(zhí)行的Job。如下圖所示权烧,可以看到返回為SKIPPER時候跳到generateReport這個Step眯亦,其他的都直接跳到clean這個Step。

配置如下:

監(jiān)控

Spring Batch提供了4種監(jiān)控?式:

直接查看Job repository的數(shù)據(jù)庫信息般码,所有的Batch元數(shù)據(jù)都會持久化到數(shù)據(jù)庫中

使用Spring Batch提供的API自?構(gòu)建監(jiān)控數(shù)據(jù)

使用Spring Batch Admin妻率,通過web控制臺監(jiān)控和操作Job

使用JMX的方式

spring batch admin提供的控制臺:

健壯性

主要包含重啟、跳過板祝、重試等舌涨。

重啟(restart)

在某個job執(zhí)行發(fā)生異常時,可能執(zhí)行完成了某些步驟扔字,期望重啟相同參數(shù)的該次job囊嘉,就可以用restart參數(shù)來進(jìn)行設(shè)置。

可配置參數(shù)allow-start-if-complete來設(shè)置開啟重啟革为,start-limit設(shè)置重啟限制次數(shù)

重啟相同job參數(shù)的job launch

配置如下:

跳過(skip)

再發(fā)生非致命異常時候扭粱,比如某些值不符合格式要求,程序檢查發(fā)生異常時震檩。這樣的情況一般選擇設(shè)置跳過即可琢蛤。

配置如下:

class="org.springframework.batch.item.file.FlatFileParseException" />

重試(retry)

發(fā)?瞬態(tài)異常,當(dāng)發(fā)?瞬態(tài)失敗的時候進(jìn)行重試(例如遇到記錄鎖的情況)抛虏,一般在Chunk的Step和應(yīng)用程序中進(jìn)行配置或處理博其。

配置如下:

commit-interval="5" retry-limit="3" skip-limit="3" >

伸縮性

Spring Batch支持Multi-threaded、Partitioning迂猴、Parallel 慕淡、Remote四種伸縮方式。

Multi-threaded方式

單線程執(zhí)行情況

前文已有部分介紹沸毁,當(dāng)批量提交次數(shù)為1的情況峰髓。批量提交次數(shù)為多個, commit-interval="3"見下圖息尺。

多線程方式

多個線程并行執(zhí)行chunk携兵。

配置如下:

commit-interval="1000">

線程池的配置

需要注意的是,在多線程Step中搂誉,需要確保Reader徐紧、Processor和Writer是線程安全的,否則容易出現(xiàn)并發(fā)問題。Spring Batch提供的大部分組件都是非線程安全的并级,他們都保存有部分狀態(tài)信息拂檩,主要是為了支持任務(wù)重啟。

因此死遭,使用多線程Step的核心任務(wù)是實現(xiàn)無狀態(tài)化广恢,例如不保存當(dāng)前讀取的item的cursor,而是同item的flag字段來區(qū)分item是否被處理過呀潭,已經(jīng)被處理過的下次重啟的時候钉迷,直接被過濾掉。多線程Step實現(xiàn)的是單個Step的多線程化钠署。

Partitioning方式

分區(qū)主要包含:

數(shù)據(jù)分區(qū)

分區(qū)處理

方式基本上包含:

Local Partitioning

Remote Partitioning

Spring Batch提供了一個同一臺機器上的Handler實現(xiàn)糠聪,在同一機器上創(chuàng)建多個Step Execution。

Local Partitioning

配置如下:

processor="itemProcessor" commit-interval="1" />

Remote Partitioning

處理遠(yuǎn)程分塊來執(zhí)行的方式外谐鼎,在遠(yuǎn)程分塊的同時還可以加上分區(qū)來實現(xiàn)遠(yuǎn)程分塊分區(qū)的實現(xiàn)舰蟆。

詳細(xì)的實現(xiàn)以及配置就不做說明了,主要是用到spring integration來做消息集成狸棍。

Remote

使用遠(yuǎn)程分塊的Step被拆分成多個進(jìn)程進(jìn)行處理身害,多個進(jìn)程間通過中間件實現(xiàn)通信。

下面是一幅模型示意圖:


Master組件是單個進(jìn)程草戈,從屬組件(Slaves)一般是多個遠(yuǎn)程進(jìn)程塌鸯。如果Master進(jìn)程不是瓶頸的話,那么這種模式的效果幾乎是最好的唐片,因此應(yīng)該在處理數(shù)據(jù)比讀取數(shù)據(jù)消耗更多時間的情況下使用(實際應(yīng)用中常常是這種情形)丙猬。

Parallel

需要并行的程序邏輯可以劃分為不同的職責(zé),并分配給各個獨立的step费韭,那么就可以在單個進(jìn)程中并行執(zhí)行茧球。并行Step執(zhí)行很容易配置和使用,如下圖所示:

配置如下:

commit-interval="1000">

commit-interval="1000">

四種方式比較

前面對四種方式的實現(xiàn)方式和圖示已做了簡單介紹星持,下面我們再次看看四種方式的應(yīng)用上的差異抢埋,做一個比較。

寫在最后

以上為筆者在使用過程中的心得體會钉汗。目前spring batch 3.x 已涵蓋了批處理的多方面的內(nèi)容羹令,包含對jsr-352也有較好的支持、也提供了豐富的接口损痰,易于擴展,且上手相對容易酒来,可是對annotation的配置方式支持不夠全卢未,期望后續(xù)的版本能夠有改進(jìn)。

參考:

選擇正確的批處理實現(xiàn)

Horizontal and Vertical Scaling Strategies for Batch Applications

Spring Batch Behind the Scenes


本文作者:楊濤(點融黑幫),目前在點融網(wǎng)架構(gòu)組從事應(yīng)用架構(gòu)相關(guān)工作病毡。對微服務(wù)和docker技術(shù)有較多的實戰(zhàn)經(jīng)驗审孽。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末解幽,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子戳葵,更是在濱河造成了極大的恐慌,老刑警劉巖汉匙,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拱烁,死亡現(xiàn)場離奇詭異,居然都是意外死亡噩翠,警方通過查閱死者的電腦和手機戏自,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來伤锚,“玉大人擅笔,你說我怎么就攤上這事⊥驮” “怎么了猛们?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長狞洋。 經(jīng)常有香客問我弯淘,道長,這世上最難降的妖魔是什么徘铝? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任耳胎,我火速辦了婚禮,結(jié)果婚禮上惕它,老公的妹妹穿的比我還像新娘怕午。我一直安慰自己,他們只是感情好淹魄,可當(dāng)我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布郁惜。 她就那樣靜靜地躺著,像睡著了一般甲锡。 火紅的嫁衣襯著肌膚如雪兆蕉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天缤沦,我揣著相機與錄音虎韵,去河邊找鬼。 笑死缸废,一個胖子當(dāng)著我的面吹牛包蓝,可吹牛的內(nèi)容都是我干的驶社。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼测萎,長吁一口氣:“原來是場噩夢啊……” “哼亡电!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起硅瞧,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤份乒,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后腕唧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體或辖,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年四苇,在試婚紗的時候發(fā)現(xiàn)自己被綠了孝凌。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡月腋,死狀恐怖蟀架,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情榆骚,我是刑警寧澤片拍,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站妓肢,受9級特大地震影響捌省,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜碉钠,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一纲缓、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧喊废,春花似錦祝高、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至瓣蛀,卻和暖如春陆蟆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背惋增。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工叠殷, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人诈皿。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓溪猿,卻偏偏與公主長得像钩杰,于是被迫代替她去往敵國和親纫塌。 傳聞我的和親對象是個殘疾皇子诊县,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,877評論 2 345

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