一、工作流与微服务编排
1. 工作流
提到工作流,印象里都是 OA 系统各种请假审批流。事实上,广义上的工作流是对工作流程及其各操作步骤之间业务规则的抽象、概括、描述。简单理解,我们为了实现某个业务目标,抽象拆解出来的一系列步骤及这些步骤之间的协作关系,就是工作流。例如订单发货流、程序构建流等。业界通常用 BPMN 流程图来描述一个工作流。
(1)没有工作流时的任务协作
以实现一个用户购买逻辑为例,如果不应用工作流模型,我们串联多个任务(步骤)一般是通过显示的代码调用:
校验、支付、发货一气呵成,流畅自然。正喝着枸杞红枣,产品一脸笑意跑过来:“我们新搞个充会员卡的业务,大概步骤就校验 -> 推荐 -> 支付 -> 充值。校验和支付前面都做过了,应该很快实现吧?”
精通 if-else 的你,听完的瞬间就已经构思好了代码:
一通写下来,总感觉哪里不对,“为什么加新的任务节点,要改已有的代码呢?这不符合开闭原则啊!”。
(2)应用工作流模型的任务协作
工作流模型正是为了解决这类问题而生:分离任务的实现和任务的协作关系。上面同样的用户购物逻辑,有了工作流模型,各个任务只实现自己原子的逻辑,任务协作关系使用流程图来表达。
当新的逻辑需要复用已有任务节点时,只需要调整流程图,无需修改已有代码。
2. 工作流引擎
将任务实现与任务协作关系分离之后,就诞生了专门维护任务协作关系的程序 - 工作流引擎(也常称作流程引擎)。
其中最具有代表性的就非 Activiti 莫属了。在企业应用蓬勃发展的 21 世纪初,它几乎是实现流程自动化的标配。关于 Activiti 的介绍,网上已经有足够多的文章。今天我们要介绍是由 Activiti 的核心成员打造的另一款专为微服务编排而生的工作流引擎 - Zeebe。在开始之前,我们先理解下什么是微服务编排。
3. 微服务编排
微服务架构的一大核心是把大的复杂的业务系统拆分成高内聚的微服务,每个服务负责相对独立的逻辑。例如一个电商系统,可能会拆分出支付微服务、订单微服务、仓储微服务、物流微服务等。服务拆分的好处无需赘述,但是要实现业务价值,不是看单个服务的能力,而是要协调所有服务保证企业端到端业务流的成功。
那么,哪个服务来负责端到端业务流的成功呢?答案是没有。事实上,在公司内,端到端的业务流可能都没有正式的文档说明,从一个微服务到另一个微服务的事件流转都是在代码里隐式表达的。
很多微服务架构依赖一种相对纯粹的编舞模式(choreography pattern)来解决这个问题。在这种模式下,微服务通过向一个消息队列发送和接收事件来相互协作。编舞模式给开发者提供了很高的灵活度,但是编舞模式仍不能解决:
-
可见性:多少端到端业务流正在运行中,它们的状态是什么样子。过去 24 小时,有多少业务流实例没有成功结束?为什么这些业务流实例没有成功结束?一个业务流或者某个任务完成的平均时间是多少?
-
异常处理:如果业务流里有一个微服务失败,谁负责处理这个异常?业务流的重试逻辑是怎么样的?如果需要人工介入,问题的升级处理规则是怎么样的?
于是便诞生了一种更严格的编排模式(orchestration pattern),用于协调各个微服务。在这种模式下,会有一个中控的引擎:
-
按照业务逻辑的蓝图,编排各个微服务的调用关系;
-
监控整个业务流的状态;
-
提供自动化的机制处理单个服务的失败,保证整个业务流的成功。
可以借用下面的图,来进一步理解微服务编排和微服务编舞模式的区别:
按照我们前面对工作流模型的阐述,工作流引擎很适合作为中控引擎,来编排调度微服务。那为什么诸如 Activiti 等传统的工作流引擎没能继续占领微服务编排的市场,而是诞生了新的微服务编排引擎-Zeebe?更有趣的是,Zeebe 的核心开发,也是来自最初的 Activiti 团队。
答案是诸如 Activiti 等传统工作流引擎的架构无法适应当下微服务的场景:
-
传统的工作流引擎,编排的大部分是人工审批任务,意味着任务流转效率低,系统吞吐低。而当下微服务大部分是程序化的自动任务,意味着任务高效流转,系统吞吐高。单点架构、同步响应、高度依赖 DB 的 Activiti,显然支撑不了这样的场景。
-
Activiti 等工作流引擎,通常都以 jar 包的形式,嵌入到业务程序中,直接通过调用本地方法的方式调度起业务 TaskHandler。在单体架构下,这种集成方式简单易用。但是在微服务架构下,工作流的任务往往是分布在多个服务的,而且同一个服务往往还会根据负载情况部署不同数量的实例。如果还是采用引擎主动调用的方式,怎么寻址到具体的 TaskHandler?当后端业务服务处理能力本身是瓶颈的时候,如果引擎还是不断的调用,只会进一步压垮服务。
而 Zeebe 在设计之初,就考虑到了这些问题,下文来为大家详细介绍。
二、Zeebe 特性与顶层架构
1. Zeebe 核心特性
Zeebe 是专为微服务编排设计的免费开源的工作流引擎,它提供了:
-
可见性(visibility):Zeebe 提供能力展示出企业工作流运行状态,包括当前运行中的工作流数量、平均耗时、工作流当前的故障和错误等;
-
工作流编排(workflow orchestration):基于工作流的当前状态,Zeebe 以事件的形式发布指令(command),这些指令可以被一个或多个微服务消费,确保工作流任务可以按预先的定义流转;
-
监控超时(monitoring for timeouts)或其他流程错误:同时提供能力配置错误处理方式,比如有状态的重试或者升级给运维团队手动处理,确保工作流总是能按计划完成。
Zeebe 设计之初,就考虑了超大规模的微服务编排问题。为了应对超大规模,Zeebe 支持:
-
横向扩容(horizontal scalability):Zeebe 支持横向扩容并且不依赖外部的数据库,相反的,Zeebe 直接把数据写到所部署节点的文件系统里,然后在集群内分布式的计算处理,实现高吞吐;
-
容错(fault tolerance):通过简单配置化的副本机制,确保 Zeebe 能从软硬件故障中快速恢复,并且不会有数据丢失;
-
消息驱动架构(message-driven architecture):所有工作流相关事件被写到只追加写的日志(append-only log)里;
-
发布-订阅交互模式(publish-subscribe interaction model):可以保证连接到 Zeebe 的微服务根据实际的处理能力,自主的消费事件执行任务,同时提供平滑流量和背压的机制;
-
BPMN2.0 标准(Visual workflows modeled in ISO-standard BPMN 2.0):保证开发和业务能够使用相同的语言协作设计工作流;
-
语言无关的客户端模型(language-agnostic client model):可以使用任何编程语言构建 Zeebe 客户端。
2. Zeebe 架构
Zeebe 架构主要包含 4 大组件:client, gateway, brokers 以及 exporters.
1)Client
客户端向 Zeebe 发送指令:
-
发布工作流(deploy workflows)
-
执行业务逻辑(carry out business logic)
-
创建工作流实例(start workflow instances)
发布消息(publish messages)
激活任务(activate jobs)
完成任务(complete jobs)
失败任务(fail jobs)
-
处理运维问题(handle operational issues)
-
更新实例流程变量(update workflow instance variables)
-
解决异常(resolve incidents)
客户端程序可以完全独立于 Zeebe 扩缩容,Zeebe brokers 不执行任何业务逻辑。客户端是嵌入到应用程序(执行业务逻辑的微服务)的库,用于跟 Zeebe 集群连接通信。客户端通过基于 HTTP/2 协议的 gRPC 与 Zeebe gateway 连接。
Zeebe 官方提供了 Java 和 Go 客户端。社区提供了 C#,Ruby,JavaScript 客户端实现。gRPC 协议很方便生成其他语言的客户端。
Client 中,执行单独任务的单元叫 JobWorker。
(2)Gateway
Gateway 作为 Zeebe 集群的入口,转发请求到 brokers。Gateway 是无状态(stateless)无会话(sessionless)的,可以按需增加节点,以负载均衡及高可用。
(3)Broker
Broker 是分布式的流程引擎,维护运行中流程实例的状态。Brokers 可以分区以实现横向扩容、副本以实现容错。通常情况下,Zeebe 集群都不止一个节点。
需要重点强调的是,broker 不包含任何业务逻辑,它只负责:
-
处理客户端发送的指令
-
存储和管理运行中流程实例的状态
-
分配任务给 job workers
Brokes 形成一个对等网络(peer-to-peer),这样集群不会有单点故障。集群中所有节点都承担相同的职责,所以一个节点不可用后,节点的任务会被透明的重新分配到网络中其他节点。
(4)Exporter
Exporter 系统提供 Zeebe 内状态变化的事件流。这些事件流数据有很多潜在用处,包括但不限于:
-
监控当前运行流程实例的状态
-
分析历史的工作流数据以做审计或 BI
-
跟踪 Zeebe 抛出的异常(incident)
Exporter 提供了简洁的 API,可以流式导出数据到任何存储系统。Zeebe 官方提供开箱即用的 Elasticsearch exporter,社区也提供了其他 Exporters。