Drools singleton StatefulKnowledgeSession作为Web服务

时间:2014-03-19 15:05:08

标签: java multithreading web-services drools

我正在使用Drools 5.6.0,我已准备好升级到6.0,因此这个问题与两个版本都有关。

我已经搜索了很多关于在多线程环境中使用Drools的内容,我仍然不确定如何继续。在下面的场景中,我试图找到一种方法,将使用大量静态事实预先初始化的单例StatefulKnowledgeSession 用作Web服务的业务逻辑。

我想知道下面进一步描述的方案是否有最佳做法。

  1. 我在服务器启动时创建一个StatefulKnowlegdeSession单例

  2. 初始化的正确位置,我将超过100.000个事实插入到StatefulKnowlegdeSession中。我将这些称为“静态事实”,因为它们不会被规则修改。静态事实更像是一组大查找表。

  3. 现在,规则引擎已置于 Web服务(Tomcat)中。 Web服务接收将插入到KnowledgeSession中的Request对象。 在fireAllRules()之后,我希望KnowledgeSession计算一个输出对象,该输出对象将作为Web服务响应返回。

  4. 响应的计算使用了静态事实。规则创建了许多临时对象,使用 insertLogical()将其插入到工作内存中。这样可以确保在Web服务调用结束时收回原始Request对象后,所有垃圾都将从工作​​内存中删除。

  5. 现在的问题是我将如何在多线程服务器中完成这项工作?

    • 我想尽可能只使用一个StatefulKnowledgeSession实例(单例),因为静态事实很大,可能会成为内存问题。

    • 无法使用在每次网络服务调用开始时新创建的StatelessKnowledgeSessions ,因为插入所有静态事实需要的时间太长。

    • 我知道 StatefulKnowlegdeSession不是线程安全的这一事实。此外,不再支持分区选项。

    • 但是,可以在不同的线程中使用不同的WorkingMemoryEntryPoints / EntryPoints 。我可以使用EntryPoints的,并且每个Web服务调用将使用池中的一个实例来插入Web服务请求。

    这也意味着我需要乘以我的规则(?),每个使用一个特定的EntryPoint,或至少第一个规则,匹配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服务响应返回。 / LI>

3 个答案:

答案 0 :(得分:1)

我不会使用多个入口点。将请求排队到运行会话的线程。如果您想使用多核,请运行多个服务或服务线程。

对于您的10万个事实,请仔细检查其字段的表示方式。 String.intern()可以提供可观的节省。其他对象可以 - 因为它都是静态的 - 可以共享。通常,在这种情况下,元素构造期间的一些额外开销在以后是有益的,例如,较少的GC开销。

(否则这是一个非常好的总结,几乎是运行这种情况的“howto”。+ 1

答案 1 :(得分:0)

听起来像是类似的系统,我只是使用' synchronized'关于服务方法。该服务是一个Spring bean。用户负荷不高且响应速度快,因此排队很少见且很少。

根据可能调用服务的并发客户端数量以及每个请求获取响应所需的时间,您还可以创建一个小型服务池(内存允许)。

答案 2 :(得分: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`),您可以看到创建需要更长时间(就像新的会话创建任务被序列化一样)已确认(排序){{3 }}
  • 版本6.0中较新的Knowledge*类已弃用
  • Kie*类(这很烦人,因为99%的示例仍然使用较旧的类)...所以KnowledgeBase替换KieContainerStatefulKnowledgeSession替换KieSession ...在优化代码的过程中,我从5.x级升级到6级。 x班

在我的情况下(我在REST服务中使用Drools 6.x),我最终使用in this nabble forum thread汇集了Drools会话(其中实例被重用),正如同一个nabble线程中所建议的那样...我不能使用Singleton,因为REST服务需要很快,如果一个请求需要更长时间,我也不希望其他请求被阻止......到目前为止,这似乎对我有用。