批處理框架 Spring Batch 這么強悼泌,你會用嗎松捉?

spring batch簡介

spring batch是spring提供的一個數(shù)據(jù)處理框架。企業(yè)域中的許多應用程序需要批量處理才能在關(guān)鍵任務環(huán)境中執(zhí)行業(yè)務操作馆里。這些業(yè)務運營包括:

? ? ? ? 無需用戶交互即可最有效地處理大量信息的自動化隘世,復雜處理。這些操作通常包括基于時間的事件(例如月末計算鸠踪,通知或通信)丙者。

? ? ? ? 在非常大的數(shù)據(jù)集中重復處理復雜業(yè)務規(guī)則的定期應用(例如,保險利益確定或費率調(diào)整)营密。

? ? ? ? 集成從內(nèi)部和外部系統(tǒng)接收的信息械媒,這些信息通常需要以事務方式格式化,驗證和處理到記錄系統(tǒng)中评汰。批處理用于每天為企業(yè)處理數(shù)十億的交易纷捞。

Spring Batch是一個輕量級,全面的批處理框架被去,旨在開發(fā)對企業(yè)系統(tǒng)日常運營至關(guān)重要的強大批處理應用程序主儡。Spring Batch構(gòu)建了人們期望的Spring Framework特性(生產(chǎn)力,基于POJO的開發(fā)方法和一般易用性)惨缆,同時使開發(fā)人員可以在必要時輕松訪問和利用更高級的企業(yè)服務糜值。Spring Batch不是一個schuedling的框架。

Spring Batch提供了可重用的功能坯墨,這些功能對于處理大量的數(shù)據(jù)至關(guān)重要寂汇,包括記錄/跟蹤,事務管理捣染,作業(yè)處理統(tǒng)計健无,作業(yè)重啟,跳過和資源管理液斜。它還提供更高級的技術(shù)服務和功能累贤,通過優(yōu)化和分區(qū)技術(shù)實現(xiàn)極高容量和高性能的批處理作業(yè)。

Spring Batch可用于兩種簡單的用例(例如將文件讀入數(shù)據(jù)庫或運行存儲過程)以及復雜的大量用例(例如在數(shù)據(jù)庫之間移動大量數(shù)據(jù)少漆,轉(zhuǎn)換它等等) 上)臼膏。大批量批處理作業(yè)可以高度可擴展的方式利用該框架來處理大量信息。

Spring Batch架構(gòu)介紹

一個典型的批處理應用程序大致如下:

? ? ? ?從數(shù)據(jù)庫示损,文件或隊列中讀取大量記錄渗磅。

? ? ? ?以某種方式處理數(shù)據(jù)。

? ? ? ?以修改之后的形式寫回數(shù)據(jù)。

其對應的示意圖如下:

spring batch的一個總體的架構(gòu)如下:?

在spring batch中一個job可以定義很多的步驟step始鱼,在每一個step里面可以定義其專屬的ItemReader用于讀取數(shù)據(jù)仔掸,ItemProcesseor用于處理數(shù)據(jù),ItemWriter用于寫數(shù)據(jù)医清,而每一個定義的job則都在JobRepository里面起暮,我們可以通過JobLauncher來啟動某一個job。

Spring Batch核心概念介紹

下面是一些概念是Spring batch框架中的核心概念会烙。

什么是Job

Job和Step是spring batch執(zhí)行批處理任務最為核心的兩個概念负懦。

其中Job是一個封裝整個批處理過程的一個概念。Job在spring batch的體系當中只是一個最頂層的一個抽象概念柏腻,體現(xiàn)在代碼當中則它只是一個最上層的接口纸厉,其代碼如下:

在Job這個接口當中定義了五個方法,它的實現(xiàn)類主要有兩種類型的job五嫂,一個是simplejob颗品,另一個是flowjob。在spring batch當中沃缘,job是最頂層的抽象抛猫,除job之外我們還有JobInstance以及JobExecution這兩個更加底層的抽象。

一個job是我們運行的基本單位孩灯,它內(nèi)部由step組成闺金。job本質(zhì)上可以看成step的一個容器。一個job可以按照指定的邏輯順序組合step峰档,并提供了我們給所有step設置相同屬性的方法败匹,例如一些事件監(jiān)聽,跳過策略讥巡。

