如何在Drools中管理事实插入以避免内存泄漏?

huangapple go评论71阅读模式
英文:

How should I manage fact insertion in drools to avoid a memory leak?

问题

以下是翻译好的内容:

我正在使用Drools 7.8.0来管理实时数据(每5秒钟有10000个事实)。我正在使用以下方式将它们插入工作内存:

KieSession kieSession = kieContainer.newKieSession();
EntryPoint entryPoint = kieSession.getEntryPoint("myData");

new Thread(new Runnable() {
    @Override
    public void run() {
        kieSession.fireUntilHalt();
    }
}).start();

while (true) {
    Data data = recieveData();
    factHandle = entryPoint.insert(data);
}

然而,这导致了内存泄漏:

共有64,994个"org.drools.core.common.EventFactHandle"实例,由"jdk.internal.loader.ClassLoaders$AppClassLoader @ 0x702500000"加载,占用113,316,792(71.06%)字节。这些实例被一个"java.lang.Thread"实例引用,该实例由"<系统类加载器>"加载。

所以我尝试跟踪我的事实并使用update代替insert,但这影响了规则的行为,一些事实无法匹配。

Map<String, FactHandle> allfacts = new HashMap<String, FactHandle>();

if (!allfacts.containsKey(dataName) && data != null) {
    factHandle = entryPoint.insert(data);
    allfacts.put(dataName, factHandle);
} else {
    entryPoint.update(allfacts.get(dataName), opcTagData);
}

这里是我拥有的规则的一个示例:

declare Data
    @role(event)
    @timestamp(timestamp)
    @expires(20s)
end

rule "status not available for 10 seconds"
dialect "java"

when
    d: Data(Name.contains("/Smart/Status")) from entry-point "myData"
    eval(!d.getValue().equals("Available"))
    not(
        Data(
            this.getName() == d.getName(),
            this.getValue().equals("Available"),
            this after[0s,10s] d) from entry-point "myData")
then
    doSmthg();
end

我无法找出插入事实并仍然获得预期结果而不会遇到内存泄漏的正确方法。

PS:我使用fireUntilHalt是因为在编写规则时我使用了时间操作符,我注意到使用fireAllRules不能给我预期的结果。

英文:

I am using Drools 7.8.0 to manage real time data ( 10000 facts every 5 seconds).
I am inserting them in the working memory using :

KieSession kieSession = kieContainer.newKieSession();
EntryPoint entryPoint = kieSession.getEntryPoint(&quot;myData&quot;);	

new Thread( new Runnable() {
					  @Override
					  public void run() {
						  kieSession.fireUntilHalt();
					  }
					} ).start();

while ( true )
{
Data data = recieveData();
factHandle=entryPoint.insert(data);
}

However, this is causing a memory leak :

64,994 instances of &quot;org.drools.core.common.EventFactHandle&quot;, loaded by &quot;jdk.internal.loader.ClassLoaders$AppClassLoader @ 0x702500000&quot; occupy 113,316,792 (71.06%) bytes. These instances are referenced from one instance of &quot;java.lang.Thread&quot;, loaded by &quot;&lt;system class loader&gt;&quot;

so I tried keeping track of my facts and using update instead of insert but this affected the rule's behavior and some facts weren't matched.

 Map&lt;String,FactHandle&gt; allfacts = new HashMap&lt;String,FactHandle&gt;();

if( !allfacts.containsKey(dataName) &amp;&amp; data!=null)
    		{
	    		factHandle=entryPoint.insert(data);
	    		allfacts.put(dataName,factHandle);
				
    		}
    		else
    		{
    			
    			entryPoint.update(allfacts.get(dataName), opcTagData);
    			
    		}

    	}
    	catch(Exception ex)
    	{
    		//error 
    	}

Here's an example of the rules I have:

declare Data
    @role( event )
    @timestamp( timestamp )  
    @expires( 20s )   
      
end

rule &quot;status not available for 10 seconds &quot;
dialect &quot;java&quot;

when
	d: Data(Name.contains(&quot;/Smart/Status&quot;)) from entry-point &quot;myData&quot;
	eval(!d.getValue().equals(&quot;Available&quot;))
	not(
    Data(
      this.getName() == d.getName(),
      this.getValue().equals(&quot;Available&quot;),
      this after[0s,10s] d) from entry-point &quot;myData&quot;)
	
	
then
	doSmthg();

end

I can't figure out what's the right way to to insert the facts and still get the expected result without facing a memory leak

PS:
I'm using fireUntilHalt because I used Temporal Operators when writing the rules and I noticed that using fireallrules does not give me the expected result.

答案1

得分: 2

以下是您提供的内容的翻译部分:

