说到流程人们往往会想到BPM,的确BPM非常成熟,在企业内部应用也非常广泛,本文试图用类似于BPM的方式来解决高并发环境下的程序化运营场景应用。
应用场景
我们是一家从事营销自动化的SaaS公司,我们同时服务于上千家企业客户,我们的系统每秒钟会收到上千个事件,每个事件是key-value的形式,里面的属性并不固定。我们的系统需要在预定的场景下对这些场景做出秒级响应。比如用户在浏览了某一个页面,或点击了某一个按钮后需要迅速通过短信通知到用户,下一步可以做什么,然后根据用户的进一步行为通过适当的渠道推送新的信息给用户。
根据上面的描述,我们需要的是一个能够事件快速响应,而且易于扩展的流程引擎。
有很多BPM的实现都是典型的流程引擎,如Activity,很好的实践了DDD和CQRS。但是这种基于数据库的方案还是不能满足我们的快速和扩展的要求。因此我们把目光放在响应式编程的框架上。
AKKA的优势
1. 基于内存,把IO的影响降低到最小。
2. 事件驱动,能够处理复杂的event和event handler组合。
3. 可扩展,最小化共享可变状态,位置透明,方便横向扩展。
4. 容错性,弱耦合,通用的监督者和容错机制。
简单描述一下用到的技术
Akka:一种适用于高并发分布式环境下的消息驱动工具和运行时框架。
Akka Actor: AKKA中最小的带状态的计算单元,Actor之间的相互作用都通过消息来实现。
Akka FSM: 用Actor 实现的有限状态机。完成类似于在什么状态下发生什么事情则做出什么响应。
MongoDB: 用于保存流程的定义,流程的状态统计等信息,以及各种Actor 的快照。
Kafka: 用于各个模块间的数据传递。
流程相关概念说明
流程部署
首先我们通过一个类似于BPM的流程设计输出一个流程模型(json),简单地说每个模型由启动条件,动作步骤和分支步骤组成。流程模型在设计时是一个json 对象,而在运行时是一组Actor Class。这中间我们通过一个中间的编译装换器来完成流程模型的编译过程。
流程运行
这个模型一旦部署就可以接收他关心的事件,如果某一个用户所做的行为(一个事件)满足了模型的启动条件,这个用户的流程实例将被启动。每一个流程实例由一个Trigger和一个FSM组成。Trigger主要负责条件判断,而FSM负责在每一个预定步骤里对特定事件作出相应。因为流程实例有一定的生命周期,所以在运行时会有大量的流程实例同时运行。为此我们为这些Actor 实现了分片和集群,这些实例可以均匀地分布到不同的服务器上运行。
除了对事件快速响应之外,在流程的执行过程中很多地方都需要延时执行,有的时候需要相对延时有的时候需要绝对延时,相对延时我们采用了Akka FSM的StateTimeout,在某一状态(步骤)保持一定时间后触发,而对于绝对延时我们在Trigger中实现了一个Schedule对模型中定义的固定时间延时作出触发。
流程监控和动作执行
流程实例会将每一个步骤演进和状态变化告诉Monitor, 再由Monitor actor 将这些数据传递到外部持久化服务中。动作执行也是通过共享的Worker actor 来传递到外部相关系统。
消息驱动的核心是对异步的处理,异步处理相对于同步处理更难于调试和监控。在我们的流程引擎一个节点的内存里同时运行着几百万的Actor, 我们使用Kamon和StateD对每一个Actor的健康状况进行监控。
大量的数据都以流的形式传输,计算,存储。要挖掘这些数据的价值需要找出这些流里面的每个单元(事件)之间的关联关系,而流程化程序化的自动处理则是找出这些关系的重要方法之一。在这个产品里面我们深入地实践了响应式编程的思想,为其他人解决类似的问题提供参考。
幸运的是我们找到了Akka,Akka很适合处理需要高并发的问题,尤其是需要保持某些中间状态的数据流处理。
关于作者
李斌,现为营销实验室(www.convertlab.com)数据架构师,10年以上企业软件和互联网产品开发经验,曾任IBM资深中间件专家,平安互联网金融架构师,营销大数据架构师。擅长大型产品基础平台,市场营销优化,深度分析,大数据挖掘。毕业于哈尔滨工业大学。