思路
首先,drools的整体思路比较简单,一个是加载,一个是执行! 加载:把一个比较复杂的关系运算想办法放到drools里面!
执行:让drools去计算这个复杂的运算,最终我们只需要取结果就好!
用法
加载的方式有很多,可以通过xml,也可以通过drl,也可以maven构建,官网有详细的demo,可以直接拿来用,也有很详细的文档可以参考,github上也有从数据库加载的,看各自项目吧,我们是直接把运算的关系表达式串扔进drools里用的,不同项目适合的方式不一样!
问题
我们的业务场景,会有很多规则先加载,然后等请求到了,同一时间,会有大量请求去执行已经加载好的规则,刚开始一切正常,但是后来发现,并发执行超过30多次、50多次、60多次以上,同样的条件,drools执行完给出的结果就不准确了,还是没有规律的不准确,经过大量的调试、查找,最终定位到是kieBase的问题,因为new
kieBase().newKieSession(),执行完是正确的,但是new好的kieBase放内存里,再拿出来直接调用newKieSession(),结果就不准确了,但是每次都创建新的kieBase,并发大的情况下,平均时间会超过1.5秒,这是不可忍受的,所以就不能每次都new
kieBase。但不new的情况下,为什么前几十次是正确的,后面就不准确了,new的时候它里面做了什么?部分源码如下: 我们用的KieHelper,它直接build(),相当于new kisBase();
一直到kieBase创建结束,也没发现什么特别的地方,看起来都很正常!不过定位的问题我相信是没错的,几种加载规则的方式我都试了,都逃不过kieBase的不准确问题,现象表现的很明显,问题就是出在kieBase,于是又只针对kieBase的问题查找了一番,偶然发现一个小伙伴遇到的是超过20次出现转换异常的问题,他的做法是禁用了JIT编译器,抱着试一试的心态同样禁用了一下,好家伙,真的没问题了!!!
回想上面的源码,发现new KieBase()的时候,确实没管过它的默认配置,看下配置:
确实默认配置里面的jittingThreshold默认值是20,而我们没有类型转换的问题,所以它超过20次才表现出来不准确的问题,所以它是超过20是不保证准确,并不是一定不准确,至此,问题解决!
顺便贴一下代码:
KieServices kieServices = KieServices.Factory.get();
KieBaseConfiguration kieBaseConfiguration = kieServices.newKieBaseConfiguration();
kieBaseConfiguration.setOption(ConstraintJittingThresholdOption.get(-1));//禁用jittingThreshold(阈值默认20,设为-1)
KieSession kieSession = KieHelper.addResource(ResourceFactory.newByteArrayResource(drl.getBytes(StandardCharsets.UTF_8)),ResourceType.DRL).build(kieBaseConfiguration).newKieSession();
kieSession.insert(session);
kieSession.fireAllRules();
kieSession.dispose();