Spring Batch以SimpleJob類的形式提供了Job接口的默認簡單實現(xiàn)掀亩,它在Job之上創(chuàng)建了一些標準功能。一個使用java config的例子代碼如下:

這個配置的意思是:首先給這個job起了一個名字叫footballJob欢顷,接著指定了這個job的三個step槽棍,他們分別由方法,playerLoad,gameLoad, playerSummarization實現(xiàn)抬驴。

什么是JobInstance

我們在上文已經(jīng)提到了JobInstance炼七,他是Job的更加底層的一個抽象,他的定義如下:

他的方法很簡單布持,一個是返回Job的id豌拙,另一個是返回Job的名字。

JobInstance指的是job運行當中题暖,作業(yè)執(zhí)行過程當中的概念按傅。Instance本就是實例的意思捉超。

比如說現(xiàn)在有一個批處理的job,它的功能是在一天結(jié)束時執(zhí)行行一次唯绍。我們假定這個批處理job的名字為'EndOfDay'拼岳。在這個情況下,那么每天就會有一個邏輯意義上的JobInstance, 而我們必須記錄job的每次運行的情況况芒。

什么是JobParameters

在上文當中我們提到了惜纸,同一個job每天運行一次的話,那么每天都有一個jobIntsance牛柒,但他們的job定義都是一樣的,那么我們怎么來區(qū)別一個job的不同jobinstance了痊乾。不妨先做個猜想皮壁,雖然jobinstance的job定義一樣,但是他們有的東西就不一樣哪审,例如運行時間蛾魄。

spring batch中提供的用來標識一個jobinstance的東西是:JobParameters。JobParameters對象包含一組用于啟動批處理作業(yè)的參數(shù)湿滓,它可以在運行期間用于識別或甚至用作參考數(shù)據(jù)滴须。我們假設的運行時間,就可以作為一個JobParameters叽奥。

例如, 我們前面的'EndOfDay'的job現(xiàn)在已經(jīng)有了兩個實例扔水,一個產(chǎn)生于1月1日,另一個產(chǎn)生于1月2日朝氓,那么我們就可以定義兩個JobParameter對象:一個的參數(shù)是01-01, 另一個的參數(shù)是01-02魔市。因此,識別一個JobInstance的方法可以定義為:

因此赵哲,我么可以通過Jobparameter來操作正確的JobInstance

什么是JobExecution

JobExecution指的是單次嘗試運行一個我們定義好的Job的代碼層面的概念待德。job的一次執(zhí)行可能以失敗也可能成功。只有當執(zhí)行成功完成時枫夺,給定的與執(zhí)行相對應的JobInstance才也被視為完成将宪。

還是以前面描述的EndOfDay的job作為示例,假設第一次運行01-01-2019的JobInstance結(jié)果是失敗橡庞。那么此時如果使用與第一次運行相同的Jobparameter參數(shù)(即01-01-2019)作業(yè)參數(shù)再次運行较坛,那么就會創(chuàng)建一個對應于之前jobInstance的一個新的JobExecution實例,JobInstance仍然只有一個。

JobExecution的接口定義如下:

每一個方法的注釋已經(jīng)解釋的很清楚扒最,這里不再多做解釋燎潮。只提一下BatchStatus,JobExecution當中提供了一個方法getBatchStatus用于獲取一個job某一次特地執(zhí)行的一個狀態(tài)扼倘。BatchStatus是一個代表job狀態(tài)的枚舉類确封,其定義如下:

這些屬性對于一個job的執(zhí)行來說是非常關(guān)鍵的信息除呵,并且spring batch會將他們持久到數(shù)據(jù)庫當中. 在使用Spring batch的過程當中spring batch會自動創(chuàng)建一些表用于存儲一些job相關(guān)的信息,用于存儲JobExecution的表為batch_job_execution,下面是一個從數(shù)據(jù)庫當中截圖的實例:

什么是Step

每一個Step對象都封裝了批處理作業(yè)的一個獨立的階段爪喘。事實上颜曾,每一個Job本質(zhì)上都是由一個或多個步驟組成。每一個step包含定義和控制實際批處理所需的所有信息秉剑。任何特定的內(nèi)容都由編寫Job的開發(fā)人員自行決定泛豪。

