2014-03-19 19 views
5

我正在使用Drools 5.6.0,並且我已準備好升級到6.0,因此此問題對於這兩個版本都是相關的。Drools singleton StatefulKnowledgeSession作爲Web服務

我已經google了很多關於在多線程環境中使用Drools,我仍然不確定如何繼續。在下面的場景中,我試圖找到一種方法來使用單身StatefulKnowledgeSession預初始化,其中有大量的靜態事實作爲Web服務的業務邏輯。

我想知道下面進一步描述的場景是否有最佳做法。

  1. 我創建了一個StatefulKnowlegdeSession單當服務器在初始化我插入超過10萬分的事實進入StatefulKnowlegdeSession開始

  2. 權。我稱這些爲「靜態事實」,因爲它們永遠不會被規則修改。靜態事實更像是一組大查找表。

  3. 現在規則引擎被放入網絡服務(Tomcat)。 Web服務接收一個將被插入到KnowledgeSession中的Request對象。 fireAllRules()之後我期望KnowledgeSession計算一個要作爲Web服務響應返回的輸出對象。

  4. 響應的計算利用了靜態事實。規則創建了很多臨時對象,這些對象使用insertLogical()插入到工作內存中。這可確保在Web服務調用結束時收回原始請求對象後,所有垃圾將從工作內存中移除。

現在的問題是我將如何使這項工作在多線程服務器?

  • 儘可能我想,因爲靜態的事實是大隻使用一個StatefulKnowledgeSession實例(單),它可能成爲一個內存問題。

  • 不能使用在每個Web服務調用開始時新創建的StatelessKnowledgeSessions,因爲插入所有靜態事實將花費太長時間。我知道StatefulKnowlegdeSession不是線程安全的這個事實。此外,分區選項不再受支持。

  • 但是,可以從不同的線程使用不同的WorkingMemoryEntryPoints/EntryPoints。我可以使用EntryPoints的,並且每個Web服務調用都將使用池中的一個實例來插入Web服務請求。

這也意味着,我需要每使用一個特定的入口點,或者至少第一規則加倍重視自己的規則,搭配Web服務請求的對象(?):

rule 「entry rule for WORKER-1」 // rule to be duplicated for entry points WORKER-2, WORKER-3,... 
    when 
     $req : Request() from entry-point 「WORKER-1」 
     $stat : StaticFact(attr = $req.getAttr()) 
    then 
     insertLogical(new SomeTemporaryStuff ($req)); 
end 

rule 「subsequent rule」 
    when 
     $tmp : SomeTemporaryStuff() 
    then 
     ...go on with the calculation and create a Response at some point... 
end 

後續規則會在工作記憶中創建臨時對象,並且在這一點上,如果我要用幾十個併發請求轟炸引擎,我真的害怕搞亂某些東西。

  • 我也可以開始「fireUntilHalt」模式KnowledgeSession但在這種情況下,我不知道我怎麼能得到規則引擎同步響應返回其作爲Web服務響應。

回答

1

我不會使用多個入口點。將請求排隊到運行會話的線程。如果您想要使用多核,請運行多個服務或服務線程。

對於您的100k事實,請仔細檢查其字段是如何表示的。 String.intern()可能會提供相當大的節省。其他對象可以 - 因爲它全部是靜態的 - 可以共享。通常,在這種情況下,元素構建期間的一些額外開銷稍後有益,例如較少的GC開銷。

(否則這是一個非常好的總結,幾乎是「HOWTO」爲捉迷藏這種情況。+1

+0

你不使用EntryPoints的原因是什麼?規則庫複雜度較高? KnowledgeSession中的併發問題?整體複雜性更高? – balazs

+0

@balazs入口點就像另一個屬性一樣,但是你必須以一種不合理的方式聲明可能的值,即「from」,並且你必須重複規則,因爲你的規則不應該有所不同。在這種情況下,我會在使用EP之前調查諸如添加「源」屬性或包裝器(類Source {request request;})等選項。 – laune

0

爲了什麼聽起來像一個類似的系統,我只是用了與服務方法「同步」。服務是一個Spring bean,沒有用戶負載和響應速度很快,因此排隊很少且很少。

根據可能調用該服務的併發客戶端的數量以及每個請求花費多長時間反應,你也可以創建一個小的服務池(內存許可)。

+0

如果您有非常高的性能要求(高併發性,典型服務響應時間爲1-3秒),您是否仍然會排除使用共享的StatefulKnowledgeSession?如果是這樣,爲什麼? – balazs

+0

我在上面的設計中使用了StatefulKnowledgeSession。我只是使用synchronized來確保在insert-fire-retract期間,沒有其他線程插入到同一個會話中。根據會話的內存要求,您可以創建一個有狀態會話池來幫助處理同時發生的請求。 – Steve

0

我知道這是索姆有點老......但我發佈了一個答案,希望信息可以幫助有人在類似的情況下使用Drools 6.x.

兩件事情我已經在過去的幾天裏瞭解的Drools:

  • 我已經緩存的KnowledgeBase創建因爲我創建DRL對象在運行時,一旦創造,我緩存它(使用Google Guava)......但我知道創建StatefulKnowledgeSession(根據請求使用newStatefulKnowledgeSession()fast (enough) in a single-threaded environment...but once you go multi-threaded (where I create a new StatefulKnowledgeSession`),您可以看到創建需要更長和更長時間(就像正在序列化新會話創建任務一樣)(排序的)in this nabble forum thread
  • Knowledge*類已被較新的Kie*班在6.0版本(這是煩人,因爲實例仍然使用舊類99%)...所以KnowledgeBaseKieContainerStatefulKnowledgeSession取代被替換KieSession ...在我的優化我的代碼的過程中,我從5.x類升級到6.x類

在我的情況下(我在一個REST服務中使用Drools 6.x),我結束了使用Drools會話Apache Commons Pooling正如在同一個討厭的線程中所建議的那樣......我不能使用Singleton,因爲REST服務需要快速,並且我不希望其他請求被潛在阻塞,如果一個請求需要更長時間......並且到目前爲止,似乎對我而言。