一、运行环境

以下所有的描述都是基于Activiti的5.20.0.1版本

 public interface ProcessEngine extends EngineServices {

   /** the version of the activiti library */
public static String VERSION = "5.20.0.1"; /** The name as specified in 'process-engine-name' in
* the activiti.cfg.xml configuration file.
* The default name for a process engine is 'default */
String getName(); void close();
}

二、Activiti不支持分布的原因分析

  1. next.dbid
  2. schema.history
  3. schema.version

其中next.dbid对应的值为数据库中当前最近一次增长后的最大记录id,每次增长的步长为2500,

protected int idBlockSize = 2500; (在ProcessEngineConfiguration类中)

  • Activiti中所有的id(如:Task的id,Execution的id,ProcessInstance的id等)都是通过IdGenerator来生成的
 /**
* generates {@link IdBlock}s that are used to assign ids to new objects.
*
* The scope of an instance of this class is process engine,
* which means that there is only one instance in one process engine instance.
*
* @author Tom Baeyens
* @author Joram Barrez
*/
public interface IdGenerator { String getNextId(); }
  • IdGenerator的默认实现是
 /**
* @author Tom Baeyens
*/
public class DbIdGenerator implements IdGenerator { protected int idBlockSize;
protected long nextId = 0;
protected long lastId = -1; protected CommandExecutor commandExecutor;
protected CommandConfig commandConfig; public synchronized String getNextId() {
if (lastId<nextId) {
getNewBlock();
}
long _nextId = nextId++;
return Long.toString(_nextId);
} protected synchronized void getNewBlock() {
IdBlock idBlock = commandExecutor.execute(commandConfig, new GetNextIdBlockCmd(idBlockSize));
this.nextId = idBlock.getNextId();
this.lastId = idBlock.getLastId();
}

从上面的代码可以看出,获取下一个id的方法是加锁的,也就是在一台服务器上id的增长是没有问题的,但是如果将Activiti部署在多台服务器上就会有两个问题

  1. 从代码的第17,18行可以看出id是本地自增,如果有多台服务器就会出现id相同的情况(由并发写造成的);
  2. 获取lastId的方法是操作同一个数据库的,会有问题,代码22中通过执行GetNextIdBlockCmd来获取数据库中的next.dbid的值,如果在多台服务器上由于一台服务器修改后,其他服务器无法知道
 /**
* @author Tom Baeyens
*/
public class GetNextIdBlockCmd implements Command<IdBlock> { private static final long serialVersionUID = 1L;
protected int idBlockSize; public GetNextIdBlockCmd(int idBlockSize) {
this.idBlockSize = idBlockSize;
} public IdBlock execute(CommandContext commandContext) {
PropertyEntity property = (PropertyEntity) commandContext
.getPropertyEntityManager()
.findPropertyById("next.dbid");
long oldValue = Long.parseLong(property.getValue());
long newValue = oldValue+idBlockSize;
property.setValue(Long.toString(newValue));
return new IdBlock(oldValue, newValue-1);
}
}

三、解决方案

要想解决Activiti分布式的问题,就需要解决id生成的问题,也就是要自己实现IdGenerator接口,因此要有一个地方来生成一个全局唯一的id才行。

我在实际工作中是通过redis来实现的,redis也可以做集群,因此不需要考虑redis单点的问题,具体方案如下:

 /**
* 分布式id生成器
*
* @version 1.0
* @author Pin Xiong
* @date 创建时间:2016年8月12日 下午3:22:09
*/
public class DistributedIdGenerator implements IdGenerator { public DistributedIdGenerator(RedisService redisService) {
this.redisService = redisService;
} private RedisService redisService; @Override
public String getNextId() {
return String.format("%sX%s", D.formatDate(Constants.ACTIVITI_ENGINE_DISTRIBUTED_ID_PREFIX),this.redisService.incrby(Constants.ACTIVITI_ENGINE_DISTRIBUTED_ID_KEY, 1L));
}
}

其中,D.formatDate(Constants.ACTIVITI_ENGINE_DISTRIBUTED_ID_PREFIX)是通过服务器时间来生成id的前缀,

重点是后面的this.redisService.incrby(MainRK.ACTIVITI_ENGINE_DISTRIBUTED_ID_KEY, 1L)

该方法是在redis中获取key (也就是代码中Constants.ACTIVITI_ENGINE_DISTRIBUTED_ID_KEY)对应的值,并自增1

在实际工作中通过该方案可以解决Activiti分布式问题。

如果其他同学有更好的方案,也希望可以一起分享,谢谢!

Activiti工作流--分布式实现方案的更多相关文章

  1. Activiti工作流学习-----基于5.19.0版本(1)

    该版本的Activiti运行须知: 1.JDK 6+,Eclipse最好是Kepler以上版本. 2.试验功能都有EXPERIMENTAL标注,被标注的部分不应该视为稳定的. 有兴趣的同学可以去了解下 ...

