批处理最佳做法
大多數應用程序至少具有一個批處理任務,在后臺執行特定的邏輯。 編寫批處理作業并不復雜,但是您需要了解一些基本規則,我將列舉一些我發現最重要的規則。
從輸入類型的角度來看,處理項目可以通過輪詢處理項目存儲庫來實現,也可以通過將它們通過隊列推送到系統中來實現。 下圖顯示了典型批處理系統的三個主要組件:
- 輸入組件(通過輪詢或從輸入隊列加載項目)
- 處理器:主要處理邏輯組件
- 輸出組件:輸出結果的輸出通道或存儲位置
1.始終分批輪詢
您一次只能檢索一批項目。 我最近不得不在嘗試檢索所有可能的項目進行處理時,診斷由計劃作業拋出的OutOfMemoryError。
系統集成測試正使用少量數據,因此通過了,但是由于某些部署問題,當計劃的作業脫機兩天時,由于沒有人消耗它們,因此要處理的項目數已經累積起來。 ,并且當調度程序重新聯機時,由于它們不適合調度程序的內存堆,因此無法使用它們。 因此,僅設置高調度頻率速率是不夠的。
為了避免這種情況,您只需要獲取一批物料,將它們消耗掉即可,然后您可以重新運行該過程,直到沒有剩余要處理的東西為止。
2.編寫線程安全的批處理程序
通常,無論您選擇并行運行多少個作業,計劃作業都應正確運行。 因此,批處理處理器應該是無狀態的,僅使用本地作業執行上下文將狀態從一個組件傳遞到另一個組件。 畢竟,即使是踩踏安全的全局變量也不是那么安全,因為作業的數據可能在并發執行時混雜在一起。
3.節流
使用隊列(輸入或在批處理程序中)時,您應該始終有一個限制策略。 如果物品的生產率始終高于消耗的物品,那么您將遭受災難。 如果排隊的項目保留在內存中,最終將用完它。 如果項目存儲在持久隊列中,則會用完空間。 因此,您需要一種平衡生產者和消費者的機制。 只要生產率是有限的,您只是要確保您有合適的消費者數量來平衡生產率。
當隊列大小超過給定閾值時,自動擴展消費者就像開始新的消費者一樣,是一種合適的自適應策略。 當隊列大小低于其他閾值時殺死使用者,可以釋放不必要的空閑線程。
create-new-consumer閾值應大于kill-idle閾值,因為如果它們相等,則當隊列大小在閾值大小附近波動時,您將獲得create-kill抖動。
4.存儲工作結果
在內存中存儲作業結果不是很周到的事情。 選擇一個持久性存儲(MongoDb限制的集合)是一個更好的選擇。
如果結果保存在內存中,而您忘記將它們限制在一個上限,則批處理處理器最終將耗盡內存。 重新啟動計劃程序將清除您以前的工作結果,這是非常有價值的,因為這是您獲得的唯一反饋。
5.泛濫外部服務提供商
for(GeocodeRequest geocodeRequest : batchRequests) {mapsService.resolveLocation(geocodeRequest); }這段代碼充斥著您的地圖提供商,因為一旦您完成一項請求,幾乎立即就會發出一個新請求,這給他們的服務器帶來了很大壓力。 如果batchRequests數目足夠高,那么您可能會被禁止。
您應該在兩次請求之間添加一個短暫的延遲,但是不要讓當前的睡眠狀態變慢,而應使用EIP延遲器。
6.對批處理
盡管程序風格的編程是大多數程序員的默認思維方式,但許多批處理任務更適合企業集成模式設計。 使用EIP工具更容易實現所有上述規則:
- 消息隊列
- 投票渠道
- 變形金剛
- 分離器/聚合器
- 延遲器
使用EIP組件可簡化測試,因為您一次只專注于一項職責。 EIP組件通過隊列傳遞的消息進行通信,因此將一個同步處理通道更改為調度的線程池只是一個配置細節。
有關EIP的更多信息,請查看出色的Spring Integration框架。 我已經使用了三年了,接種疫苗后,您會更喜歡它而不是過程編程。
翻譯自: https://www.javacodegeeks.com/2013/11/batch-processing-best-practices.html
總結
- 上一篇: bilibili电脑端加速器(bilib
- 下一篇: Apache Karaf遇到Apache