批量系統設計之禪

weixin_34146805發表於2017-12-01

之前寫過關於基於SpringBatch框架來實現批量的文章,有些同學反應希望寫寫關於批量設計的文章,畢竟筆者以前也在國有大銀行寫過3年的後臺OLAP批量系統,在批量程式方面還是掉過很多坑,同時也學到了很多批量優化方面的經驗,本篇文章就是總結了我自己批量的經驗和原先行裡總結的一些批量設計經驗,以前我們批量都是使用大量的儲存過程來實現功能,使用儲存過程的問題就在於擴充套件性非常差,對某個資料庫的依賴非常高,工作中會遇到各種因為資料庫產品導致的bug,對程式設計師SQL要求非常高,優秀的SQL和爛SQL效能可能會差幾十倍,所以目前除了一些傳統公司還在使用老式的儲存過程來實現批量,大部分網際網路公司的批量都已經改為使用一些類似Springbatch的框架,通過這樣的框架可以減少很多開發工作,而且對於一般能夠寫java的同學都可以去寫批量了,但是做聯機和做批量在設計思想上還是有很大差別,本文就給大家梳理下批量設計思路。文章開頭說下批量的設計核心思想就是“減少IO”,這是所有批量系統優化效能的核心思路,做批量的同學請牢記這一條!!!

1. 批量系統使用場景

  • 定期提交批處理任務
  • 併發批處理:並行執行任務
  • 分階段,企業訊息驅動處理
  • 高併發批處理任務
  • 失敗後手動或定時重啟
  • 按順序處理任務依賴(使用工作流驅動的批處理外掛)
  • 區域性處理:跳過記錄(例如在回滾時)
  • 完整的批處理事務:因為可能有小資料量的批處理或存在儲存過程/指令碼

2. 批量設計原則

  • 批處理架構通常會影響線上服務的架構,反之亦然。設計架構和環境時請儘可能將聯機資料資源和批量資料資源分開。
  • 儘可能的簡化,避免在單個批處理應用中構建複雜的邏輯結構。
  • 儘可能在資料存放的地方處理這些資料,反之亦然(即各自負責處理自己的資料)。
  • 儘可能少的使用系統資源,尤其是I/O。儘可能多地在記憶體中執行大部分操作。
  • 審查應用程式I/O(分析SQL語句)以避免不必要的物理I/O。特別是以下四個常見的缺陷需要避免:
    • 在每個事務中都將(所有並不需要的)資料讀取,並快取起來;
    • 多次讀取/查詢同一事務中已經讀取過的資料;
    • 引起不必要的表或索引掃描;
    • 在SQL語句的WHERE子句中不指定過濾條件。
  • 在同一個批處理不要做兩次一樣的事。例如,如果你需要報表的資料彙總,請在處理每一條記錄時使用增量來儲存,儘可能不要再去遍歷一次同樣的資料。
  • 在批處理程式開始時就分配足夠的記憶體,以避免執行過程中再執行耗時的記憶體分配。
  • 總是將資料完整性假定為最壞情況。插入適當的檢查和資料校驗以保持資料完整性(integrity)。
  • 如有可能,請為內部校驗實現checksum。例如,平面檔案應該有一條結尾記錄,說明檔案中的總記錄數和關鍵欄位的集合。
  • 儘可能早地在模擬生產環境下使用真實的資料量,進行計劃和執行壓力測試。
  • 在大型批處理系統中,備份會是一個很大的挑戰,特別是 7x24小時不間斷的線上服務系統。資料庫備份通常在設計時就考慮好了,但是檔案備份也應該提升到同養的重要程度。如果系統依賴於文字檔案,檔案備份程式不僅要正確設定和形成文件,還要定期進行測試。

3. 批量設計策略

