You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Camunda DeploymentCache内存占用问题及精细化管控需求

Camunda DeploymentCache内存占用过高的优化方案(7.13.0版本)

问题背景

堆转储分析显示,Camunda组件org.camunda.bpm.engine.impl.persistence.deploy.cache.DeploymentCache占用了69.47%的JVM内存,其中org.camunda.bpm.engine.impl.persistence.deploy.cache.BpmnModelInstanceCache占比高达69.03%。
原因在于Camunda启动时会全量加载数据库中所有已部署的流程定义、案例定义和决策定义,而当前系统存在数万条流程定义,导致内存占用过高。

当前采用org.camunda.bpm.engine.RepositoryService#deleteDeployment(java.lang.String, boolean)方法删除旧部署缓解内存问题,代码如下:

List<Deployment> oldDeployments = repositoryService.createDeploymentQuery()
        .deploymentBefore(date)
        .listPage(0, maxResult);
boolean cascade = true;

for (Deployment deployment : oldDeployments) {
    repositoryService.deleteDeployment(deployment.getId(), cascade);
}

但该方案缺乏管控能力,核心支付类流程即使过期也不能被删除,需作为例外处理。以下是针对性的优化方案:


方案一:添加业务判断处理器,精准管控可删除部署

在现有删除逻辑中加入业务校验步骤,通过查询业务数据表的额外标识,判断部署是否允许被删除:

示例代码修改

List<Deployment> oldDeployments = repositoryService.createDeploymentQuery()
        .deploymentBefore(date)
        .listPage(0, maxResult);
boolean cascade = true;

for (Deployment deployment : oldDeployments) {
    // 1. 通过部署ID/关联业务标识查询是否为核心流程
    boolean isCoreProcess = businessProcessService.isCorePaymentProcess(deployment.getId());
    // 2. 核心流程直接跳过删除
    if (isCoreProcess) {
        continue;
    }
    // 3. 非核心流程执行删除
    repositoryService.deleteDeployment(deployment.getId(), cascade);
}

其中businessProcessService.isCorePaymentProcess为自定义业务方法,可根据部署关联的流程key、业务标签等标识,判断是否属于不可删除的核心流程。


方案二:排除特定模式的部署,从查询阶段过滤

直接在部署查询时排除特定模式的部署,避免加载到待删除列表中:

示例代码修改

// 排除名称包含"payment-core"的核心支付部署,同时排除指定流程key的部署
List<Deployment> oldDeployments = repositoryService.createDeploymentQuery()
        .deploymentBefore(date)
        .deploymentNameNotLike("%payment-core%")
        .processDefinitionKeyNotIn("core-payment-flow")
        .listPage(0, maxResult);
boolean cascade = true;

for (Deployment deployment : oldDeployments) {
    repositoryService.deleteDeployment(deployment.getId(), cascade);
}

可根据实际业务规则,通过部署名称、流程key、租户ID等多维度条件过滤,直接排除不可删除的部署。


方案三:自定义DeploymentCache,优化加载与缓存策略

针对Camunda启动全量加载的特性,通过自定义DeploymentCache实现按需加载或容量限制:

1. 设置缓存容量上限

Camunda 7.13.0支持通过配置参数限制缓存容量,在application.yml中添加:

camunda:
  bpm:
    deployment-cache:
      bpmn-model-cache-capacity: 5000  # 设置BpmnModelInstanceCache的最大容量
      process-definition-cache-capacity: 5000  # 设置流程定义缓存容量

当缓存达到上限时,会自动淘汰最少使用的缓存条目,避免内存持续增长。

2. 自定义DeploymentCache实现按需加载

扩展DefaultDeploymentCache,重写初始化逻辑,启动时仅加载指定时间段内的部署,其余流程按需动态加载:

public class CustomDeploymentCache extends DefaultDeploymentCache {

    private final RepositoryService repositoryService;
    private final Date loadStartTime;

    public CustomDeploymentCache(CacheFactory cacheFactory, RepositoryService repositoryService, Date loadStartTime) {
        super(cacheFactory);
        this.repositoryService = repositoryService;
        this.loadStartTime = loadStartTime;
    }

    @Override
    protected void deploymentsAdded(List<Deployment> deployments) {
        // 仅加载指定时间范围内的部署
        List<Deployment> filteredDeployments = deployments.stream()
                .filter(d -> d.getDeploymentTime().after(loadStartTime))
                .collect(Collectors.toList());
        super.deploymentsAdded(filteredDeployments);
    }

    // 重写流程定义获取方法,未缓存时动态加载
    @Override
    public ProcessDefinition findProcessDefinitionById(String processDefinitionId) {
        ProcessDefinition definition = super.findProcessDefinitionById(processDefinitionId);
        if (definition == null) {
            // 从数据库查询并加载到缓存
            definition = repositoryService.createProcessDefinitionQuery()
                    .processDefinitionId(processDefinitionId)
                    .singleResult();
            if (definition != null) {
                deploy(repositoryService.getDeployment(definition.getDeploymentId()));
            }
        }
        return definition;
    }
}

然后通过配置类替换默认的DeploymentCache:

@Configuration
public class CamundaCacheConfig {

    @Bean
    public DeploymentCache customDeploymentCache(CacheFactory cacheFactory, RepositoryService repositoryService) {
        // 仅加载最近30天的部署
        Date thirtyDaysAgo = DateUtils.addDays(new Date(), -30);
        return new CustomDeploymentCache(cacheFactory, repositoryService, thirtyDaysAgo);
    }
}

注意:按需加载需权衡性能,建议配合缓存过期策略使用,避免频繁查询数据库。


内容的提问来源于stack exchange,提问作者leonaugust

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 16:01:48