结论 排查问题发现项目内使用的官网推荐的写法,但是并不适用于实际项目中的使用,由于我们的是动态规则使用,所以在规则匹配时是循环创建knowledgeBase,该操作会极大的浪费cpu开
结论
排查问题发现项目内使用的官网推荐的写法,但是并不适用于实际项目中的使用,由于我们的是动态规则使用,所以在规则匹配时是循环创建knowledgeBase,该操作会极大的浪费cpu开销,所以最后本地缓存knowledgeBase来解决问题
官网写法
优化写法
//本地缓存最好换成带自动过期的
public static ConcurrentHashMap<String, KnowledgeBaseImpl> map = new ConcurrentHashMap<>();
public KieSession getKieSession(String drlStr, String id) throws Exception {
//id为活动唯一id
KnowledgeBaseImpl knowledgeBase = map.get(id);
if (!Objects.isNull(knowledgeBase)) {
return knowledgeBase.newStatefulKnowledgeSession();
}
Resource resource = ResourceFactory.newReaderResource(new StringReader(drlStr));
KnowledgeBuilder knowledgeBuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
knowledgeBuilder.add(resource, ResourceType.DRL);
if (knowledgeBuilder.hasErrors()) {
Iterator var4 = knowledgeBuilder.getErrors().iterator();
if (var4.hasNext()) {
KnowledgeBuilderError error = (KnowledgeBuilderError)var4.next();
throw new Exception(error.getMessage());
}
}
KieBaseConfiguration kieBaseConfiguration = KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
//此处需要禁用jini编译,否则会出现匹配不准的情况
kieBaseConfiguration.setOption(ConstraintJittingThresholdOption.get(-1));
knowledgeBase = (KnowledgeBaseImpl)KnowledgeBaseFactory.newKnowledgeBase(kieBaseConfiguration);
knowledgeBase.addKnowledgePackages(knowledgeBuilder.getKnowledgePackages());
map.put(id,knowledgeBase);
return knowledgeBase.newStatefulKnowledgeSession();
注意事项
//注意KieSession使用完后要删除,否则可能会出现频繁触发垃圾回收的情况
FactHandle factHandle = kieSession.insert(custLable);
kieSession.fireAllRules();
kieSession.delete(factHandle);
drools规则引擎优化过程中的坑
1.缓存有状态会话kieSession出现匹配不准的情况
尝试缓存有状态会话KieSession 每次使用完不关闭会话,经过压测结果比对,会发现出现规则匹配不对的情况,且数量较少,上网查证这两个操作在6点多的版本为线程安全的操作,但是压测结果就是出现不准的情况,目前没有找到原因,但考虑KieSession的创建与销毁为轻量级会话,放弃缓存他
kieSession.insert(dto);
kieSession.fireAllRules();
2.redis缓存knowledgeBase性能低
缓存knowledgeBase到redis 做全局的缓存,但是最后在压测的时候,打堆栈看,redis缓存对象,在取出时的反序列化很耗费时间,用的是常用的反序列化jar包,推测可能并发高的时候IO影响的,大对象传输也会导致redis集群出现问题,所以放弃该方案
3.本地缓存knowledgeBase也出现规则匹配不准的情况
因为官方的源码默认使用20次后,将会出现不准的情况,这里没有进行深究,使用禁用jini编译来规避匹配不准的情况