為了輔助批處理系統的設計和實現、應該通過結構示意圖和程式碼例項的形式為設計師和程式設計師提供基礎的批處理程式構建模組和以及處理模式. 在設計批處理Job時,應該將業務邏輯分解成一系列的步驟,使每個步驟都可以利用以下的標準構建模組來實現:

  • 轉換程式(Conversion Applications): 由外部系統提供或需要寫入到外部系統的各種型別的檔案,我們都需要為其建立一個
  • 轉換程式, 用來將所提供的事務記錄轉換成符合要求的標準格式.這種型別的批處理程式可以部分或全部由轉換工具模組
  • 驗證程式(Validation Applications): 驗證程式確保所有輸入/輸出記錄都是正確和一致的.驗證通常基於檔案頭和結尾資訊,
  • 校驗和(checksums)以及記錄級別的交叉驗證演算法.
  • 提取程式(Extract Applications): 這種程式從資料庫或輸入檔案讀取一堆記錄,根據預定義的規則選取記錄,並將選取的記錄
  • 寫入到輸出檔案.
  • 提取/更新程式(Extract/Update Applications): 這種程式從資料庫或輸入檔案讀取記錄,並將輸入的每條記錄都更新到資料庫或記錄到輸出檔案.
  • 處理和更新程式(Processing and Updating Applications): 這種程式對從 提取或驗證程式 傳過來的輸入事務記錄進行處理.這些處理通常包括 從資料庫讀取資料,有可能更新資料庫,並建立輸出記錄.
  • 輸出/格式化程式(Output/Format Applications): 這種程式從輸入檔案中讀取資訊,將資料重組成為標準格式,並列印到輸出檔案,或者傳輸給另一個程式或系統.

因為業務邏輯不能用上面介紹的這些標準模組來完成, 所以還需要另外提供一個基本的程式外殼.

除了這些主要的模組,每個應用還可以使用一到多個標準的實用程式環節(standard utility steps),如:

  • Sort 排序,排序程式從輸入檔案讀取記錄,並根據記錄中的某個key欄位重新排序,然後生成輸出檔案. 排序通常由標準的系統實用程式來執行.
  • Split 拆分,拆分程式從單個輸入檔案中讀取記錄,根據某個欄位的值,將記錄寫入到不同的輸出檔案中. 拆分可以自定義或者由引數驅動的(parameter-driven)系統實用程式來執行.
  • Merge 合併,合併程式從多個輸入檔案讀取記錄,並將組合後的資料寫入到單個輸出檔案中. 合併可以自定義或者由引數驅動的(parameter-driven)系統實用程式來執行.

批處理程式也可以根據輸入來源分類:

  • 資料庫驅動(Database-driven)的應用程式, 由從資料庫中獲取的行或值驅動.
  • 檔案驅動(File-driven)的應用程式,是由從檔案中獲取的值或記錄驅動的.
  • 訊息驅動(Message-driven)的應用程式由從訊息佇列中檢索到的訊息驅動.

所有批處理系統的基礎都是處理策略.影響策略選擇的因素包括: 預估的批處理系統容量, 線上併發或與另一個批處理系統的併發量, 可用的批處理時間視窗(隨著越來越多的企業想要全天候(7x24小時)運轉,所以基本上沒有明確的批處理視窗).

典型的批處理選項包括:

  • 在一個批處理視窗中執行常規離線批處理
  • 併發批處理/線上處理
  • 同一時刻有許多不同的批處理在並行執行
  • 分割槽(即同一時刻,有多個例項在處理同一個job)
  • 上面這些的組合

上面列表中的順序代表了批處理實現複雜性的排序,在同一個批處理視窗的處理最簡單,而分割槽實現最複雜,分割槽實現雖然併發效能高能夠充分利用IO資源,但是缺點是對資料結構設計和批量設計要求很高,弄不好就會出很多多執行緒或資源死鎖問題導致批量加工資料錯誤或中斷,所以如果資料量不是非常巨大就不要用分割槽批量實現方案了,當你資料量足夠大了,並且自己已經能力提高並能夠充分理解批量精髓後,自然就會靈活使用批量分割槽實現方案了.

總結

本文主要是從各個角度講訴了下批量設計的思路,真的只是思路,估計很多同學看完了很多條tips都不知道在說啥或者不知道如何實踐,如果具體展開講這些tips要寫太多字了,本人比較懶不想寫了,如果感興趣的人比較多後續可能會對於大家感興趣的一些tips展開講講後面的故事。

相關文章