Camunda7 - 集群部署的分析 | 字痕随行
首先,先看一下官方对于Camunda分布式部署的说明。可以参考它的官方文档:
https://docs.camunda.org/manual/latest/introduction/architecture/
这是英文的,大概看一下Clustering Model这个章节。此章节确定了一点,如果多个流程引擎的实例连接的是同一个数据库,是可以在流程引擎层面实现集群部署的。
所以本文主要着眼于两点进行分析:
- 每一次触发流程运行(调用taskComplete),必从数据库获取最新的数据,执行完毕后,必将数据持久化到数据库,即:每一个流程引擎实例不会在运行中缓存数据,影响到下一次的触发。
- 在任何一个流程引擎实例部署新的流程定义,在其它的流程引擎实例启动流程时,会使用最新的流程定义。
先分析第一点:
仍旧由taskComplete方法入手,很明显的一段查询代码如下:
TaskManager taskManager = commandContext.getTaskManager();
TaskEntity task = taskManager.findTaskById(taskId);
看看最终是怎么查询task数据的:
public <T extends DbEntity> T selectById(Class<T> entityClass, String id) {
T persistentObject = dbEntityCache.get(entityClass, id);
if (persistentObject!=null) {
return persistentObject;
}
persistentObject = persistenceSession.selectById(entityClass, id);
if (persistentObject==null) {
return null;
}
// don't have to put object into the cache now. See onEntityLoaded() callback
return persistentObject;
}
在上面的代码中,dbEntityCache一看就是从缓存查找,那persistenceSession就是从数据库查询了。
先看看dbEntityCache,这个地方其实就是从Map里面Get,仅从这里无法确定这数据是不是会被永久缓存。
其实,完全可以看看commandContext.getTaskManager(),由此可以看看commandContext是从哪里来的。
因为,我们都知道,Activiti、Flowable、Camunda都是基于命令链模式的,而且它们这块命令链的代码都差不多。
所以,直接看CommandContextInterceptor里面的:
Context.getCommandContext()
就会发现,CommandContext被保存在当前线程里:
protected static ThreadLocal<Deque<CommandContext>> commandContextThreadLocal = new ThreadLocal<Deque<CommandContext>>();
依照这个,再看其它相关的代码,就会发现Session、Cache都是保存在ThreadLocal的,这其实就可以保证数据不会扩散,不会影响到当前线程之外的其它处理结果。
在之前的Flowable相关文章里面也分析过,这些流程引擎数据写入数据库其实是在命令链结束时一次写入的,也就是在CommandContext的close方法内:
public void close(CommandInvocationContext commandInvocationContext) {
}
至此,其实第一个问题已经分析完了,结论就是:每一个流程引擎实例不会在运行中缓存数据,影响到下一次的触发,而且每一次新的调用都会重新从数据库中初始化数据。
再来分析第二点:
直接由启动流程的代码入手
@Override
public ProcessInstance startProcessInstanceByKey(String processDefinitionKey) {
return createProcessInstanceByKey(processDefinitionKey)
.execute();
}
依此定位到GetDeployedProcessDefinitionCmd的流程定义查询方法
ProcessDefinitionEntity processDefinition = find(commandContext);
直接跟到最后的查询方法
public T findDeployedLatestDefinitionByKey(String definitionKey) {
T definition = getManager()
.findLatestDefinitionByKey(definitionKey);
checkInvalidDefinitionByKey(definitionKey, definition);
definition = resolveDefinition(definition);
return definition;
}
findLatestDefinitionByKey其实就是从数据库查询数据。到此,第二点也分析完了,结论就是:每次启动都从数据库查询最新的流程定义。
所以,只要是共享数据库,Camunda就是支持多流程引擎实例部署的,它运行时的所需的数据都是从数据库中获取最新的,并且运行完成后,会立即更新到数据库中。
但是,官方的文档中也指出了,负载均衡是需要单独支持的。举个例子,taskComplete并发了,并且两个请求打到了两个流程引擎实例上,这时候其实是有问题的,所以在更上层还是需要分布式锁来控制。
如果有问题,欢迎指正讨论。
觉的不错?可以关注我的公众号↑↑↑