Drools 7.55.0加载10万级规则内存占用高、启动慢问题咨询
Drools 7.55.0.Final 内存占用过高、启动慢、首请求耗时长问题排查
业务场景
我们当前使用Drools V 7.55.0.Final版本进行开发,业务场景为:每次API请求仅需处理1-10个Fact对象,但需匹配的规则总量约为10万条。
单条规则示例如下:
rule "Rule-000000-2627" when discountObject: Discount(purchaseSource == "FLIPKART" && customerType == "NEW" && bank == "HDFC" && purchaseType == "BNPL" && apparelType == "SHIRT" && price >= 100 && price < 200) then discountObject.setDiscount(2); end
业务使用的Discount实体类定义如下:
public class Discount { private String name; private String purchaseSource; private String customerType; private String bank; private String purchaseType; private String apparelType; private int price; private int discount; }
现有集成代码
Drools配置类
public class DroolDiscountConfig { private KieServices kieServices = KieServices.Factory.get(); @Value( "${drool.rule.file}" ) private String droolConfigFile; private KieFileSystem getKieFileSystem() throws IOException { KieFileSystem kieFileSystem = kieServices.newKieFileSystem(); Long startTime = Utility.startTime(); String[] droolFiles = this.droolConfigFile.split(","); for(String droolFile: droolFiles) { kieFileSystem.write(ResourceFactory.newFileResource(droolFile)); } Long elapseTime = Utility.elapsedTime(startTime); System.out.println("Completed loading drool file " + droolConfigFile + " in " + elapseTime); return kieFileSystem; } @Bean public KieContainer getKieContainer() throws IOException { System.out.println("Container created..."); getKieRepository(); Long startTimeKieBuilder = Utility.startTime(); KieBuilder kb = kieServices.newKieBuilder(getKieFileSystem()); kb.buildAll(); System.out.println("Kie builder took " + Utility.elapsedTime(startTimeKieBuilder)); Long startTimeKieModule = Utility.startTime(); KieModule kieModule = kb.getKieModule(); System.out.println("Kie Module generation took " + Utility.elapsedTime(startTimeKieModule)); Long startTimeKieContainer = Utility.startTime(); KieContainer kContainer = kieServices.newKieContainer(kieModule.getReleaseId()); System.out.println("KieContainer generation took " + Utility.elapsedTime(startTimeKieContainer)); return kContainer; } private void getKieRepository() { Long startTimeKieRepo = Utility.startTime(); final KieRepository kieRepository = kieServices.getRepository(); kieRepository.addKieModule(new KieModule() { public ReleaseId getReleaseId() { return kieRepository.getDefaultReleaseId(); } }); System.out.println("KieRepo generation took " + Utility.elapsedTime(startTimeKieRepo)); } }
接口层Controller代码
@RestController public class DiscountController { @Autowired private KieContainer kieContainer; @PostMapping("/discount") public List<Discount> viewDiscount(@RequestBody List<Discount> discounts) { StatelessKieSession statelessKieSession = kieContainer.newStatelessKieSession(); statelessKieSession.execute(discounts); return discounts; } }
现存问题
当前我们将所有规则写入单个大小为40MB的drl文件中,服务启动时内存占用高达5-6GB;通过VisualVM分析内存dump发现,大部分内存被byte[]与String[]类型对象占用,未定位到具体异常根因。我们需要确认当前Drools的使用方式是否符合最佳实践,以及如何优化以降低过高的内存消耗。
除此之外还存在三个明确问题:
- 首个API请求响应耗时过长,约30秒
- 服务整体启动耗时过长,约5分钟
- 若将JVM堆内存限制为3-4GB,服务启动过程中会抛出
OutOfMemoryError错误,错误栈如下:
ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'discountController': Unsatisfied dependency expressed through field 'kieContainer'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'getKieContainer' defined in class path resource [load/test/DroolDiscountConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.kie.api.runtime.KieContainer]: Factory method 'getKieContainer' threw exception; nested exception is java.lang.OutOfMemoryError: Java heap space
内容的提问来源于stack exchange,提问作者Juvenik
相关产品推荐
相关产品推荐

