Activiti绩效对决
到現在為止,當您問我同樣的問題時,我將告訴您Activiti如何以各種可能的方式最小化數據庫訪問,如何將流程結構分解為“執行樹”,以便進行快速查詢或如何利用十年的工作流框架開發知識。
您知道,嘗試不回答問題就解決這個問題。 我們知道它很快,因為我們已經在此基礎上建立了理論基礎。 但是現在我們有了證明:實數……。 是的,這將是一個冗長的帖子。 但是請相信我,這值得您花時間!
免責聲明:性能基準很難。 真的很難。 不同的機器,稍有不同的測試設置…很小的東西會嚴重改變結果。 此處的數字僅是為了證明Activiti引擎的開銷非常小,同時還非常容易集成到Java生態系統中并提供BPMN 2.0流程執行。
Activiti基準項目
為了測試Activiti引擎的流程執行開銷,我在github上創建了一個小項目: https : //github.com/jbarrez/activiti-benchmark
該項目目前包含9個測試過程,我們將在下面進行分析。 項目中的邏輯非常簡單:
- 為每次測試運行創建一個流程引擎
- 每個進程都使用1到10個線程的線程池在此進程引擎上順序執行。
- 將所有過程都放入一個包中,其中抽取了許多隨機執行的內容。
- 收集所有結果,并生成帶有一些漂亮圖表HTML報告
要運行基準測試,只需按照github頁上的說明來構建和執行jar。
基準結果
我用于測試結果的測試計算機是我的(相當舊的)臺式計算機:AMD Phenom II X4 940 3.0Ghz,8 Gb 800Mhz RAM和運行Ubuntu 11.10的舊版本7200 rpm HD。 用于測試的數據庫在運行測試的同一臺計算機上運行。 因此請記住,在“真實”服務器環境中,結果甚至可能更好!
我上面提到的基準測試項目是在默認的Ubuntu MySQL 5數據庫上執行的。 我只是切換到'large.cnf'設置(這會在數據庫上拋出更多的RAM以及類似的東西),而不是默認配置。
- 每個測試過程使用一個從1個到10個線程的線程池運行2500次 。 用simpleton語言:僅使用一個線程執行2500個進程執行,使用兩個線程執行2500個線程執行,使用三個線程執行2500個進程執行…是的,您知道了。
- 每次基準測試都是使用“默認” Activiti流程引擎完成的。 這基本上意味著以純Java創建的“常規”獨立Activiti引擎。 每個基準測試運行都在“ Spring”配置中完成。 在這里,流程引擎是通過將其包裝在工廠bean中而構造的,數據源是Spring數據源,事務和連接池也由Spring管理(我實際上是使用經過調整的BoneCP線程池)
- 每次基準測試運行都是在默認歷史記錄級別(即“審核”)上使用歷史記錄,并且未啟用歷史記錄(即歷史記錄級別“無”)時執行的 。
以下各節詳細分析了這些過程,但是這里已經是測試運行的整體結果:
- Activiti 5.9 – MySQL –默認–歷史記錄已啟用
- Activiti 5.9 – MySQL –默認–歷史記錄已禁用
- Activiti 5.9 – MySQL – Spring –歷史記錄已啟用
- Activiti 5.9 – MySQL – Spring –歷史記錄已禁用
我使用Activiti的最新公共發行版Activiti 5.9運行了所有測試。 但是,我的測試運行為表面帶來了一些潛在的性能修復(我還通過探查器運行了基準項目)。 很快就可以清楚地看到,大多數流程執行時間實際上是在流程結束時完成的。 基本上,觸發更多的查詢是不必要的,如果我們要在執行樹中保存更多狀態,則沒有必要。 我與來自Camunda的 Daniel Meyer和我的同事Frederik Heremans坐在一起,他們已經設法為此進行了修復! 因此, 當前的Activiti 主干 (即Activiti 5.10-SNAPSHOT)比5.9快得多 。
- Activiti 5.10 – MySQL –默認–歷史記錄已啟用
- Activiti 5.10 – MySQL –默認–歷史記錄已禁用
- Activiti 5.10 – MySQL – Spring –歷史記錄已啟用
- Activiti 5.10 – MySQL – Spring –歷史記錄已禁用
從高級角度(向下滾動以進行詳細分析),需要注意以下幾點:
- 由于使用了更多的“專業”連接池,我期望默認配置和Spring配置之間會有一些差異。 但是,兩種環境的結果都差不多。 有時默認值更快,有時是Spring。 很難真正找到一種模式。 因此,我在下面的詳細分析中省略了Spring結果。
- 最佳的平均時間是使用四個線程執行進程時大多數時候找到的時間 。 這可能是由于擁有四核計算機。
- 當使用八個線程執行進程時,通常會找到最佳的吞吐量數字。 我只能假設這與擁有四核計算機有關。
- 當線程池中的線程數增加時,吞吐量(每秒執行的進程)增加,這兩者均對平均時間產生負面影響。 當然,具有六個或七個以上的線程,您會非常清楚地看到這種效果。 這基本上意味著,雖然進程本身需要花費更長的時間來執行,但是由于有多個線程,您可以在相同的時間內執行更多這些“較慢”的進程。
- 啟用歷史記錄確實會產生影響。 通常,啟用歷史記錄會使執行時間加倍。 這是合乎邏輯的,因為當歷史記錄處于默認級別(即“審核”)時會插入許多額外的記錄。
出于好奇,我進行了最后一個測試:在Oracle XE 11.2數據庫上運行性能最佳的設置。 Oracle XE是“真實” Oracle數據庫的免費版本。 無論多么努力,我都嘗試過,無法在Ubuntu上正常運行。 因此,我在同一臺計算機上使用了舊的Windows XP安裝。 但是,操作系統是32位,這意味著系統僅具有3.2可用的8Gb RAM。 結果如下:
- Activiti 5.10 – Windows上的Oracle –默認–歷史記錄已禁用
結果不言而喻。 Oracle吹走了MySQL上的任何(單線程)結果 (它們已經非常快了!)。 但是,當使用多線程時,它比任何MySQL結果都要差得多。 我的猜測是,這些是由于XE版本的局限性 :僅使用一個CPU,僅使用1 GB RAM,等等。 我真的想在一個由Oracle托管的真實Oracle上運行這些測試, DBA…如果您有興趣,請隨時與我聯系 !
在下一部分中,我們將詳細研究每個測試過程的性能數字。 可以自行下載包含以下所有數字和圖表的Excel工作表。
流程1:裸手(一筆交易)
第一個過程至少在業務方面不是一個非常有趣的過程。 開始該過程后,立即結束。 它本身不是很有用,但是它的數目使我們了解到一件重要的事情:Activiti引擎的光禿禿的開銷。 以下是平均時間:
此過程在單個事務中運行,這意味著由于Activiti的優化禁用了歷史記錄后,沒有任何內容保存到數據庫中。 啟用歷史記錄后,您基本上將獲得在歷史流程實例表中插入一行的成本,這大約是4.44毫秒。 同樣很明顯,我們對Activiti 5.10的修復在這里產生了巨大的影響。 在以前的版本中,有99%的時間用于流程的清理檢查。 在這里查看最佳結果:使用4個線程執行2500次此過程時,為0.47 ms 。 僅半毫秒 ! 可以說Activiti引擎的開銷非常小。
吞吐量數字同樣令人印象深刻:
在最好的情況下,將執行8741個進程。 每秒。 當您到達此處閱讀帖子時,您可能已經執行了數百萬個過程 。 您還可以看到這里的4或8個線程之間幾乎沒有什么區別。 這里大多數執行時間是cpu時間,在這里不會發生諸如等待數據庫鎖定之類的潛在沖突。
在這些數字中,您還可以輕松地看到Oracle XE不能很好地在多個線程之間進行擴展(如上所述)。 在以下結果中,您將看到相同的行為。
流程2:相同,但時間更長(一筆交易)
此過程與上一個過程非常相似。 我們又只有一筆交易。 該過程開始后,我們將進行七個無操作通過活動,直到結束。
這里要注意一些事情:
- 最好的結果(同樣是4個線程,禁用了歷史記錄)實際上比以前的簡單過程更好。 但也請注意,單線程執行速度要慢一些。 這意味著該過程本身會比較慢,這是合理的,因為有更多活動。 但是,在進程中使用更多的線程并進行更多的活動確實允許更多潛在的交錯。 在前一種情況下,該線程幾乎沒有誕生,然后再次被殺死。
- 啟用/禁用歷史記錄之間的差異大于以前的過程。 這是合乎邏輯的,因為這里記錄了更多的歷史記錄(對于每個活動,數據庫中都有一條記錄)。
- 同樣,Activiti 5.10遠遠優于Activiti 5.9。
吞吐量數字遵循以下觀察結果:在這里有更多的機會使用線程。 最好的結果徘徊在每秒12000個進程執行左右 。 再次,它演示了Activiti引擎的輕量級執行。
流程3:一次交易中的并行性
此過程執行一個派生的并行網關,而一個并行網關加入同一事務。 您會期望獲得與先前結果類似的結果,但是您會感到驚訝:
將這些數字與上一個過程進行比較,您會發現執行速度較慢。 那么,即使活動較少,為什么此過程也會變慢? 原因在于并行網關的實現方式,尤其是聯接行為。 在實現方面,最困難的部分是您需要應對多個執行到達聯接時的情況。 為了確保行為是原子的,我們在內部進行一些鎖定,并在執行樹中獲取所有子執行,以查明聯接是否激活。 因此,與“常規”活動相比,這是一個“昂貴”的操作。
請注意, 我們在這里只談論5毫秒的單線程和3.59毫秒的MySQL最佳情況 。 給定實現并行網關功能所需的功能,如果您要問我的話,這是花生。
吞吐量數字:
這是第一個實際上包含一些“邏輯”的過程。 在上述最佳情況下,這意味著可以在一秒鐘內執行1112個過程。 如果您要問我,真是令人印象深刻! 。
流程4:現在我們到達某個地方(一筆交易)
在對真實的業務流程進行建模時,您已經看到了該流程。 但是,由于所有活動都是自動傳遞,因此我們仍在一個數據庫事務中運行它。 在這里,我們還有兩個分叉和兩個聯接。
看一下最低的數字:使用一個線程運行時,在Oracle上為6.88毫秒 。 考慮到這里發生的所有事情,這真是太快了。 此處的歷史記錄數量至少翻了一番(Activiti 5.10),這是有道理的,因為此處有大量活動審核日志記錄。 您還可以看到,這導致此處四個線程的平均時間更長,這可能是由于聯接的實現所致。 如果您對Activiti內部有一點了解,那么您將了解這意味著執行樹中有很多執行。 我們有一個較大的并發根,但也有多個子級,有時它們也是并發根。
但是,盡管平均時間增加了,但吞吐量無疑會受益:
使用八個線程運行此過程,使您可以在一秒鐘內執行411次此過程。
這里還有一些奇特的地方:Oracle數據庫在執行更多線程并發時表現更好。 這與所有其他度量完全相反,在所有其他度量中,Oracle在該環境中總是較慢(請參見上面的說明)。 我認為這與我們在派生/加入時應用的內部鎖定和強制更新有關,Oracle似乎可以更好地處理它。
流程5:添加一些Java邏輯(單個事務)
我添加了此過程,以了解在過程中添加Java服務任務的影響。 在此過程中,第一個活動生成一個隨機值,將其存儲為過程變量,然后根據該隨機值在過程中上升或下降。 上升或下降的機會約為50/50。
平均時間非常好。 實際上,結果與上述過程1和2相同(沒有活動或僅具有自動傳遞)。 這意味著將Java邏輯集成到您的進程中的開銷幾乎不存在 (當然免費是免費的)。 當然,您仍然可以使用該邏輯編寫慢速代碼,但是您不能為此而怪罪Activiti引擎
吞吐量數字與過程1和2相當:非常非常高。 最好的情況是每秒執行9000個以上的進程 。 這確實也意味著您自己的Java邏輯有9000次調用。
P rocess 6,7和8:加入等待狀態和交易
先前的過程向我們展示了Activiti引擎的全部開銷。 在這里,我們將研究等待狀態和多個事務如何影響性能。 為此,我添加了三個包含用戶任務的測試過程。 對于每個用戶任務,引擎將提交當前事務并將線程返回給客戶端。 由于結果與這些流程幾乎完全兼容,因此我們將其分組。 這些過程是:
按上述過程的順序,這是平均計時結果。 對于第一個過程,僅包含一個用戶任務:
顯然,具有等待狀態和多個事務確實會對性能產生影響。 這也是合乎邏輯的:之前,引擎可以通過不將運行時狀態插入數據庫來進行優化,因為該過程是在一個事務中完成的。 現在,整個狀態(即指向您當前位置的指針)需要保存到數據庫中。 這樣的過程可能會像這樣“沉睡”很多天,幾個月,幾年……。 Activiti引擎現在不再將其保存在內存中,它可以釋放出來以完全關注其他進程。
如果僅用一個用戶任務檢查過程的結果,就會發現在最佳情況下(Oracle,單線程– MySQL上的4個線程非常接近),此操作在6.27毫秒內完成。 這確實非常快,如果考慮到我們在這里進行了一些插入(執行樹,任務),一些更新(執行樹)和刪除(清理)。
這里的第二個過程包含7個用戶任務:
第二張圖表告訴我們,從邏輯上講,更多事務意味著更多時間。 最好的情況是,此過程在32.12 ms內完成。 這是針對七個事務的,每個事務給出4.6毫秒。 因此很明顯,添加等待狀態時,平均時間以線性方式縮放。 這當然是有道理的,因為交易不是免費的。
另請注意,啟用歷史記錄確實會在此處增加一些開銷。 這是由于將歷史記錄級別設置為“審核”,從而將所有用戶任務信息存儲在歷史記錄表中。 從禁用歷史記錄的Activiti 5.9和啟用歷史記錄的Activiti 5.10之間的區別也可以注意到這一點:這是極少數情況,其中啟用歷史記錄的Activiti 5.10比禁用歷史記錄的5.9慢。 但是考慮到這里存儲的歷史記錄數量,這是合乎邏輯的。
第三個過程向我們學習了用戶任務和并行網關如何交互:
第三張圖告訴我們不多的新知識。 現在,我們有兩個用戶任務,以及更“昂貴”的fork / join(請參見上文)。 平均時間就是我們期望的時間。
吞吐量圖表與您期望的平均時間一致。 每秒70至250個進程。 w!
為了節省空間,您需要單擊它們以將其放大:
流程9:那么范圍呢?
對于最后一個過程,我們將研究“范圍”。 “范圍”是我們內部在引擎中的調用方式,它與可變的可見性,指示進程狀態的指針之間的關系,事件捕獲等有關。BPMN2.0在這些范圍內有很多情況,例如嵌入式子流程,如此處的流程所示。 基本上,每個子流程都可以具有邊界事件(捕獲錯誤,消息等),這些邊界事件僅在其作用域處于活動狀態時才應用于其內部活動。 無需過多討論技術細節:要以正確的方式實現范圍,您需要一些不太瑣碎的邏輯。
這里的示例流程具有4個子流程,彼此嵌套。 內部過程使用并發性,這對于Activiti引擎本身也是一個作用域。 這里還有兩個用戶任務,因此意味著兩個事務。 因此,讓我們看一下它的性能:
您可以清楚地看到Activiti 5.9和5.10之間的巨大差異。 范圍的確是一個領域,最后,圍繞“流程清理”的修復程序具有巨大的優勢,因為創建了許多執行對象并將其持久化以表示許多不同的范圍。 在Activiti 5.9上,單線程性能不是很好。 幸運的是,從藍色和紅色條之間的間隙中可以看到,這些作用域確實允許高并發性。
Oracle的數量加上5.10測試的多線程結果,確實證明了引擎現在可以有效地處理范圍。 吞吐量圖表證明,該進程可以通過更多線程很好地進行擴展,正如您所看到的,倒數第二個塊中的紅線和綠線之間存在較大差距。 在最佳情況下,引擎會處理此更為復雜的過程中的64個過程。
隨機執行
如果您已經單擊了帖子開頭的完整報告,則可能已經注意到還針對每種環境都對隨機執行進行了測試。 在此設置中,完成了2500個流程執行,并且兩個流程都是隨機選擇的。 如這些報告所示,這意味著超過2500次執行,每個進程執行的次數幾乎相同(正態分布)。
最后一張圖表顯示了最佳設置(Activiti 5.10,禁用了歷史記錄)以及添加更多線程時這些隨機進程執行的吞吐量如何:
正如我們在上面的許多測試中所看到的那樣,一旦通過了四個線程,事情就不會改變太多了。 數字(每秒167個進程)證明在實際情況下(即,多個進程同時執行),Activiti引擎可以很好地擴展。 結論
平均時序圖清楚地顯示了兩件事:
- Activiti引擎速度快,開銷最小 !
- 啟用或禁用歷史記錄之間的區別絕對明顯。 有時甚至會減少一半的時間。 所有歷史記錄測試都是使用“審核”級別完成的,但是有一個更簡單的歷史記錄級別(“活動”),可能對用例而言足夠好。 Activiti在歷史記錄配置方面非常靈活,您可以為每個進程專門調整歷史記錄級別。 因此,請考慮一下您的流程需要具備的級別,如果它完全需要歷史記錄的話 !
吞吐量圖表證明,當有更多線程可用時(即,任何現代應用程序服務器),引擎可以很好地擴展。 Activiti經過精心設計,可用于高吞吐量和可用性(集群)架構 。
正如我在引言中所說,數字就是它們:僅僅是數字。 我要在這里總結的主要觀點是Activiti引擎非常輕巧。 使用Activiti自動化業務流程的開銷很小。 通常, 如果您需要使業務流程或工作流自動化,則希望與任何Java系統進行一流的集成,并且您希望所有這些都快速且可擴展……所有這些都無需進一步!
參考:來自JCG合作伙伴 Joram Barrez 的Activiti Performance Showdown活動,來自“ 小腳走路”博客。
翻譯自: https://www.javacodegeeks.com/2012/07/activiti-performance-showdown.html
總結
以上是生活随笔為你收集整理的Activiti绩效对决的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安卓手游充值退款流程(安卓手游充值)
- 下一篇: 代理ip攻击(ip代理防止ddos)