我测试了您的规则并进行了撤销,对我起作用。每个事件在20秒内被撤销。
您能确认您使用了 `stream` [模式](https://docs.jboss.org/drools/release/7.43.1.Final/drools-docs/html_single/index.html#cep-modes-con_decision-engine) 吗?

使用系统属性设置流模式

    drools.eventProcessingMode=stream

使用Java客户端API设置流模式

    import org.kie.api.conf.EventProcessingOption;
    import org.kie.api.KieBaseConfiguration;
    import org.kie.api.KieServices.Factory;

    KieBaseConfiguration config = KieServices.Factory.get().newKieBaseConfiguration();

    config.setOption(EventProcessingOption.STREAM);

使用项目的 kmodule.xml 文件设置流模式

    <kmodule>
      ...
      <kbase name="KBase2" default="false" eventProcessingMode="stream" packages="org.domain.pkg2, org.domain.pkg3" includes="KBase1">
        ...
      </kbase>
      ...
    </kmodule>

---

在之前的 drools 版本中,显式的事件撤销效果更好

    rule "retract expired events"
    salience 1
    duration 20000
    when
        d: Data() from entry-point "myData"
    then
        retract(d);
    end

---
这是我如何测试您的代码

test.drl

    package draft;
    dialect "java";
    
    declare Data
        @role(event)
        @timestamp(timestamp)
        @expires(20s)
    end
    
    rule "retract expired events"
    salience 1
    duration 20000
    when
        d: Data() from entry-point "test it"
    then
        retract(d);
    end
    
    rule "status not available for 10 seconds"
    when
        d: Data(Name.contains("/Smart/Status")) from entry-point "myData"
        eval(!d.getValue().equals("Available"))
        not(
        Data(
            this.getName() == d.getName(),
            this.getValue().equals("Available"),
            this after[0s,10s] d) from entry-point "myData")
    then
        System.out.println("alert");
    end

PlaygroundTest.java

    @DroolsSession("test.drl")
    public class PlaygroundTest {
        
        @Rule
        public DroolsAssert drools = new DroolsAssert();
        
        @Test
        public void testIt() {
            for (int i = 0; i < 5; i++) {
                drools.insertAndFireAt("myData", new Data(new Date(SECONDS.toMillis(i * 5)), "/Smart/Status", "Unavailable"));
                drools.advanceTime(5, SECONDS);
                drools.printFacts();
            }
            drools.assertFactsCount(3);
            drools.advanceTime(5, SECONDS);
            drools.printFacts();
            drools.assertFactsCount(2);
            drools.advanceTime(5, SECONDS);
            drools.printFacts();
            drools.assertFactsCount(1);
            drools.advanceTime(5, SECONDS);
            drools.printFacts();
            drools.assertFactsCount(0);
        }
    }

Data.java

    public class Data {
        
        private Date timestamp;
        private String name;
        private String value;
        
        public Data(Date timestamp, String name, String value) {
            this.timestamp = timestamp;
            this.name = name;
            this.value = value;
        }
        
        public Date getTimestamp() {
            return timestamp;
        }
        
        public String getName() {
            return name;
        }
        
        public String getValue() {
            return value;
        }
    }

stdout

    00:00:00 --> inserted: Data[timestamp=Thu Jan 01 02:00:00 EET 1970,name=/Smart/Status,value=Unavailable]
    00:00:00 --> fireAllRules
    00:00:05 Facts (1):
    Data[timestamp=Thu Jan 01 02:00:00 EET 1970,name=/Smart/Status,value=Unavailable]
    ...
    00:00:40 Facts (0):
英文:

I tested your rule and retraction works for me. Each event was retracted in 20s.
Can you confirm you use stream mode?

Set stream mode using system property

drools.eventProcessingMode=stream

Set stream mode using Java client API

import org.kie.api.conf.EventProcessingOption;
import org.kie.api.KieBaseConfiguration;
import org.kie.api.KieServices.Factory;

KieBaseConfiguration config = KieServices.Factory.get().newKieBaseConfiguration();

config.setOption(EventProcessingOption.STREAM);

Set stream mode using project kmodule.xml file

&lt;kmodule&gt;
  ...
  &lt;kbase name=&quot;KBase2&quot; default=&quot;false&quot; eventProcessingMode=&quot;stream&quot; packages=&quot;org.domain.pkg2, org.domain.pkg3&quot; includes=&quot;KBase1&quot;&gt;
    ...
  &lt;/kbase&gt;
  ...
&lt;/kmodule&gt;

It happened in previous versions of drools that explicit event retraction worked better

rule &quot;retract expired events&quot;
salience 1
duration 20000
when
	d: Data() from entry-point &quot;myData&quot;
then
	retract(d);
end

This is how I tested your code

test.drl

package draft;
dialect &quot;java&quot;

declare Data
	@role(event)
	@timestamp(timestamp)
	@expires(20s)
end

rule &quot;retract expired events&quot;
salience 1
duration 20000
when
	d: Data() from entry-point &quot;test it&quot;
then
	retract(d);
end

rule &quot;status not available for 10 seconds&quot;
when
	d: Data(Name.contains(&quot;/Smart/Status&quot;)) from entry-point &quot;myData&quot;
	eval(!d.getValue().equals(&quot;Available&quot;))
	not(
	Data(
		this.getName() == d.getName(),
		this.getValue().equals(&quot;Available&quot;),
		this after[0s,10s] d) from entry-point &quot;myData&quot;)
then
		System.out.println(&quot;alert&quot;);
end

PlaygroundTest.java

@DroolsSession(&quot;test.drl&quot;)
public class PlaygroundTest {
	
	@Rule
	public DroolsAssert drools = new DroolsAssert();
	
	@Test
	public void testIt() {
		for (int i = 0; i &lt; 5; i++) {
			drools.insertAndFireAt(&quot;myData&quot;, new Data(new Date(SECONDS.toMillis(i * 5)), &quot;/Smart/Status&quot;, &quot;Unavailable&quot;));
			drools.advanceTime(5, SECONDS);
			drools.printFacts();
		}
		drools.assertFactsCount(3);
		drools.advanceTime(5, SECONDS);
		drools.printFacts();
		drools.assertFactsCount(2);
		drools.advanceTime(5, SECONDS);
		drools.printFacts();
		drools.assertFactsCount(1);
		drools.advanceTime(5, SECONDS);
		drools.printFacts();
		drools.assertFactsCount(0);
	}
}

Data.java

public class Data {
	
	private Date timestamp;
	private String name;
	private String value;
	
	public Data(Date timestamp, String name, String value) {
		this.timestamp = timestamp;
		this.name = name;
		this.value = value;
	}
	
	public Date getTimestamp() {
		return timestamp;
	}
	
	public String getName() {
		return name;
	}
	
	public String getValue() {
		return value;
	}
}

stdout

00:00:00 --&gt; inserted: Data[timestamp=Thu Jan 01 02:00:00 EET 1970,name=/Smart/Status,value=Unavailable]
00:00:00 --&gt; fireAllRules
00:00:05 Facts (1):
Data[timestamp=Thu Jan 01 02:00:00 EET 1970,name=/Smart/Status,value=Unavailable]
00:00:05 --&gt; inserted: Data[timestamp=Thu Jan 01 02:00:05 EET 1970,name=/Smart/Status,value=Unavailable]
00:00:05 --&gt; fireAllRules
00:00:10 &lt;-- &#39;status not available for 10 seconds&#39; has been activated by the tuple [Data]
alert
00:00:10 Facts (2):
Data[timestamp=Thu Jan 01 02:00:00 EET 1970,name=/Smart/Status,value=Unavailable]
Data[timestamp=Thu Jan 01 02:00:05 EET 1970,name=/Smart/Status,value=Unavailable]
00:00:10 --&gt; inserted: Data[timestamp=Thu Jan 01 02:00:10 EET 1970,name=/Smart/Status,value=Unavailable]
00:00:10 --&gt; fireAllRules
00:00:15 &lt;-- &#39;status not available for 10 seconds&#39; has been activated by the tuple [Data]
alert
00:00:15 Facts (3):
Data[timestamp=Thu Jan 01 02:00:00 EET 1970,name=/Smart/Status,value=Unavailable]
Data[timestamp=Thu Jan 01 02:00:05 EET 1970,name=/Smart/Status,value=Unavailable]
Data[timestamp=Thu Jan 01 02:00:10 EET 1970,name=/Smart/Status,value=Unavailable]
00:00:15 --&gt; inserted: Data[timestamp=Thu Jan 01 02:00:15 EET 1970,name=/Smart/Status,value=Unavailable]
00:00:15 --&gt; fireAllRules
00:00:20 &lt;-- &#39;status not available for 10 seconds&#39; has been activated by the tuple [Data]
alert
00:00:20 Facts (3):
Data[timestamp=Thu Jan 01 02:00:05 EET 1970,name=/Smart/Status,value=Unavailable]
Data[timestamp=Thu Jan 01 02:00:10 EET 1970,name=/Smart/Status,value=Unavailable]
Data[timestamp=Thu Jan 01 02:00:15 EET 1970,name=/Smart/Status,value=Unavailable]
00:00:20 --&gt; inserted: Data[timestamp=Thu Jan 01 02:00:20 EET 1970,name=/Smart/Status,value=Unavailable]
00:00:20 --&gt; fireAllRules
00:00:25 &lt;-- &#39;status not available for 10 seconds&#39; has been activated by the tuple [Data]
alert
00:00:25 Facts (3):
Data[timestamp=Thu Jan 01 02:00:10 EET 1970,name=/Smart/Status,value=Unavailable]
Data[timestamp=Thu Jan 01 02:00:15 EET 1970,name=/Smart/Status,value=Unavailable]
Data[timestamp=Thu Jan 01 02:00:20 EET 1970,name=/Smart/Status,value=Unavailable]
00:00:30 &lt;-- &#39;status not available for 10 seconds&#39; has been activated by the tuple [Data]
alert
00:00:30 Facts (2):
Data[timestamp=Thu Jan 01 02:00:15 EET 1970,name=/Smart/Status,value=Unavailable]
Data[timestamp=Thu Jan 01 02:00:20 EET 1970,name=/Smart/Status,value=Unavailable]
00:00:35 Facts (1):
Data[timestamp=Thu Jan 01 02:00:20 EET 1970,name=/Smart/Status,value=Unavailable]
00:00:40 Facts (0):

huangapple
  • 本文由 发表于 2020年9月16日 18:05:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/63917707.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定