一個step可以非常簡單也可以非常復雜。例如侦鹏,一個step的功能是將文件中的數(shù)據(jù)加載到數(shù)據(jù)庫中诡曙,那么基于現(xiàn)在spring batch的支持則幾乎不需要寫代碼。更復雜的step可能具有復雜的業(yè)務邏輯略水,這些邏輯作為處理的一部分价卤。

與Job一樣,Step具有與JobExecution類似的StepExecution渊涝,如下圖所示:

什么是StepExecution

StepExecution表示一次執(zhí)行Step, 每次運行一個Step時都會創(chuàng)建一個新的StepExecution慎璧,類似于JobExecution。但是跨释,某個步驟可能由于其之前的步驟失敗而無法執(zhí)行胸私。且僅當Step實際啟動時才會創(chuàng)建StepExecution。

一次step執(zhí)行的實例由StepExecution類的對象表示鳖谈。每個StepExecution都包含對其相應步驟的引用以及JobExecution和事務相關(guān)的數(shù)據(jù)岁疼,例如提交和回滾計數(shù)以及開始和結(jié)束時間。

此外缆娃,每個步驟執(zhí)行都包含一個ExecutionContext五续,其中包含開發(fā)人員需要在批處理運行中保留的任何數(shù)據(jù),例如重新啟動所需的統(tǒng)計信息或狀態(tài)信息龄恋。下面是一個從數(shù)據(jù)庫當中截圖的實例:

什么是ExecutionContext

ExecutionContext即每一個StepExecution 的執(zhí)行環(huán)境疙驾。它包含一系列的鍵值對。我們可以用如下代碼獲取ExecutionContext

什么是JobRepository

JobRepository是一個用于將上述job郭毕,step等概念進行持久化的一個類它碎。它同時給Job和Step以及下文會提到的JobLauncher實現(xiàn)提供CRUD操作。

首次啟動Job時显押,將從repository中獲取JobExecution扳肛,并且在執(zhí)行批處理的過程中,StepExecution和JobExecution將被存儲到repository當中乘碑。

@EnableBatchProcessing注解可以為JobRepository提供自動配置挖息。

什么是JobLauncher

JobLauncher這個接口的功能非常簡單,它是用于啟動指定了JobParameters的Job兽肤,為什么這里要強調(diào)指定了JobParameter套腹,原因其實我們在前面已經(jīng)提到了绪抛,jobparameter和job一起才能組成一次job的執(zhí)行。下面是代碼實例:

上面run方法實現(xiàn)的功能是根據(jù)傳入的job以及jobparamaters從JobRepository獲取一個JobExecution并執(zhí)行Job电禀。

什么是Item Reader

ItemReader是一個讀數(shù)據(jù)的抽象幢码,它的功能是為每一個Step提供數(shù)據(jù)輸入。當ItemReader以及讀完所有數(shù)據(jù)時尖飞,它會返回null來告訴后續(xù)操作數(shù)據(jù)已經(jīng)讀完症副。Spring Batch為ItemReader提供了非常多的有用的實現(xiàn)類,比如JdbcPagingItemReader政基,JdbcCursorItemReader等等贞铣。

ItemReader支持的讀入的數(shù)據(jù)源也是非常豐富的,包括各種類型的數(shù)據(jù)庫沮明,文件辕坝,數(shù)據(jù)流,等等珊擂。幾乎涵蓋了我們的所有場景圣勒。

下面是一個JdbcPagingItemReader的例子代碼:

JdbcPagingItemReader必須指定一個PagingQueryProvider费变,負責提供SQL查詢語句來按分頁返回數(shù)據(jù)摧扇。

下面是一個JdbcCursorItemReader的例子代碼:

什么是Item Writer

既然ItemReader是讀數(shù)據(jù)的一個抽象,那么ItemWriter自然就是一個寫數(shù)據(jù)的抽象挚歧,它是為每一個step提供數(shù)據(jù)寫出的功能扛稽。寫的單位是可以配置的,我們可以一次寫一條數(shù)據(jù)滑负,也可以一次寫一個chunk的數(shù)據(jù)在张,關(guān)于chunk下文會有專門的介紹。ItemWriter對于讀入的數(shù)據(jù)是不能做任何操作的矮慕。

Spring Batch為ItemWriter也提供了非常多的有用的實現(xiàn)類帮匾,當然我們也可以去實現(xiàn)自己的writer功能。

