概述
本文是Spring Cloud Task系列的第四篇文章,如果你尚未使用過Spring Cloud Task,請(qǐng) 移步spring cloud task1 簡(jiǎn)介與示例坊谁。
本文主要講述的是Spring的另一個(gè)核心子項(xiàng)目 Spring Batch,一個(gè)輕量級(jí)的綜合的批處理框架柄粹∏蕉框架主要為規(guī)范、簡(jiǎn)化企業(yè)級(jí)具有健壯性要求的重要日常任務(wù)盈罐。
Spring Batch為大批量數(shù)據(jù)處理提供很多可重用的核心組件榜跌,包括日志、追蹤盅粪、事務(wù)管理钓葫、任務(wù)處理分析、任務(wù)重啟票顾、跳讀以及資源管理器础浮。另外它還提供了更為先進(jìn)的技術(shù)服務(wù)與特性,如通過最優(yōu)和分區(qū)技術(shù)來支持超大規(guī)模數(shù)據(jù)的高性能批處理奠骄《雇總之,無論是簡(jiǎn)單的含鳞,還是復(fù)雜的大數(shù)據(jù)量的處理任務(wù)影锈,都可以利用該框架為信息處理提供可擴(kuò)展的支持。
Spring Batch有以下特性:
- 事務(wù)管理器
- 任務(wù)塊處理
- 聲明式I/O
- Start/Stop/Restart狀態(tài)控制
- Retry/Skip 任務(wù)重試與跳過
- 管理員web操作接口(需要依賴Spring Cloud Data Flow)
詳情
在企業(yè)級(jí)應(yīng)用中許多關(guān)鍵任務(wù)都需要批處理操作,需求大致可以分為如下幾類:
- 自動(dòng)化對(duì)大批量數(shù)據(jù)進(jìn)行復(fù)雜處理鸭廷。這些任務(wù)大部分都是基于時(shí)間事件驅(qū)動(dòng)的無人值守任務(wù)(如月度統(tǒng)計(jì)枣抱、通知、通信任務(wù))辆床。
- 在超大數(shù)據(jù)集合中進(jìn)行周期性重復(fù)的業(yè)務(wù)邏輯(比如借款利率計(jì)算)沃但。
- 對(duì)內(nèi)部或外部系統(tǒng)進(jìn)行消息集成,通常還需要在一個(gè)事務(wù)管理器中完成格式化佛吓、驗(yàn)證以及處理并存儲(chǔ)幾率宵晚。批處理應(yīng)用可以每天為企業(yè)處理數(shù)以億計(jì)的數(shù)據(jù)。
Spring Batch繼承了Spring框架的設(shè)計(jì)理念维雇,強(qiáng)調(diào)基于POJO的開發(fā)方式并且促進(jìn)創(chuàng)建可維護(hù)淤刃、可測(cè)試的代碼。在功能設(shè)計(jì)上它利用調(diào)度框架(如Quartz)工作吱型,并非是一個(gè)調(diào)度框架逸贾。
Spring Batch提供了很多用于支持大批量數(shù)據(jù)處理的功能,例如失敗后的重試津滞、跳過記錄铝侵、從最后一次失敗的位置重新開始工作、定期批量的提交給事務(wù)型數(shù)據(jù)庫(kù)触徐、可重用的組件(如解析器咪鲜、映射器、讀取器撞鹉、處理器疟丙、寫入器和校驗(yàn)器)以及工作流定義。
使用場(chǎng)景
下面是幾個(gè)典型的批處理程序的使用場(chǎng)景:
- 需要從數(shù)據(jù)庫(kù)鸟雏、文件或隊(duì)列中讀取大批量的數(shù)據(jù)
- 以數(shù)據(jù)流的方式處理數(shù)據(jù)
- 以修改的形式回寫數(shù)據(jù)
Spring Batch 能夠自動(dòng)完成上述基礎(chǔ)批處理迭代享郊,并將類似的事務(wù)抽象成一個(gè)集合視角來處理,故而其典型應(yīng)用場(chǎng)景就是無人值守的批處理孝鹊。
Spring Batch是一個(gè)完全開源的框架炊琉,它提供了穩(wěn)定的企業(yè)級(jí)批處理任務(wù)的解決方案,尤其適用于以下業(yè)務(wù)場(chǎng)景又活。
- 周期性提交的批處理任務(wù)
- 并行批處理
- 消息過程驅(qū)動(dòng)任務(wù)處理
- 超大規(guī)模并行批處理
- 失敗后手動(dòng)或自動(dòng)重啟任務(wù)
- 支持任務(wù)工作流苔咪,按照指定步驟執(zhí)行任務(wù)
- 任務(wù)分批機(jī)制和任務(wù)跳過功能
- 事務(wù)支持
技術(shù)目標(biāo)
- 使用Spring的編程模型,開發(fā)者只需集中精力關(guān)心業(yè)務(wù)邏輯的研發(fā)皇钞,所有的基礎(chǔ)設(shè)施的操作都完全交由框架來管理悼泌。
- 使基礎(chǔ)架構(gòu)設(shè)施,軟件執(zhí)行環(huán)境和批處理應(yīng)用之間完全分離夹界。
- 以接口的方式提供公共核心服務(wù)的功能馆里,業(yè)務(wù)系統(tǒng)可以根據(jù)需要實(shí)現(xiàn)所需的組件隘世。
- 提供公共核心服務(wù)接口的簡(jiǎn)單默認(rèn)實(shí)現(xiàn),整個(gè)框架開箱可用
- 借助于Spring框架鸠踪,可以很方便的完成框架的配置丙者,定制化以及繼承服務(wù)。
- 所有核心服務(wù)都應(yīng)該在不影響基礎(chǔ)層的情況下能夠被替換和繼承
架構(gòu)設(shè)計(jì)
Spring Batch在設(shè)計(jì)時(shí)充分考慮的不同類型的用戶需求营密,重視框架的可擴(kuò)展性械媒。其設(shè)計(jì)上的分層架構(gòu)如下圖所示。
Spring Batch的分層架構(gòu)將系統(tǒng)分為應(yīng)用層评汰,核心層和基礎(chǔ)組組件層纷捞。
應(yīng)用層包含所有批處理任務(wù)以及開發(fā)者使用Spring Batch編寫的其它代碼。
核心層提供運(yùn)行與管理批處理任務(wù)的能力被去。主要有 JobLauncher
,Job
以及Step
接口的實(shí)現(xiàn)類組成主儡。
應(yīng)用層和核心層都依賴于公共基礎(chǔ)層〔依拢基礎(chǔ)層由公共的輸入reader糜值、輸出writer以及服務(wù)service。
通用批處理程序參考指南
在設(shè)計(jì)批處理應(yīng)用時(shí)坯墨,我們應(yīng)慎重思考以下幾點(diǎn)寂汇。
- 在同時(shí)具有批處理和實(shí)時(shí)處理的環(huán)境中,最好使用數(shù)據(jù)塊來作為整體操作對(duì)象捣染,因?yàn)榕幚砑軜?gòu)和實(shí)時(shí)處理架構(gòu)會(huì)相互影響骄瓣。
- 拒絕在單一批處理應(yīng)用中使用復(fù)雜的邏輯結(jié)構(gòu),在設(shè)計(jì)應(yīng)用時(shí)一定要遵守簡(jiǎn)單至上的原則液斜。
- 保證在進(jìn)行數(shù)據(jù)處理時(shí)有備份數(shù)據(jù)
- 盡量減少系統(tǒng)資源占用累贤,特別是應(yīng)該大量使用內(nèi)存計(jì)算以減少I/O操作。
- 應(yīng)謹(jǐn)慎檢查應(yīng)用的I/O操作來確保應(yīng)用沒有非必要的I/O(可通過分析SQL語(yǔ)句等方式)少漆,特別應(yīng)仔細(xì)檢查是否存在以下四種缺陷:1. 當(dāng)可以一次性讀取到所有數(shù)據(jù),緩存在應(yīng)用中時(shí)硼被,卻在每個(gè)事務(wù)里都從物理磁盤讀取相關(guān)數(shù)據(jù)示损。2.在同一個(gè)事務(wù)中重復(fù)讀取數(shù)據(jù)。3.不必要的表或索引掃描嚷硫。4.在where子句中使用非精確查找检访。
- 必要情況下對(duì)計(jì)算的臨時(shí)結(jié)果值進(jìn)行存儲(chǔ),不要重復(fù)的進(jìn)行相同的計(jì)算仔掸。
- 在批處理應(yīng)用開始時(shí)就申請(qǐng)足夠的內(nèi)存空間脆贵,避免隨著時(shí)間的增加不斷的申請(qǐng)更多的內(nèi)存空間。
- 適當(dāng)?shù)臋z查與記錄校驗(yàn)以保證數(shù)據(jù)的完整性起暮。
- 進(jìn)行周期性的校驗(yàn)卖氨。例如在文件持續(xù)變動(dòng)的場(chǎng)景下,需要從末尾計(jì)算總記錄數(shù)以及對(duì)關(guān)鍵字進(jìn)行聚合統(tǒng)計(jì)。
- 盡早的在與接近真實(shí)環(huán)境的條件下使用真實(shí)的數(shù)據(jù)進(jìn)行壓力測(cè)試筒捺。
- 在7*24小時(shí)高可用的大批量數(shù)據(jù)處理系統(tǒng)中柏腻,數(shù)據(jù)備份是一項(xiàng)有挑戰(zhàn)性的工作。運(yùn)維都通常能設(shè)計(jì)好在線數(shù)據(jù)庫(kù)的備份系吭,同樣重要文件的備份其實(shí)并不是那么容易操作五嫂。如果項(xiàng)目依賴于可變動(dòng)的文件,那么文件的備份不但要關(guān)心適當(dāng)?shù)奈恢煤臀臋n化肯尺,還應(yīng)該定期的進(jìn)行測(cè)試沃缘。
批處理策略
為了更好的設(shè)計(jì)和實(shí)現(xiàn)批處理系統(tǒng),基礎(chǔ)批處理應(yīng)用的的構(gòu)建塊和模式應(yīng)該提供圖表式的框架以及編程接口給設(shè)計(jì)和研發(fā)人員则吟。在設(shè)計(jì)批處理任務(wù)時(shí)槐臀,首重抽象分解階段,業(yè)務(wù)處理邏輯應(yīng)該被分解為一連串的步驟逾滥,每一個(gè)步驟都是一個(gè)行為模塊峰档。具體的步驟設(shè)計(jì)可參考下面的標(biāo)準(zhǔn)行為模塊。
- 轉(zhuǎn)換型模塊:所謂轉(zhuǎn)換主要是在系統(tǒng)需要依賴外部數(shù)據(jù)時(shí)寨昙,將外部數(shù)據(jù)轉(zhuǎn)化為標(biāo)準(zhǔn)的輸入數(shù)據(jù)格式讥巡。在批處理系統(tǒng)中轉(zhuǎn)換模塊完全可以設(shè)計(jì)為公共可抽象的模塊。
- 校驗(yàn)型模塊:校驗(yàn)組件用來確保輸入/輸出紀(jì)錄的正確性以及可持久化舔哪。比較有代表性的校驗(yàn)如文件頭尾格式信息欢顷,行數(shù)校驗(yàn),校驗(yàn)算法以及數(shù)據(jù)紀(jì)錄級(jí)別的反復(fù)核對(duì)捉蚤。
- 選取型應(yīng)用:對(duì)批處理模塊的抽象的核心是精準(zhǔn)定位應(yīng)用的核心功能抬驴。如一個(gè)選取型模塊應(yīng)該做的事是依照預(yù)定義的規(guī)則從文件或數(shù)據(jù)中選取數(shù)據(jù)作為輸入,然后輸出到目標(biāo)位置缆巧。
- 選取/更新型模塊:采用基于數(shù)據(jù)事件驅(qū)動(dòng)的方式從文件或數(shù)據(jù)庫(kù)中讀取數(shù)據(jù)布持,進(jìn)行更改之后將數(shù)據(jù)回寫持久化到數(shù)據(jù)庫(kù)或文件中。
- 數(shù)據(jù)處理與更新模塊:數(shù)據(jù)處理型模塊的輸入事務(wù)源于外部數(shù)據(jù)源或檢驗(yàn)型模塊陕悬。該行為模塊通常包含從數(shù)據(jù)庫(kù)中獲取需要進(jìn)行處理的數(shù)據(jù)题暖,然后更新數(shù)據(jù)庫(kù)或者創(chuàng)建若干新的數(shù)據(jù)。
- 格式化輸出組件:輸出型組件從文件中讀取數(shù)據(jù)捉超,依照標(biāo)準(zhǔn)去更改紀(jì)錄的數(shù)據(jù)結(jié)構(gòu)后胧卤,將數(shù)據(jù)輸出到新的文件或者傳輸?shù)狡渌到y(tǒng)中。
然而受復(fù)雜業(yè)務(wù)邏輯的影響拼岳,很多應(yīng)用無法簡(jiǎn)單的由上述標(biāo)準(zhǔn)行為模塊組成枝誊。此時(shí)或許可以嘗試將多個(gè)標(biāo)準(zhǔn)組件組合,以完成業(yè)務(wù)需求惜纸。除了上述標(biāo)準(zhǔn)模塊外叶撒,框架還提供了如下模塊绝骚。
- 排序:從源文件中讀取數(shù)據(jù),并依照指定的字段作為鍵進(jìn)行排序痊乾。
- 切分:從單個(gè)數(shù)據(jù)源中讀出數(shù)據(jù)皮壁,并依據(jù)參數(shù)規(guī)則將每條數(shù)據(jù)拆分輸出到多個(gè)目標(biāo)地點(diǎn)。
- 合并:與切分型模塊功能相反哪审。
根據(jù)不同的數(shù)據(jù)源蛾魄,批處理應(yīng)用可被分為以下三類:
- 數(shù)據(jù)庫(kù)驅(qū)動(dòng)型應(yīng)用:數(shù)據(jù)依賴于由數(shù)據(jù)庫(kù)存儲(chǔ)的紀(jì)錄行或值。
- 文件驅(qū)動(dòng)型應(yīng)用:紀(jì)錄或值存儲(chǔ)在文件中
- 消息驅(qū)動(dòng)型應(yīng)用:數(shù)據(jù)紀(jì)錄由消息隊(duì)列維護(hù)
批處理策略的選擇
上述的批處理策略是批處理系統(tǒng)的基礎(chǔ)湿滓。在選用具體的批處理策略時(shí)要充分考慮很多因素滴须。首先要估算數(shù)據(jù)量的大小,其次是批處理系統(tǒng)要面臨的并發(fā)叽奥,再者還需要考慮系統(tǒng)的可用性要求(業(yè)務(wù)方希望系統(tǒng)7*24小時(shí)可用)扔水。
下面是幾種典型的批處理模式(通常結(jié)合調(diào)度任務(wù)使用):
- 離線普通批處理
- 在線并發(fā)批處理
- 并行運(yùn)行多種批處理任務(wù)
- 分區(qū)批處理(將一個(gè)批處理應(yīng)用部署多個(gè)節(jié)點(diǎn))
- 綜合上述批處理模式
針對(duì)不同的模式,數(shù)據(jù)的提交和鎖定的策略非常重要朝氓,且在設(shè)計(jì)完成整體架構(gòu)之后魔市,批處理模式很難能獨(dú)立更改。鎖策略可以選用數(shù)據(jù)庫(kù)自帶的鎖赵哲,也可以自己自定義繼承框架中的鎖服務(wù)待德。鎖服務(wù)可以根據(jù)數(shù)據(jù)庫(kù)鎖狀態(tài)來判斷是否給予數(shù)據(jù)庫(kù)操作的權(quán)限。根據(jù)鎖服務(wù)的狀態(tài)枫夺,也可以避免自己繼承實(shí)現(xiàn)的重試邏輯的無意義執(zhí)行将宪。
離線普通批處理
在數(shù)據(jù)不被線上客戶修改訪問,沒有并發(fā)處理的需求橡庞,也沒有其它批處理任務(wù)一同對(duì)這些數(shù)據(jù)進(jìn)行更改時(shí)较坛,當(dāng)前任務(wù)處理完成后就可以簡(jiǎn)單的對(duì)結(jié)果進(jìn)行提交。
誠(chéng)然最簡(jiǎn)單的邏輯是最有效的扒最。但是隨著時(shí)間的發(fā)展和產(chǎn)品迭代丑勤,要處理的數(shù)據(jù)關(guān)系會(huì)愈加復(fù)雜,數(shù)據(jù)量也會(huì)變得越來越大吧趣。如果沒有設(shè)計(jì)鎖服務(wù)确封,此時(shí)批處理模型的數(shù)據(jù)單次提交邏輯就顯得相形見絀。
實(shí)時(shí)并發(fā)批處理
實(shí)時(shí)并發(fā)批處理程序需要同時(shí)滿足多個(gè)并發(fā)請(qǐng)求再菊,且任務(wù)處理可能占用數(shù)秒時(shí)間,任務(wù)結(jié)束后還需要在同一事物中提交數(shù)據(jù)颜曾,故而并發(fā)批處理不應(yīng)該鎖定任何數(shù)據(jù)纠拔。整體鎖定的數(shù)據(jù)越少,數(shù)據(jù)對(duì)于其它進(jìn)程不可用的時(shí)間越少泛豪,整個(gè)系統(tǒng)就越健壯稠诲。
合理選擇樂觀鎖或悲觀鎖來實(shí)現(xiàn)邏輯行級(jí)鎖是減少物理鎖定的好思路侦鹏。下面分別對(duì)樂觀鎖和悲觀鎖進(jìn)行介紹。
樂觀鎖: 適用于數(shù)據(jù)很少發(fā)生鎖競(jìng)爭(zhēng)的情況臀叙。在使用數(shù)據(jù)庫(kù)時(shí)具體實(shí)現(xiàn)方案為在批處理程序需要用到的數(shù)據(jù)表的添加一個(gè)版本號(hào)或者時(shí)間戳字段略水。當(dāng)應(yīng)用讀取數(shù)據(jù)一行數(shù)據(jù)時(shí),同時(shí)也會(huì)讀取到此列劝萤。且當(dāng)應(yīng)用處理完成要更新數(shù)據(jù)時(shí)渊涝,會(huì)將這個(gè)時(shí)間戳或版本作為WHERE子句的條件。如果數(shù)據(jù)庫(kù)中該行當(dāng)前的時(shí)間戳字段與WHERE條件一樣床嫌,這條數(shù)據(jù)才會(huì)被更新跨释。否則的話就意味著這條數(shù)據(jù)已經(jīng)被其它應(yīng)用修改過了,應(yīng)用此時(shí)應(yīng)該去嘗試其它策略厌处。
悲觀鎖: 適用于數(shù)據(jù)會(huì)發(fā)生很多競(jìng)爭(zhēng)的情況鳖谈,在檢索時(shí)需要取得物理或者邏輯鎖。使用數(shù)據(jù)庫(kù)時(shí)可以借助數(shù)據(jù)庫(kù)默認(rèn)的行級(jí)鎖來實(shí)現(xiàn)阔涉。當(dāng)應(yīng)用需要更新數(shù)據(jù)時(shí)缆娃,首先檢索該行并將鎖標(biāo)識(shí)為已鎖定。這時(shí)其它應(yīng)用嘗試檢索相同數(shù)據(jù)時(shí)會(huì)發(fā)生邏輯失敗瑰排。直到應(yīng)用將數(shù)據(jù)更新完成贯要,鎖標(biāo)志才會(huì)被釋放,其它應(yīng)用才能重新獲取數(shù)據(jù)凶伙。使用悲觀鎖有兩點(diǎn)情況需要注意:1.在鎖的鎖定和釋放的時(shí)間范圍內(nèi)郭毕,應(yīng)當(dāng)保證數(shù)據(jù)的完整性。2. 應(yīng)當(dāng)對(duì)鎖設(shè)置超時(shí)機(jī)制函荣。
上述知識(shí)尤其適用于高并發(fā)程序显押。一般情況下,樂觀鎖適用于實(shí)時(shí)處理應(yīng)用傻挂,而互斥鎖在批處理應(yīng)用中能夠大展拳腳乘碑。無論具體使用哪種鎖,其根本目的都是為了保證數(shù)據(jù)的安全金拒。
不過這些鎖只能對(duì)單條數(shù)據(jù)定位鎖定兽肤。當(dāng)需要對(duì)一組數(shù)據(jù)進(jìn)行鎖定時(shí),你所面臨的最大的挑戰(zhàn)是死鎖的發(fā)生绪抛。怎么避免呢资铡?有了邏輯鎖,或許可以再設(shè)計(jì)一個(gè)邏輯鎖管理器幢码,管理器應(yīng)該是一致的笤休、非死鎖的且應(yīng)該能理解你想保護(hù)的數(shù)據(jù)組。邏輯鎖管理器常常有自己的一張自己的表症副,如此便能提供鎖管理店雅、競(jìng)爭(zhēng)報(bào)告政基、超時(shí)機(jī)制以及其它用戶關(guān)注的功能。
并行處理
并行批處理的意思是多個(gè)批處理應(yīng)用或任務(wù)并行工作闹啦,從而減少整體處理時(shí)間沮明。 如果多個(gè)應(yīng)用間沒有共享同一個(gè)文件、數(shù)據(jù)庫(kù)表或者索引空間窍奋,多個(gè)應(yīng)用并行處理荐健,各自只關(guān)注自己的數(shù)據(jù),其間沒有數(shù)據(jù)沖突费变,也不會(huì)發(fā)生什么問題摧扇。當(dāng)應(yīng)用間有共享資源時(shí),一般情況我們會(huì)通過自定義數(shù)據(jù)分片策略來決定每個(gè)應(yīng)用應(yīng)該去處理哪些數(shù)據(jù)挚歧。在這里引入另一個(gè)新思路扛稽,數(shù)據(jù)管理表。數(shù)據(jù)管理表是一個(gè)維護(hù)數(shù)據(jù)相互依賴性的管理模型滑负,它記錄者每行可共享資源以及正在被使用與否在张,如此批處理程序就能知道自己可以訪問哪些共享資源。
解決了數(shù)據(jù)訪問方面的問題矮慕,可以配合使用多線程來實(shí)現(xiàn)對(duì)數(shù)據(jù)的并行處理帮匾。大型機(jī)環(huán)境下CPU資源豐富,能夠保證每個(gè)處理任務(wù)都能分配到足夠的cpu時(shí)間片痴鳄,并行作業(yè)處理技術(shù)也相對(duì)成熟瘟斜。
再者,我們需要考慮并行處理資源的高可用和負(fù)載均衡問題痪寻。這些可能用到的技術(shù)有連接池螺句、緩存等等。最后需要注意橡类,超大的并行處理中數(shù)據(jù)管理表本身可能會(huì)成為資源瓶頸蛇尚。
關(guān)于
示例源碼
Spring Cloud Task learning 的 task-demo-with-datasource 子項(xiàng)目
后記
Spring Cloud Task是一個(gè)優(yōu)秀的項(xiàng)目,但是我找遍網(wǎng)絡(luò)顾画,也難以找出系統(tǒng)的取劫、準(zhǔn)確的中文相關(guān)文檔。本系列文章以保證對(duì)Spring Cloud Task相關(guān)概念和設(shè)計(jì)理解的正確性為標(biāo)準(zhǔn)研侣,盡量采用通俗易懂的語(yǔ)言谱邪,希望能給各位帶來一些便捷。
本文內(nèi)容主要是對(duì) Spring Cloud Task 1.2.2-RELEASE 官方文檔的翻譯庶诡,不過作者水平有限虾标,有不盡然的地方敬請(qǐng)指出。本項(xiàng)目和文檔中所用的內(nèi)容僅供學(xué)習(xí)和研究之用,轉(zhuǎn)載或引用時(shí)請(qǐng)指明出處璧函。如果你對(duì)文檔有疑問或問題,請(qǐng)?jiān)陧?xiàng)目中給我留言或發(fā)email到
weiwei02@vip.qq.com 我的github:
https://github.com/weiwei02/ 我相信技術(shù)能夠改變世界 基显。