  2. activiti工作流的web流程设计器整合视频教程 SSM和独立部署

    本视频为activiti工作流的web流程设计器整合视频教程 整合Acitiviti在线流程设计器(Activiti-Modeler 5.21.0 官方流程设计器) 本视频共讲了两种整合方式 1. 流 ...

  3. activiti工作流的web流程设计器整合视频教程 SSM 和 独立部署

    本视频为activiti工作流的web流程设计器整合视频教程 整合Acitiviti在线流程设计器(Activiti-Modeler 5.21.0 官方流程设计器) 本视频共讲了两种整合方式 1. 流 ...

  4. Activiti工作流学习(三)Activiti工作流与spring集成

    一.前言 前面Activiti工作流的学习,说明了Activiti的基本应用,在我们开发中可以根据实际的业务参考Activiti的API去更好的理解以及巩固.我们实际的开发中我们基本上都使用sprin ...

  5. activiti工作流的web流程设计器整合视频教程

    本视频为activiti工作流的web流程设计器整合视频教程 整合Acitiviti在线流程设计器(Activiti-Modeler 5.21.0 官方流程设计器) 本视频共讲了两种整合方式 1. 流 ...

  6. Activiti工作流学习(一)部署对象和流程定义

    一.前言 前一段时间在工作中,使用了流程审批,对api的调用非常不熟悉,都是调用别人写好的接口在界面上进行显示,基本了解了流程审批的主要步骤,现对流程审批进行学习,主要是调用api进行CRUD操作,感 ...

  7. Activiti工作流引擎参考资料

    Activiti工作流引擎使用 工作流-Activiti核心API介绍 传智播客Activiti工作流视频教程(企业开发实例讲解) 工作流引擎Activiti演示项目 http://www.kafei ...

  8. Memcached常规应用与分布式部署方案

    1.Memcached常规应用 $mc = new Memcache(); $mc->conncet('127.0.0.1', 11211); $sql = sprintf("SELE ...

  9. Window Redis分布式部署方案 java

    Redis分布式部署方案 Window 1.    基本介绍 首先redis官方是没有提供window下的版本, 是window配合发布的.因现阶段项目需求,所以研究部署的是window版本的,其实都 ...

随机推荐

  1. Com训练_1

    初次接触Com大概是2001年,离现在多年了,那时认识比较肤浅,再次接触学习下. //ComPort + D7, 稍后将训练ComPort6 + D10.3.2环境 //MSComm + D7,D10 ...

  2. 将MySQL库的表转入到MSSQL中的某个库中(Employees下的Employees表 → pubs库下)_2

    将MySQL库的表转入到MSSQL中的某个库中(Employees下的Employees表 → pubs库下, 此pubs下的表名是employee,不冲突),方法大致以下几个(另有其他方法待补充), ...

  3. (五)使用logback进行日志记录

    原文:https://www.cnblogs.com/taiyonghai/p/9290641.html 引入jar包 此处如果是引用了spring boot则不需要再引一下的jar包了,spring ...

  4. 【JMeter_08】JMeter逻辑控制器__While控制器<While Controller>

    While控制器<While Controller> 业务逻辑: 当条件为非false时,执行该节点下的脚本内容,判断条件包括数字.null.空白.字母.符号.true. 当条件为fals ...

  5. Oracle调优之看懂Oracle执行计划

    @ 目录 1.文章写作前言简介 2.什么是执行计划? 3.怎么查看执行计划? 4.查看真实执行计划 5.看懂Oracle执行计划 5.1 查看explain 5.2 explain执行顺序 5.3 访 ...

  6. C#多线程编程(一)进程与线程

    一. 进程 简单来说,进程是对资源的抽象,是资源的容器,在传统操作系统中,进程是资源分配的基本单位,而且是执行的基本单位,进程支持并发执行,因为每个进程有独立的数据,独立的堆栈空间.一个程序想要并发执 ...

  7. PHP丨PHP基础知识之数据类型

    PHP的数据类型主要有三大种:(细分的话8小种) 一.标量数据类型 标量数据类型包括以下几种: (1)BOOLEAN:布尔型 布尔变量是PHP变量中最简单的: 它保存一个TRUE或者FALSE值: 其 ...

  8. Java垃圾回收机制(GC)

    Java内存分配机制 这里所说的内存分配,主要指的是在堆上的分配,一般的,对象的内存分配都是在堆上进行,但现代技术也支持将对象拆成标量类型(标量类型即原子类型,表示单个值,可以是基本类型或String ...

  9. django python mange.py runserver 源码

    django python mange.py runserver 源码 入 口 mange.py文件 execute_from_command_line函数 输入参数为['manage.py', 'r ...

  10. Python 分布式缓存之Reids数据类型操作

    目录 1.Redis API 2.String 操作 3.Hash 操作 4.List 操作 1.Redis API 1.操作模式 redis-py提供两个类Redis和StrictRedis用于实现 ...