什么是Item Processor

ItemProcessor對項目的業(yè)務邏輯處理的一個抽象, 當ItemReader讀取到一條記錄之后痴鳄,ItemWriter還未寫入這條記錄之前瘟斜,I我們可以借助temProcessor提供一個處理業(yè)務邏輯的功能,并對數(shù)據(jù)進行相應操作痪寻。如果我們在ItemProcessor發(fā)現(xiàn)一條數(shù)據(jù)不應該被寫入螺句,可以通過返回null來表示。ItemProcessor和ItemReader以及ItemWriter可以非常好的結(jié)合在一起工作橡类,他們之間的數(shù)據(jù)傳輸也非常方便蛇尚。我們直接使用即可。

chunk 處理流程

spring batch提供了讓我們按照chunk處理數(shù)據(jù)的能力顾画,一個chunk的示意圖如下:

它的意思就和圖示的一樣取劫,由于我們一次batch的任務可能會有很多的數(shù)據(jù)讀寫操作匆笤,因此一條一條的處理并向數(shù)據(jù)庫提交的話效率不會很高,因此spring batch提供了chunk這個概念勇凭,我們可以設定一個chunk size疚膊,spring batch 將一條一條處理數(shù)據(jù),但不提交到數(shù)據(jù)庫虾标,只有當處理的數(shù)據(jù)數(shù)量達到chunk size設定的值得時候寓盗,才一起去commit.

java的實例定義代碼如下:

在上面這個step里面,chunk size被設為了10璧函,當ItemReader讀的數(shù)據(jù)數(shù)量達到10的時候傀蚌,這一批次的數(shù)據(jù)就一起被傳到itemWriter,同時transaction被提交蘸吓。

skip策略和失敗處理

一個batch的job的step善炫,可能會處理非常大數(shù)量的數(shù)據(jù),難免會遇到出錯的情況库继,出錯的情況雖出現(xiàn)的概率較小箩艺,但是我們不得不考慮這些情況,因為我們做數(shù)據(jù)遷移最重要的是要保證數(shù)據(jù)的最終一致性宪萄。spring batch當然也考慮到了這種情況艺谆,并且為我們提供了相關(guān)的技術(shù)支持,請看如下bean的配置:

我們需要留意這三個方法拜英,分別是skipLimit(),skip(),noSkip(),

skipLimit方法的意思是我們可以設定一個我們允許的這個step可以跳過的異常數(shù)量静汤,假如我們設定為10,則當這個step運行時居凶,只要出現(xiàn)的異常數(shù)目不超過10虫给,整個step都不會fail。注意侠碧,若不設定skipLimit抹估,則其默認值是0.

skip方法我們可以指定我們可以跳過的異常,因為有些異常的出現(xiàn)弄兜,我們是可以忽略的药蜻。

noSkip方法的意思則是指出現(xiàn)這個異常我們不想跳過,也就是從skip的所以exception當中排除這個exception挨队,從上面的例子來說谷暮,也就是跳過所有除FileNotFoundException的exception。

那么對于這個step來說盛垦,F(xiàn)ileNotFoundException就是一個fatal的exception湿弦,拋出這個exception的時候step就會直接fail

批處理操作指南

本部分是一些使用spring batch時的值得注意的點

批處理原則

在構(gòu)建批處理解決方案時,應考慮以下關(guān)鍵原則和注意事項腾夯。

? ? ? ?批處理體系結(jié)構(gòu)通常會影響體系結(jié)構(gòu)

? ? ? ?盡可能簡化并避免在單批應用程序中構(gòu)建復雜的邏輯結(jié)構(gòu)

? ? ? ?保持數(shù)據(jù)的處理和存儲在物理上靠得很近(換句話說颊埃,將數(shù)據(jù)保存在處理過程中)蔬充。

? ? ? ?最大限度地減少系統(tǒng)資源的使用,尤其是I / O. 在internal memory中執(zhí)行盡可能多的操作班利。

? ? ? ?查看應用程序I / O(分析SQL語句)以確保避免不必要的物理I / O. 特別是饥漫,需要尋找以下四個常見缺陷:

? ? ? ? ? ? ? ?當數(shù)據(jù)可以被讀取一次并緩存或保存在工作存儲中時,讀取每個事務的數(shù)據(jù)罗标。

