基于REST的云工作流引擎的架构设计
2019-01-07夏怀婷潘金涛
夏怀婷, 潘金涛
(中远海运科技股份有限公司,上海 200135)
0 引 言
工作流引擎是企业将其分散的应用连接起来整合成一个完整的流程应用的调度工作。在传统的工作流引擎系统方案中,企业内所有需使用工作流引擎的应用系统都必须购买并集成工作流引擎系统,导致应用过于复杂,且耦合度较高,不利于云端的部署,难以与不同结构的应用服务交互;同时,只能以流程为单位存储工作流要素,无法以流程节点的层次提供工作流要素给客户复用,难以满足客户对细节定制的需求。
随着企业内的业务系统开始向云(尤其是私有云)中迁移,提供基于私有云的工作流引擎成为必然。在私有云中,可提供基于云的流程建模、流程执行、流程监控分析、流程管理和业务调用。基于REST的工作流引擎在云中具有一定的优势,通过对云中的服务进行编制或编排,满足企业内各业务协作的需要。
在云环境中搭建工作流引擎服务通常有2种方式:
1) 结合云环境的特点,运用工作流技术实现云工作流引擎建模、执行、管理和监控等功能;
2) 将现有的开源工作流引擎移植到云环境中。
当前的云工作流引擎系统大多采用第1种方式,这将带来一些不必要的开销。因此,本文采用第2种方式,即将开源工作流引擎移植到云环境中,在Activiti的基础上设计基于REST(Representational State Transfer)的工作流引擎,使其适应云端部署环境,根据RESTful服务中每个资源结点都可发布并接受访问的特性,将流程、活动和实例等所有工作流要素都封装为REST的资源,从而以流程节点的层次提供可复用的工作流要素。
1 设计目标
云工作流引擎的设计目标主要是将工作流引擎从应用系统中解耦出来,形成一个独立的服务,从而降低系统的耦合性,提供更加灵活的服务支持,实现复杂度可控、独立部署、技术选型灵活、服务容错和按需独立扩展等目标。
1) 复杂度可控:将整体应用分解为一组服务,功能总量没有变化,但应用程序已被分为体积小、复杂度低和可管理的微服务。每个服务专注于单一功能,由专注于该服务的团队独立开发,可大大提高开发效率。
2) 独立部署:微服务架构模式可实现每个微服务独立部署,开发人员无需协调部署本地变更到服务,这些变更经过测试之后即可立即部署。同时,每个微服务在启动方面比大型整体应用快得多,使得发布更为高效,且会加速部署。
3) 技术选型灵活:在微服务架构模式下,技术选型是去中心化的。开发者可自由选择任何符合服务API契约的技术。此外,由于服务较小,采用当前的技术重写旧服务将变得更为可行。
4) 服务容错:当某一服务发生故障时,在单一整体应用的传统架构模式下,故障很可能在整个应用内扩散,形成全局性的不可用;而在微服务架构模式下,故障会被隔离在单个服务中,可通过超时重试、限流、降级和熔断等机制实现服务的容错。
5) 按需独立扩展:传统单体应用架构必须以应用为单位进行横向扩展,在资源需求有冲突时会变得比较困难。引擎微服务化之后,可独立于应用服务,使用负载均衡器进行自由扩展。此外,引擎服务可部署到最适合其资源需求的硬件上,而整体架构中具有严重资源需求差异的组件(如CPU密集和内存密集)必须部署在一起。
2 架构设计
2.1 总体技术架构设计
整个云工作流引擎架构基于云计算平台开发部署,并由微服务、容器和BPM(Business Process Management)等若干技术组件构成,其中:微服务分解BPM应用系统,将应用与引擎微服务化;容器采用Docker技术实现微服务镜像化;BPM组件实现BPM建模、执行、管理和监控等功能,这些功能必须基于“用户权限隔离”底层机制,实现BPM云引擎多租户隔离和交互要求。
当然,服务的平稳运行离不开架构的整体监控和治理,包括服务注册与发现、服务容器管理、服务编排、配置中心、安全管理和日志收集等。该工作流引擎的总体技术架构见图1。
图1 基于REST的云工作流引擎总体技术架构
2.2 关键开发技术
2.2.1 Activiti
Activiti是一个开源的工作流引擎,实现了BPMN 2.0规范,可发布设计好的流程定义,并通过API(Application Programming Interface)进行流程调度。Activiti采用流程虚拟机(Process Virtual Machine, PVM),支持BPMN2.0规范以外的流程格式,具有与外部服务良好集成的能力,服务接口清晰,已实现部分RESTful接口。
2.2.2 RESTful
图2 面向资源的REST服务访问
图2为面向资源的REST服务访问。REST架构风格将一切都看作是资源,客户端通过GET、PUT、POST和DELETE等4种操作实现与资源的交互。因此,在BPM私有云引擎的设计中,遵循该原理设计BPM引擎的API,并提供基于REST的API。
2.2.3 Spring Boot
Spring Boot用来简化新Spring应用的初始搭建和开发过程。该框架采用特定的方式配置,从而使开发人员不必定义样板化的配置,可专注于应用程序的逻辑。
2.2.4 Spring Cloud
Spring Cloud是一系列框架的有序集合,利用Spring Boot的开发便利性巧妙地简化分布式系统基础设施的开发,服务发现注册、配置中心、消息总线、负载均衡、断路器和数据监控等都可用Spring Boot的开发风格做到一键式启动和部署。
2.3 SAAS服务关键功能实现方式设计
2.3.1 用户权限隔离
SAAS服务的主要特性是支持多租户应用,其关键实现方式是数据隔离(包括组织内的部门用户数据和流程数据)和客户自服务(包括个性定制和管理隔离)。该设计通过租户识别码对多租户进行数据管理,即将多个租户存入同一个数据库中,使用同一个Schema(即将数据保存在一个表格中,通过租户的识别码来区分)。
图3为用户权限隔离的ER图,组织的各个表中都有一个租户识别码,根据该识别码实现组织内用户的隔离,不同租户对各自的组织数据进行维护。在模型表和流程定义表中添加“租户识别码”,通过“租户识别码”字段实现对不同租户流程定义的隔离,该“租户识别码”与组织表中的租户识别码相关联。在流程实例表中添加字段“租户识别码”,活动实例表、工作任务表、流程转移表和流程变量表等都通过“流程实例ID”与流程实例表相关联,因此无需添加租户识别码字段。
图3 用户权限隔离的ER图
2.3.2 用户数据同步
每个涉及到用户的系统都有一套用户权限管理平台或模块,用来维护用户在系统内的功能、数据权限。采用的Activiti工作流引擎配套设计包括User和Group的Identify模块,针对Activiti Identify用户数据的同步,通过调用IdentifyService接口完成同步,即通过数据推送的方式将数据同步到Activiti的身份表中。
Activiti的Identify模块由用户、用户组和用户与组关系组成(见图4),因此接口内容应包括同步用户信息、同步组信息和同步用户与组关系信息等。
图4 Activiti用户组关系图
用于用户、用户组及用户组关系同步的,需开发的REST API为:
1) POST/identity/user/{userId}:同步某个用户数据;
2) POST/identity/group/{groupId}:同步某个组数据;
3) POST/identity/membership/{membershipId}:同步某个用户组关系数据;
4) DELETE/identity/user/{userId}:删除某个用户数据;
5) DELETE/identity/group/{groupId}:删除某个组数据;
6) DELETE/identity/membership/{membershipId}:删除某个用户组关系数据。
2.3.3 REST API设计与实现方式
图5为Activiti引擎的系统服务结构图,给出了引擎提供的所有功能组件。ProcessEngineConfiguration是配置管理类,管理的对象包括ProcessEngine、XXservice和数据库session等。对于ProcessEngineConfiguration的配置,Activiti默认从activiti.cfg.xml中读取,也可从Spring的配置文件中读取。ProcessEngine提供有很多工作流方法的服务,都是线程安全的,下面对各服务的功能进行介绍。
图5 Activiti引擎的系统服务结构图
1) RepositoryService:提供对Repository(BPMN2.0 XML文件、表单定义文件和流程定义图像文件等)的存取服务。
2) RuntimeService:提供启动流程、查询流程实例和设置获取流程实例变量等功能。此外,提供对流程部署、流程定义和流程实例的存取服务。
3) TaskService:提供对用户Task和Form的相关操作及运行时任务查询、领取、完成、删除和变量设置等功能。
4) IdentityService:提供对Activiti系统中用户和用户组的管理功能。
5) ManagementService:提供对Activiti流程引擎的管理和维护功能,这些功能不在工作流驱动的应用程序中使用,主要用于Activiti系统的日常维护。
6) HistoryService:用于获取正在运行或已完成流程实例的信息,与 RuntimeService中获取的流程信息不同,历史信息包含已持久化存储的永久信息,并已被针对查询优化。
7) FormService:可存取启动和完成任务所需的表单数据并根据需要渲染表单。
按照RESTful风格将上述服务提供的接口和访问方法发布为Web资源,各服务对应的REST API见图6。
图6 各服务对应的REST API
以Repository的API为例,对各资源的具体操作类型作简要说明。
1) /repository/models
GET:获取所有模型
POST:创建一个模型
2) /repository/deployments
GET:获取所有已部署的流程
POST:部署一个流程
3) /repository/deployments/{deploymentId}
GET:获取某个部署信息
DELETE:删除某个部署信息
4) /repository/deployments/{deploymentId}/resources
GET:获取某个部署下的资源列表
5) /repository/deployments/{deploymentId}/resources/{resourceId}
GET:获取某个部署下的某个资源信息
3 架构部署
云工作流引擎平台的架构部署包含注册中心、配置中心、调用中心、部署中心、日志中心、监控中心、追踪中心和消息中心等8部分(见图7)。
图7 架构部署
1) 注册中心:用于注册微服务相关配置信息的中心,实现服务发现和服务注册,选用Eureka实现。
2) 配置中心:用于管理微服务应用程序所需的配置参数,选用Spring Cloud Config实现,通过Spring Cloud Bus实现动态的配置更新。
3) 调用中心:即API网关,用于提供给前端调用的统一入口,选用Zuul实现。
4) 部署中心:用于编译、打包微服务源码并将其部署到Docker引擎中,选用Jenkins实现。
5) 日志中心:用于收集和管理微服务应用程序中产生的日志,选用ELK实现。
6) 监控中心:用于监控微服务的实时运行状况,选用zipkin实现。
7) 追踪中心:用于最终调用微服务的轨迹,选用sleuth实现。
8) 消息中心:用于解耦微服务之间的调用关系,同步调用选用REST实现,异步调用选用kafka实现。
在实现工作流引擎的所有接口之后,由部署中心执行编译和打包操作,构建成Docker镜像,最后将其上传到镜像仓库,以便后续从镜像仓库中下载指定的镜像,运行相应的Docker容器。
在Docker镜像上传到镜像仓库之后,部署中心可在不同的运行环境下根据特定的镜像启动相应的Docker容器。为便于描述,将该容器称为“服务容器”,包含承载微服务的应用程序及其配置文件。
在服务容器启动之后,自动从配置中心读取相应的配置信息并将其网络地址等信息写入注册中心,该过程称为“服务注册”。服务容器与注册中心通过一定的机制(例如心跳)通信,注册中心若长时间无法与某服务容器通信,会注销该实例,服务网络地址变更时会重新写入注册中心。
服务容器相互调用时,若链路的某个服务容器不可用或响应时间太长,则调用该服务的链路会产生大量积压,导致积压蔓延,称之为“雪崩效应”。为防止雪崩,当调用某个服务之后发现无法完成时,主动撤销连接,返回fallback的响应信息,防止雪崩,该过程称为“服务熔断”。当系统压力过大时,进行限流或关停不重要的业务,为主要业务让出资源,该过程称为“服务降级”。
用户在通过浏览器或移动端访问引擎系统时,请求首先通过负载均衡进入服务网关,因为其是所有请求调用的中心、系统的唯一入口,也称其为“调用中心”。调用中心虽然是不带任何业务的中心,但需确保其所做的事情足够少,使其不会成为整个应用系统调用的瓶颈,客户端的认证、访问控制、监控和缓存等公共逻辑可抽象到网关中实现。
调用中心随后连接注册中心,并通过服务名称从注册中心获取服务所在的IP地址和端口号(即服务地址),该过程称为“服务发现”。由此,调用中心可根据服务地址,以反向代理的方式调用具体的服务容器,该过程称为“服务调用”。
在服务容器中可能会触发一些事件,这些事件将以消息的方式写入消息中心,以便其他服务对消息中心进行监听并从中获取相应的消息。该方案可解决服务之间的耦合问题,同时能将同步调用转为异步调用,提高整个应用系统的吞吐率。
服务容器在运行时会产生大量的日志,可将这些日志统一写入日志中心,并能在日志中心提供的控制台上查询具体的日志信息。此外,日志中心能帮助快速定位和分析系统出现的异常情况。
为判断服务容器的运行是否正常,可借助监控中心输出的图形化数据来实现。监控中心不断地收集服务容器的运行状态,包括CPU、内存、硬盘、网络及应用程序的JVM内存使用情况等。
由于微服务很难切得干净,除了向外部提供以外,微服务之间难免会出现少量的调用关系,可将每次调用产生的相关信息写入追踪中心,通过追踪中心提供的图形化界面查看服务之间的调用轨迹和产生的调用延时,从而分析出服务调用产生的性能瓶颈。
4 架构应用
简单搭建1个Eureka服务(服务注册中心)、2个应用服务(OA Service)、2个工作流引擎服务(Workflow Service)和1个API网关(Zuul Server),验证上述架构设计的可行性(见图8)。所有服务都需注册到Eureka服务上,以便服务间调用。API网关是系统唯一的入口,主要实现服务请求路由、负载均衡和服务熔断等功能。这里与/oa相关的请求全部转发到OA Service上,与/workflow相关的请求全部转发到Workflow Service上,并选择其中一台服务(Server A或Server B)进行转发,实现服务的负载均衡。同时,OA Service与Workflow Service之间也可通过REST方式调用对方的API,如应用服务可调用引擎服务的用户数据同步接口实现用户信息同步,应用服务的用户待办数据可调用引擎服务获取用户任务的接口,应用服务的流程跟踪可调用引擎流程跟踪接口等。
单体架构应用(见图9)就是将所有功能(OA接口和工作流引擎接口)集成到一起组成一个整体应用,进行集中式管理,简单直接,基本上不会重复开发,但会带来开发效率低、代码维护难、部署不灵活、稳定性不高和可扩展性不强等问题。
图8 微服务架构应用
图9 单体架构应用
由2种应用的对比可知,微服务架构应用将工作流引擎从应用系统中成功地分离出来,由原来的1个完整服务(Application Server)拆分为2个服务(OA Service和Workflow Service), OA Service只需实现业务相关功能接口,工作流引擎相关接口交由Workflow Service完成,从而实现2个服务的独立部署和扩展。
5 结 语
随着云计算的发展和企业集约化、一体化、集中化的发展,云工作流引擎成为企业建立私有云工作流引擎的发展必然,给企业带来更多的经济效益,包括硬件的成本得以降低、硬件资源的使用率大幅提升、平台维护人员大幅减少、数据的管理和管控更加集中;同时,云工作流引擎可带来系统的高可用、可扩展性和自动伸缩等能力。但是,云工作流引擎是分布式系统,会提高部署和管理的复杂性,从而对开发者提出更高的要求。