对基于消息队列的Activiti异步执行器进行基准测试
一點(diǎn)歷史
永不停息??的一件事是,Activiti如何以驚人的規(guī)模在一些大型組織中使用。 過(guò)去,這導(dǎo)致了各種優(yōu)化和重構(gòu),其中包括異步執(zhí)行器-替換舊的作業(yè)執(zhí)行器。 對(duì)于未啟動(dòng)的用戶:這些執(zhí)行器在流程實(shí)例中處理計(jì)時(shí)器和異步繼續(xù)。 特別是在過(guò)去的兩年中,我們已經(jīng)看到它的使用大大增加。 異步執(zhí)行器的引入極大地提高了性能。 但是,去年在巴黎舉行的社區(qū)活動(dòng)中,我們了解到,在處理大量工作時(shí),執(zhí)行者使用的查詢可能會(huì)導(dǎo)致需要進(jìn)行表掃描。 這永遠(yuǎn)不是一件好事。
因此,我們知道在完成版本6之前,我們確實(shí)要做一件事,那就是重構(gòu)異步執(zhí)行器,使它使用的所有查詢都變得非常簡(jiǎn)單。 這確實(shí)意味著我們必須將作業(yè)數(shù)據(jù)拆分為與不同類型和狀態(tài)匹配的各種表,同時(shí)仍要使API與以前的Activiti版本兼容。
在過(guò)去的幾個(gè)月中,我們一直在做這些事情(包括許多其他事情),并取得了一些不錯(cuò)的結(jié)果和一些新的不錯(cuò)的API,它們豐富了該平臺(tái)。 我可以在“新的”異步執(zhí)行程序的工作方式上寫(xiě)另一個(gè)博客,但是昨天我已經(jīng)完成了文檔工作,所以,如果您對(duì)所有工作方式都感興趣, 請(qǐng)查看在線文檔或檢查工具 欄上 的源代碼。 v6分支 。
架構(gòu)設(shè)計(jì)當(dāng)然受我們從過(guò)去兩種實(shí)現(xiàn)中學(xué)到的知識(shí)的影響,但同時(shí)也受消息隊(duì)列系統(tǒng)中概念的影響很大。 設(shè)計(jì)目標(biāo)之一是,插入消息隊(duì)列并運(yùn)行它應(yīng)該非常容易,因?yàn)槲覀冇幸环N直覺(jué),認(rèn)為這將對(duì)性能有所幫助。
因此,我們做到了。 由于新的體系結(jié)構(gòu),使異步執(zhí)行程序與消息隊(duì)列一起工作幾乎是微不足道的。 如果您對(duì)實(shí)現(xiàn)感興趣, 我還會(huì)在文檔中添加有關(guān)此主題的部分。
而且,當(dāng)然,您知道我,我只是想將這兩個(gè)執(zhí)行程序?qū)崿F(xiàn)相互比較基準(zhǔn)��
基準(zhǔn)項(xiàng)目
您可以找到我在Github上使用的代碼: https : //github.com/jbarrez/queue-based-async-executor-benchmark
基本上,它的工作是使用配置屬性文件運(yùn)行Main.java。
- 使用適當(dāng)?shù)呐渲脝?dòng)流程引擎(我最近在網(wǎng)上看到一些Activiti基準(zhǔn)測(cè)試,這些基準(zhǔn)測(cè)試了Activiti的性能而未使用適當(dāng)?shù)倪B接池?cái)?shù)據(jù)源。很遺憾,但是無(wú)論如何。)
- 如果以“生產(chǎn)者”身份運(yùn)行,將啟動(dòng)10000個(gè)流程實(shí)例,每10毫秒一個(gè)。 定期的統(tǒng)計(jì)信息將被打印到控制臺(tái)上。
- 如果以“執(zhí)行程序”身份運(yùn)行,則將流程引擎配置為啟用異步執(zhí)行程序。
- 可以有任意數(shù)量的生產(chǎn)者/執(zhí)行者,但是所有生產(chǎn)者/執(zhí)行者都進(jìn)入同一個(gè)數(shù)據(jù)庫(kù)。
項(xiàng)目中使用的流程定義如下:
需要注意的重要一點(diǎn)(在圖表上不可見(jiàn))是,在這個(gè)重要的流程定義中,所有服務(wù)任務(wù)都是異步的。 并行派生之后的服務(wù)任務(wù)與加入的并行網(wǎng)關(guān)一樣配置為互斥的 。 這里有兩個(gè)計(jì)時(shí)器,其中用戶任務(wù)上的一個(gè)是1秒,子流程上的一個(gè)是50分鐘。 總而言之,當(dāng)啟動(dòng)流程實(shí)例時(shí),它導(dǎo)致需要執(zhí)行27個(gè)作業(yè)才能到達(dá)終點(diǎn)。 對(duì)于10000個(gè)實(shí)例,這意味著我們正在有效測(cè)試270 000個(gè)作業(yè)的吞吐量。
請(qǐng)注意,與任何基準(zhǔn)測(cè)試一樣,原始數(shù)字說(shuō)明了一切,但不是全部。 這一切都取決于服務(wù)器硬件,實(shí)際的流程定義和許多其他細(xì)節(jié)。 但是,如果在完全相同的硬件上執(zhí)行完全相同的代碼,相對(duì)數(shù)字確實(shí)會(huì)給我們帶來(lái)很多啟發(fā)。 閱讀下一部分時(shí),請(qǐng)記住這一點(diǎn)。
測(cè)試環(huán)境
所有基準(zhǔn)測(cè)試都是在Amazon Web Services(AWS)上運(yùn)行的,生產(chǎn)者/執(zhí)行者使用EC2服務(wù)器,r3.4xlarge(16個(gè)vCPU,16個(gè)vCPU)上的數(shù)據(jù)庫(kù)使用RDS PostgresQL (因?yàn)镻ostgres是一個(gè)很棒的數(shù)據(jù)庫(kù),非常容易設(shè)置) 122 GiB內(nèi)存)。
使用以下EC2配置
- RDS(postgres):r3.4xlarge(16個(gè)vCPU,122 GiB內(nèi)存)
- 生產(chǎn)引擎:c3.4xlarge(16個(gè)vCPU,30 GiB內(nèi)存)
- 執(zhí)行器引擎:c3.8xlarge(32個(gè)vCPU,60 GiB內(nèi)存)
所有的服務(wù)器都在歐盟西部地區(qū)運(yùn)行。 因此,所有測(cè)試結(jié)果都具有真實(shí)的網(wǎng)絡(luò)延遲(沒(méi)有運(yùn)行在localhost基準(zhǔn)測(cè)試上的延遲,因此跳過(guò)了網(wǎng)上經(jīng)常看到的聯(lián)網(wǎng))。 當(dāng)運(yùn)行上面的項(xiàng)目時(shí),JVM分配了8GB的空間。
我們將使用的指標(biāo)是作業(yè)的吞吐量 ,以作業(yè)/秒表示。 簡(jiǎn)而言之,在測(cè)試運(yùn)行之后,我們驗(yàn)證數(shù)據(jù)庫(kù)中的數(shù)據(jù)是否正確(即10K完成的流程實(shí)例),并采用第一個(gè)開(kāi)始時(shí)間和最后一個(gè)結(jié)束時(shí)間,這使我們獲得了x秒的時(shí)間。 則吞吐量為x / 270000(我們知道每個(gè)流程實(shí)例等于27個(gè)作業(yè))。
基線測(cè)量
基準(zhǔn)測(cè)試的第一件事是“基準(zhǔn)”,即由線程池支持的常規(guī)異步執(zhí)行程序(即v5中異步執(zhí)行程序的改進(jìn)設(shè)計(jì))。 在此測(cè)試中,我們使用了2臺(tái)服務(wù)器,并進(jìn)行了以下配置(注意:6.0.0.Beta3實(shí)際上是快照版本):
| 一個(gè) | 乙 | C | d | |
| Activiti版本 | 6.0.0.Beta3 | 6.0.0.Beta3 | 6.0.0.Beta3 | 5.21.0 |
| 生產(chǎn)者引擎 | 1個(gè) | 1個(gè) | 1個(gè) | 1個(gè) |
| 執(zhí)行器引擎 | 1個(gè) | 1個(gè) | 2 | 2 |
| #池中的線程 | 32 | 10 | 10 | 10 |
| 阻塞隊(duì)列大小 | 256 | 100 | 100 | 100 |
一些有趣的觀察:
我認(rèn)為配置A會(huì)比配置B更好,因?yàn)檫@臺(tái)機(jī)器畢竟有32個(gè)CPU,因此將線程池的線程數(shù)與此匹配是有意義的。 但是,配置B的設(shè)置非常相似,除了只有10個(gè)線程和較小的阻塞隊(duì)列之外,它的性能大大提高(310 vs 210作業(yè)/秒)。 一個(gè)可能的解釋可能是32個(gè)線程爭(zhēng)用太多? 我確實(shí)記得當(dāng)初選擇默認(rèn)值“ 10”時(shí),我們進(jìn)行了一些基準(zhǔn)測(cè)試,其中10是吞吐量最佳的“魔術(shù)數(shù)”(但我確實(shí)認(rèn)為這取決于所使用的機(jī)器。
我希望添加另一個(gè)執(zhí)行程序節(jié)點(diǎn)會(huì)產(chǎn)生更大的影響,畢竟我們要添加32個(gè)CPU的計(jì)算機(jī),但是收益很小(310到326)。 我們將學(xué)習(xí)原因,并在本文的稍后階段進(jìn)行修復(fù)。
使用Activiti版本5.21.0的配置D使用與配置C相同的設(shè)置。但是,改進(jìn)的版本6的異步執(zhí)行程序顯然在這里勝出(326 vs 266)。 這當(dāng)然是我們希望的:-)。
到目前為止,我們最好的結(jié)果是每秒326個(gè)作業(yè) (并使用兩臺(tái)服務(wù)器)。
基準(zhǔn)線的變化
鑒于以上設(shè)置,可以詢問(wèn)運(yùn)行混合的生產(chǎn)者/執(zhí)行者時(shí)產(chǎn)生的影響。 這是Activiti引擎默認(rèn)的運(yùn)行方式:引擎將同時(shí)負(fù)責(zé)啟動(dòng)流程實(shí)例并立即執(zhí)行它們。 這是配置E (與配置C相同,除了兩個(gè)引擎現(xiàn)在都是生產(chǎn)者/執(zhí)行者),結(jié)果如下所示。 而且顯然性能較差。 一種解釋可能是機(jī)器已經(jīng)每10毫秒使用10個(gè)線程來(lái)啟動(dòng)流程實(shí)例,這可能導(dǎo)致與異步執(zhí)行器的10個(gè)線程進(jìn)行相當(dāng)多的爭(zhēng)用。 可能可以對(duì)該設(shè)置進(jìn)行很多調(diào)整以獲得更好的數(shù)字,但這不是此博客的目標(biāo)。 但是結(jié)果仍然很有趣。
因此,考慮到兩個(gè)執(zhí)行器引擎勝于一個(gè)執(zhí)行器引擎,合乎邏輯的事情是嘗試三個(gè)執(zhí)行器。 這是配置F。
類似于從一個(gè)執(zhí)行程序到兩個(gè)執(zhí)行程序,吞吐量提高了。 但不是以一種壯觀的線性方式。
介紹基于消息隊(duì)列的異步執(zhí)行器
現(xiàn)在該切換到基于消息隊(duì)列的異步執(zhí)行器了,現(xiàn)在我們有了基準(zhǔn)編號(hào)。 我選擇了最新版本的ActiveMQ ,因?yàn)槲覍?duì)此很熟悉,并且設(shè)置起來(lái)非常容易。 我沒(méi)有花時(shí)間調(diào)整ActiveMQ,切換持久性策略或嘗試替代方法。 因此,那里也可能會(huì)有一些利潤(rùn)。
在基準(zhǔn)項(xiàng)目中,我將Spring與以下配置一起使用: https : //github.com/jbarrez/queue-based-async-executor-benchmark/blob/master/src/main/java/org/activiti/MyConfigMessageExecutor.java 。 之所以選擇Spring,是因?yàn)镸essageListenerContainer提供了一種簡(jiǎn)單的方法來(lái)使消息隊(duì)列偵聽(tīng)器可以很好地與多個(gè)線程一起工作(否則,JBoss這樣的應(yīng)用程序服務(wù)器會(huì)為您提供)。 更具體地說(shuō),MessageListenerContainer的concurrenConsumers設(shè)置允許設(shè)置用于以智能方式監(jiān)聽(tīng)消息的線程數(shù)。 是的,該類確實(shí)具有很多可能會(huì)更好地影響結(jié)果的屬性,但這又不是重點(diǎn)。 請(qǐng)記住相對(duì)數(shù)字。
對(duì)于此配置,我們使用與config C類似的設(shè)置(到目前為止,我們?cè)趦膳_(tái)服務(wù)器上的最佳結(jié)果),稱為config G:1個(gè)生產(chǎn)者引擎,2個(gè)執(zhí)行者引擎。 請(qǐng)注意,我們現(xiàn)在還在混合中添加了“隊(duì)列服務(wù)器”,它使用的是c3.8xlarge機(jī)器(32個(gè)vCPU,60 GiB RAM),類似于執(zhí)行引擎服務(wù)器。
結(jié)果低于…,它們簡(jiǎn)直太棒了:在等效設(shè)置(但帶有額外的消息隊(duì)列服務(wù)器)中的消息隊(duì)列異步執(zhí)行程序比基于線程池的異步執(zhí)行程序快四倍 。
一個(gè)小的實(shí)現(xiàn)說(shuō)明:我們不得不切換到UUID ID生成器 ,因?yàn)橥掏铝繉?duì)于默認(rèn)值而言太高了。 請(qǐng)記住,UUID生成器比默認(rèn)生成器慢,結(jié)果甚至更棒(因?yàn)槲覀冊(cè)谶@里真正談?wù)摰氖呛撩?#xff09;。
有趣的觀察!
如果您運(yùn)行基準(zhǔn)測(cè)試項(xiàng)目,則會(huì)看到它定期吐出一些統(tǒng)計(jì)信息,因此您可以跟蹤系統(tǒng)中有多少個(gè)作業(yè),計(jì)時(shí)器,用戶任務(wù),歷史活動(dòng)實(shí)例,流程實(shí)例等。
在運(yùn)行消息隊(duì)列設(shè)置時(shí),從這些數(shù)字中可以很清楚地看出一種模式。 基于線程池的異步執(zhí)行器可以更快地完成流程實(shí)例(例如,大約1分鐘后,我們看到一批流程實(shí)例已完成),而對(duì)于基于消息的異步執(zhí)行器,流程實(shí)例實(shí)際上都在一個(gè)大的突發(fā)中完成了。 這表明后者將更多地分散流程實(shí)例活動(dòng)的執(zhí)行,而基于線程的活動(dòng)將繼續(xù)進(jìn)行直到完成為止。
團(tuán)隊(duì)中的一些討論導(dǎo)致了對(duì)此的解釋:基于線程池的線程將始終將下一個(gè)異步作業(yè)傳遞給執(zhí)行程序,而基于消息的線程將其放在隊(duì)列中,在隊(duì)列中已經(jīng)有數(shù)千條消息正在等待。 現(xiàn)在添加一個(gè)事實(shí),即對(duì)于流程實(shí)例,我們有很多排它異步作業(yè),這意味著對(duì)于基于線程池的異步作業(yè),許多線程試圖獲取流程實(shí)例鎖,但由于正在執(zhí)行排他實(shí)例而失敗。 但是,這項(xiàng)工作沒(méi)有獲得 ,很快就重新開(kāi)始了。 對(duì)于基于消息隊(duì)列的消息隊(duì)列,將它們?cè)俅翁砑拥较㈥?duì)列的末尾。 其中有數(shù)千條其他消息正在等待。 回到執(zhí)行此特定消息時(shí),排他鎖很可能已經(jīng)很久了。
這導(dǎo)致在基于線程池的異步執(zhí)行程序中進(jìn)行一些重構(gòu):刪除并重新插入作業(yè),而不是簡(jiǎn)單地釋放作業(yè)的鎖定,從而有效地模擬了隊(duì)列行為。 這是修復(fù)程序: https : //github.com/Activiti/Activiti/commit/d08a247570336c872bb17ce513c1fb95b3ba47a2#diff-bd9c7efdb4c57462f6fe71641b280942R212 。
在與config C完全相同的設(shè)置(稱為config H(1個(gè)生產(chǎn)者,2個(gè)執(zhí)行程序))中對(duì)這些基準(zhǔn)進(jìn)行基準(zhǔn)測(cè)試,這表明我們此簡(jiǎn)單的解決方案將吞吐量提高了34%! 現(xiàn)在我們有了一個(gè)新的基準(zhǔn)
更好的消息隊(duì)列異步執(zhí)行器結(jié)果
因此,在消息隊(duì)列結(jié)果(配置G)中,我們使用了10個(gè)線程的相當(dāng)保守的設(shè)置來(lái)偵聽(tīng)消息。 想法是我們也有10個(gè)線程用于線程池。 當(dāng)然,消息隊(duì)列使用者從根本上不同于輪詢線程:此類使用者與隊(duì)列具有持久連接,而隊(duì)列代理實(shí)際上將工作推給其使用者。 這應(yīng)該更有效。 因此,我們嘗試了以下配置,在這些配置中,我們改變了使用者(從而消耗了線程)和執(zhí)行程序節(jié)點(diǎn)的數(shù)量。
| 一世 | ? | ? | 大號(hào) | |
| 生產(chǎn)者引擎 | 1個(gè) | 1個(gè) | 1個(gè) | 1個(gè) |
| 執(zhí)行器引擎 | 2 | 2 | 3 | 3 |
| #消費(fèi)者/引擎 | 32 | 64 | 32 | 64 |
因此,一個(gè)不錯(cuò)的觀察結(jié)果是,添加更多的消費(fèi)者是超級(jí)有效的。 我們正在達(dá)到2222.9作業(yè)/秒的吞吐量 。 如果您問(wèn)我,那是非常快的,并且是基于線程池的異步執(zhí)行器的五倍。
可悲的是,添加更多的執(zhí)行器機(jī)器實(shí)際上對(duì)性能不利。 我認(rèn)為瓶頸現(xiàn)在已成為數(shù)據(jù)庫(kù),以及它如何處理大規(guī)模進(jìn)行的所有并發(fā)。 當(dāng)然,我根本沒(méi)有調(diào)整數(shù)據(jù)庫(kù) ,只是常規(guī)的RDS postgres實(shí)例。 或嘗試使用Aurora或Oracle(在我以前的基準(zhǔn)測(cè)試中獲得了最好的結(jié)果)。 但是,這里的重點(diǎn)是相對(duì)數(shù)量 ,而不是擠出吞吐量的最后一部分。 我認(rèn)為相對(duì)數(shù)字點(diǎn)已經(jīng)確定為��
結(jié)論
數(shù)字說(shuō)明了一切:基于新消息隊(duì)列的異步執(zhí)行器擊敗了基于線程池的異步執(zhí)行器。 這是否意味著您必須立即切換? 不, 常規(guī)的異步執(zhí)行器也非常快(436作業(yè)/秒仍然很快),但是更重要的是,設(shè)置非常簡(jiǎn)單,因?yàn)锳ctiviti引擎可以處理所有事情。 在項(xiàng)目中添加消息隊(duì)列意味著額外的復(fù)雜性:可能會(huì)失敗或崩潰的另一件事,是額外的監(jiān)視,維護(hù)等。但是,當(dāng)您執(zhí)行大量 (我的意思是“很多”)異步工作時(shí),您會(huì)重新達(dá)到默認(rèn)異步執(zhí)行器可以執(zhí)行的操作的限制,很高興知道還有替代方法。
我們還要忘記這里得出的另一個(gè)結(jié)論:版本6中的新異步執(zhí)行程序?qū)崿F(xiàn)是對(duì)版本5的重大改進(jìn)!
進(jìn)一步的工作
當(dāng)前的實(shí)現(xiàn)僅是Spring / JMS。 但是,該實(shí)現(xiàn)對(duì)于移植到其他系統(tǒng)和/或協(xié)議(應(yīng)用程序服務(wù)器,STOMP,AMPQ,AWS SQS等)而言是微不足道的。 對(duì)于將成為流行的下一個(gè)選擇的反饋表示贊賞。
有趣的是,這種基于消息隊(duì)列的異步執(zhí)行器使實(shí)現(xiàn)“優(yōu)先級(jí)隊(duì)列”非常簡(jiǎn)單。 優(yōu)先級(jí)隊(duì)列是我們?cè)S多大型用戶所要求的功能:提供特定的流程定義/實(shí)例/在特定條件下/…優(yōu)先級(jí)與常規(guī)作業(yè)相比。 容易想象如何設(shè)置多個(gè)隊(duì)列和/或分配更少或更多的使用者以優(yōu)先使用某些用例。
翻譯自: https://www.javacodegeeks.com/2016/07/benchmarking-message-queue-based-activiti-async-executor.html
總結(jié)
以上是生活随笔為你收集整理的对基于消息队列的Activiti异步执行器进行基准测试的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: superhot预告片下载_预告片:裸指
- 下一篇: adf开发_ADF:动态视图对象