Drools-engine 8.29.0.Final内存问题:步骤、依赖及占用原因问询
Drools在微服务中的使用疑问与解答
背景说明
我们在微服务中使用Drools,通过UI接收用户定义的规则,经Velocity模板生成DRL文件。规则执行分为两部分(已实现KieBase缓存):
1. KieBase生成与缓存代码
KieHelper kieHelper = new KieHelper(); kieHelper.setClassLoader(this.getClass().getClassLoader()); String drl = "drl"; kieHelper.addContent(drl, ResourceType.DRL ); Results res = kieHelper.verify(); KieBaseConfiguration kbConf = KieServices.Factory.get().newKieBaseConfiguration(); kbConf.setOption( EqualityBehaviorOption.EQUALITY ); KieBase kieBase = kieHelper.build( kbConf );
2. 基于缓存KieBase的规则执行代码
KieSessionConfiguration ksConf = KnowledgeBaseFactory.newKnowledgeBase().getSessionConfiguration(); ((SessionConfiguration) ksConf).setBeliefSystemType(BeliefSystemType.DEFEASIBLE); ksConf.setProperty("type", "stateful"); KieSession kieSession = kieBase.newKieSession(); kieSession.setGlobal("rules", rules); Collection<KiePackage> kiePackages = kieSession.getKieBase().getKiePackages(); kieSession.insert(request); kieSession.insert(response); try { kieSession.fireAllRules(); }catch( ConsequenceException x ){ logger.warn( "Consequence exception", x); } finally { kieSession.dispose(); }
使用的Drools依赖
<dependency> <groupId>org.drools</groupId> <artifactId>drools-engine</artifactId> <version>${drools-engine.version}</version> </dependency> <dependency> <groupId>org.drools</groupId> <artifactId>drools-mvel</artifactId> <version>${drools-mvel.version}</version> </dependency> <dependency> <groupId>org.drools</groupId> <artifactId>drools-serialization-protobuf</artifactId> <version>${drools-serialization-protobuf.version}</version> </dependency> <dependency> <groupId>org.drools</groupId> <artifactId>drools-xml-support</artifactId> <version>${drools-xml-support.version}</version> </dependency>
技术疑问解答
1. 当前规则执行步骤是否符合规范?
整体方向符合Drools最佳实践,但存在几个细节问题:
- KieSessionConfiguration创建冗余:无需通过
KnowledgeBaseFactory.newKnowledgeBase().getSessionConfiguration()新建KnowledgeBase来获取配置,规范写法是直接用KieServices创建:KieSessionConfiguration ksConf = KieServices.Factory.get().newKieSessionConfiguration(); - 无效代码需清理:
Collection<KiePackage> kiePackages = kieSession.getKieBase().getKiePackages();如果没有后续业务使用,属于无效操作,建议删除。 - 多余配置项:KieSession默认就是有状态(stateful)的,无需通过
ksConf.setProperty("type", "stateful");显式设置。 - 合规部分:缓存线程安全的KieBase、每次请求创建新KieSession、在finally块中dispose KieSession,这些都是正确的做法。
2. 使用的Drools依赖是否合适?
依赖配置有优化空间:
- 版本统一:当前使用多个版本变量管理Drools依赖,容易引发版本冲突,建议统一用一个
${drools.version}变量管理所有Drools相关依赖的版本。 - 冗余依赖清理:
drools-serialization-protobuf:仅当需要序列化KieSession或规则对象时才需要,无序列化需求可移除。drools-xml-support:用于支持XML格式规则,若仅使用DRL文件,可移除该依赖。
- 潜在依赖补充:部分Drools版本中
drools-engine未包含DRL编译模块,若运行时出现编译相关错误,需添加drools-compiler依赖。
3. 为何内存占用过高(20GB容器中内存占比达95%),已做缓存仍无改善?
缓存KieBase仅解决重复编译的内存消耗,内存过高可能由以下原因导致:
- KieBase缓存堆积:如果用户频繁修改规则,每次修改生成新KieBase,旧实例未及时从缓存中清理,会导致大量KieBase堆积占用内存,需设置缓存淘汰策略(如过期时间、数量上限)。
- KieSession相关问题:
- 高并发场景下短时间创建大量KieSession,JVM GC可能无法及时回收已dispose的实例,导致内存临时飙升。
- 插入KieSession的
request/response对象过大,或被其他线程/缓存持有引用,即使KieSession被dispose,这些业务对象也无法被GC回收。
- 规则本身的问题:
- 规则数量过多、条件过于复杂(如嵌套大量循环),会导致KieBase内存占用剧增。
- 规则执行过程中生成大量临时中间对象,未及时清理引发内存堆积。
- JVM配置问题:容器内存20GB但JVM堆内存设置不合理(过大导致GC压力大,过小引发频繁Full GC),都会导致内存占用异常。
- 内存泄漏:需通过JProfiler、VisualVM等工具抓取内存快照,排查是否存在KieBase、KieSession或业务对象的内存泄漏(如静态引用未释放、监听器未注销)。
内容的提问来源于stack exchange,提问作者Sharan
相关产品推荐
相关产品推荐