? ? ? ? ? ? ? ?重新讀取先前在同一事務中讀取數(shù)據(jù)的事務的數(shù)據(jù)庸队。

? ? ? ? ? ? ? ?導致不必要的表或索引掃描。

? ? ? ? ? ? ? ?未在SQL語句的WHERE子句中指定鍵值闯割。

? ? ? ? 在批處理運行中不要做兩次一樣的事情彻消。例如,如果需要數(shù)據(jù)匯總以用于報告目的宙拉,則應該(如果可能)在最初處理數(shù)據(jù)時遞增存儲的總計宾尚,因此您的報告應用程序不必重新處理相同的數(shù)據(jù)。

? ? ? ? 在批處理應用程序開始時分配足夠的內(nèi)存谢澈,以避免在此過程中進行耗時的重新分配煌贴。

? ? ? ? 總是假設數(shù)據(jù)完整性最差。插入適當?shù)臋z查和記錄驗證以維護數(shù)據(jù)完整性锥忿。

? ? ? ? 盡可能實施校驗和以進行內(nèi)部驗證牛郑。例如,對于一個文件里的數(shù)據(jù)應該有一個數(shù)據(jù)條數(shù)紀錄缎谷,告 訴文件中的記錄總數(shù)以及關(guān)鍵字段的匯總井濒。

? ? ? ? 在具有真實數(shù)據(jù)量的類似生產(chǎn)環(huán)境中盡早計劃和執(zhí)行壓力測試灶似。

? ? ? ? 在大批量系統(tǒng)中列林,數(shù)據(jù)備份可能具有挑戰(zhàn)性,特別是如果系統(tǒng)以24-7在線的情況運行酪惭。數(shù)據(jù)庫備份通常在在線設計中得到很好的處理希痴,但文件備份應該被視為同樣重要。如果系統(tǒng)依賴于文件春感,則文件備份過程不僅應該到位并記錄在案砌创,還應定期進行測試。

如何默認不啟動job

在使用java config使用spring batch的job時鲫懒,如果不做任何配置嫩实,項目在啟動時就會默認去跑我們定義好的批處理job。那么如何讓項目在啟動時不自動去跑job呢窥岩?

spring batch的job會在項目啟動時自動run甲献,如果我們不想讓他在啟動時run的話,可以在application.properties中添加如下屬性:

在讀數(shù)據(jù)時內(nèi)存不夠

在使用spring batch做數(shù)據(jù)遷移時颂翼,發(fā)現(xiàn)在job啟動后晃洒,執(zhí)行到一定時間點時就卡在一個地方不動了慨灭,且log也不再打印,等待一段時間之后球及,得到如下錯誤:

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末氧骤,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子吃引,更是在濱河造成了極大的恐慌筹陵,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件镊尺,死亡現(xiàn)場離奇詭異惶翻,居然都是意外死亡,警方通過查閱死者的電腦和手機鹅心,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進店門吕粗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人旭愧,你說我怎么就攤上這事颅筋。” “怎么了输枯?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵议泵,是天一觀的道長。 經(jīng)常有香客問我桃熄,道長先口,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任瞳收,我火速辦了婚禮碉京,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘螟深。我一直安慰自己谐宙,他們只是感情好,可當我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般觅玻。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上划栓,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天,我揣著相機與錄音条获,去河邊找鬼忠荞。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的钻洒。 我是一名探鬼主播奋姿,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼素标!你這毒婦竟也來了称诗?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤头遭,失蹤者是張志新(化名)和其女友劉穎寓免,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體计维,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡袜香,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了鲫惶。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蜈首。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖欠母,靈堂內(nèi)的尸體忽然破棺而出欢策,到底是詐尸還是另有隱情,我是刑警寧澤赏淌,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布踩寇,位于F島的核電站,受9級特大地震影響六水,放射性物質(zhì)發(fā)生泄漏俺孙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一掷贾、第九天 我趴在偏房一處隱蔽的房頂上張望睛榄。 院中可真熱鬧,春花似錦胯盯、人聲如沸懈费。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至票罐,卻和暖如春叉趣,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背该押。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工疗杉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓烟具,卻偏偏與公主長得像梢什,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子朝聋,可洞房花燭夜當晚...
    茶點故事閱讀 44,933評論 2 355

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