英文:
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("myData");
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 "org.drools.core.common.EventFactHandle", loaded by "jdk.internal.loader.ClassLoaders$AppClassLoader @ 0x702500000" occupy 113,316,792 (71.06%) bytes. These instances are referenced from one instance of "java.lang.Thread", loaded by "<system class loader>"
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<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);
}
}
catch(Exception ex)
{
//error
}
Here's an example of the rules I have:
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
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
<kmodule>
...
<kbase name="KBase2" default="false" eventProcessingMode="stream" packages="org.domain.pkg2, org.domain.pkg3" includes="KBase1">
...
</kbase>
...
</kmodule>
It happened in previous versions of drools that explicit event retraction worked better
rule "retract expired events"
salience 1
duration 20000
when
d: Data() from entry-point "myData"
then
retract(d);
end
This is how I tested your code
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:05 --> inserted: Data[timestamp=Thu Jan 01 02:00:05 EET 1970,name=/Smart/Status,value=Unavailable]
00:00:05 --> fireAllRules
00:00:10 <-- 'status not available for 10 seconds' 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 --> inserted: Data[timestamp=Thu Jan 01 02:00:10 EET 1970,name=/Smart/Status,value=Unavailable]
00:00:10 --> fireAllRules
00:00:15 <-- 'status not available for 10 seconds' 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 --> inserted: Data[timestamp=Thu Jan 01 02:00:15 EET 1970,name=/Smart/Status,value=Unavailable]
00:00:15 --> fireAllRules
00:00:20 <-- 'status not available for 10 seconds' 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 --> inserted: Data[timestamp=Thu Jan 01 02:00:20 EET 1970,name=/Smart/Status,value=Unavailable]
00:00:20 --> fireAllRules
00:00:25 <-- 'status not available for 10 seconds' 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 <-- 'status not available for 10 seconds' 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):
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论