一、运行环境

以下所有的描述都是基于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. [noi.ac省选模拟赛]第11场题解集合

    题目   比赛界面. T1   比较简单.容易想到是求鱼竿的最大独立集.由于题目的鱼竿可以被分割为二分图,就可以想到最大匹配.   尝试建边之后会发现边的数量不小,但联系题目性质会发现对于一条鱼竿,它 ...

  2. 分析ThreadLocal的弱引用与内存泄漏问题

    目录 一.介绍 二.问题提出 2.1内存原理图 2.2几个问题 三.回答问题 3.1为什么会出现内存泄漏 3.2若Entry使用弱引用 3.3弱引用配合自动回收 四.总结 一.介绍 之前使用Threa ...

  3. 从mysql数据库中查询最新的一条数据的方法

    第一种方法 SELECT * from a where id = (SELECT max(id) FROM a); 第二种方法: select * FROM 表名 ORDER BY id DESC L ...

  4. ESP8266局域网智能家居 路由器下作服务器模式串口透传 无线通信控制 arduino uno示例 模板参考

    准备工作 下载一个Arduino IDE, 下载8266的库文件 ESP8266服务器模式串口透传编译 功能说明 1.直接使用路由器中转数据 2.手机放热点模式直接传输数据 两者有访问IP地址的差别, ...

  5. The following packages will be SUPERCEDED by a higher-priority channel是什么意思?

    参考资料: https://stackoverflow.com/questions/42015732/the-following-packages-will-be-superceded-by-a-hi ...

  6. Android学习笔记Log类输出日志信息

    Log类提供的方法 代码示例 .. Log.e(TAG,"[错误信息]"); Log.w(TAG,"[警告信息]"); Log.i(TAG,"[普通信 ...

  7. 使用SpringCloud Stream结合rabbitMQ实现消息消费失败重发机制

    前言:实际项目中经常遇到消息消费失败了,要进行消息的重发.比如支付消息消费失败后,要分不同时间段进行N次的消息重发提醒. 本文模拟场景 当金额少于100时,消息消费成功 当金额大于100,小于200时 ...

  8. 爬取B站弹幕并且制作词云

    目录 爬取弹幕 1. 从手机端口进入网页爬取找到接口 2.代码 制作词云 1.文件读取 2.代码 爬取弹幕 1. 从手机端口进入网页爬取找到接口 2.代码 import requests from l ...

  9. js的原型和原型链

    总结: 1.每一个函数都有一个prototype属性,默认指向object空对象(原型对象), 每一个原型对象都有一个constructor属性,指向函数对象. eg: Person函数:     P ...

  10. 关于对Entity Framework 3.1的理解与总结

    Entity Framework Core 是一个ORM,所谓ORM也是ef的一个框架之一吧,简单的说就是把C#一个类,映射到数据库的一个表,把类里面的属性映射到表中的字段.然后Entity Fram ...