背景
微服务从诞生到现在,经历了很长时间。期间不同公司,不同的团队有各自独特的见解,但慢慢对于微服务的各个方面的理解,如服务发现一致性、容错、事务、熔断、降级、配置等等趋于一致。随着微服务在团队中应用,服务的划分越来越细致,单个服务的职责简单清晰,服务易于维护。微服务化确实给团队带来非常大的好处,同时微服务也会带来一些问题。
单个服务逻辑简单,职责清晰,但从整体上来讲,业务的复杂度是没有消失的,那业务的复杂度去哪里了?没错!就是服务间的直接或间接调用。业务逻辑如果很复杂,服务之间调用链路将变得很长,梳理服务之间的调用关系就成了很复杂的事情,代码同样会变得难以维护,新同学的业务学习成本依旧很高。
微服务带来了额外的复杂度,服务发现,一致性,分布式事务等问题在单体应用的时代是不存在的。即便随着微服务的发展,这些功能封装的那么完整,服务中也会出现大量的模板引用,模板代码,增加了开发的成本,为了解决这个问题,服务网格出现了,服务网格将大量公用的复杂度封装在边车中,使开发人员专注于编写业务代码。那么在现有的解决方案中能否更近一步,使开发人员尽量的少些代码呢?
综上所述,如何以尽量少的代码,清晰地体现复杂的业务逻辑呢?在调研了很多方案后,最终将目光锁定在 Knative 上,基于 Knative 构建一个 Serverless 工作流平台将完美的解决上述问题。
Knative 简介
Knative 是由 Google 在 2018 年 Google Cloud Nnext 大会上发布的 K8S sServerless 框架,目前由 Red Hat、Google、IBM、Pivotal 等多家公司共同维护。Knative 拓展了 K8S,在 K8S 和 Istio 基础上,Knative 抽象了云服务通用功能服务部署,灰度等,使用户不用关心 Deployment,Replicaset,Pods,Ingress,Distribution Rule 等 K8S,Istio 的概念,从而专心于业务开发,K8S,Istio 内部组件的整合则由 Knative 来实现。因此 Knative 本质上是以用户为角度,解决服务端构建,部署,应用管理等问题。整体架构如下图:
Knative 模块构成
Build 负责项目的 CICD,已迁移到 Tekton 中,在此不做过多介绍
Serving 负责 severless 应用和方法的部署
Eventing 负责事件的发布订阅以及基于发布订阅产生的衍生产品
Serving 主要组成
Service,Service 是应用的抽象,负责整个应用的生命周期以及其他模块的创建管理,例如 Route,Configuration 等
Route,Route 负责流量的管理,可以控制流量到 Revision 的路由规则
Configuration,Configuration 维护了应用的最新状态。代码和配置之间充分解耦,每次修改配置,都会创建一个新的 Revision
Revision,Revision 是每次代码和配置进行修改的快照,是不可变的。
Serving 组件间关系图如下:
Eventing 主要组成
Event Consumer,事件消费者,事件消费者通常实现了 Addressable 或者 Callable 接口,以接受消费事件,并将结果返回
Event Source,事件源,顾名思义事件的生产方,现有的事件源包括 K8S Apiserver,Github,Kafka,Websocket 等等,非常丰富
CloudEvent,事件数据的规范,Knative 采用此标准进行事件的传输
Broker 事件代理,可以接受一系列事件,并将事件转发给符合 Trigger 过滤条件的订阅者,从而实现事件 Filter 功能
Trigger 过滤器,定义的事件的过滤规则和订阅者,配合 Broker 使用
Event Registry EventType 的集合
Event Channel 事件持久层
Event Subscription 事件订阅,通常是时间消费者订阅事件
Eventing 整体架构如下:
图片引用自Knative组成员Aleksander Slominski
Knative 基于事件的发布订阅机制,封装 Channel 以及 Subscription,使多个工作节点能够通过发布订阅机制进行串联,从而打造 High-Level 的工作流资源,使业务人员能够进行简单的工作流开发,Knative 提供了两种 High-Level Workflow 资源:
Sequence,提供了一种顺序执行的工作流资源
Parallel,提供了方法分支列表的工作流资源
以 Sequence 为例,事件消费的流程如下:
应用实践
Knative 提供的 3 大组件中,跟 Workflow 相关的毫无疑问就是 Eventing,Eventing 的一系列组件为 Workflow 的实现打下了基础,同时 Eventing 也提供了 High-Level 工作流组件供开发人员在业务开发中使用,不过现有的 Knative 现有的工作流只是组件级别的,距离投入生产,成为一个工作流平台,还是有一定差距的。
Knative Eventing 并没有提供 UI 能力,开发人员需要手动编写 Yaml 文件才能完成工作流的定义,开发不够便捷
Yaml 的编写复杂,需要涉及到 broker,Trigger,Parallel,Sequence 等组件,学习成本较高
Sequence,Parallel 工作流组件逻辑较为简单,并不能完成相对复杂的业务逻辑
缺少业务服务,工作流统一部署方案,部署成本较高
WorkFlow 模块构成
为了解决上述问题,打造生产级别 Serverless Workflow,爱奇艺号(爱奇艺号是爱奇艺旗下专注视频内容创作、分发、变现的平台)以 Knative Eventing 组件为基准,重新进行了封装,并增加了拖拽生成工作流,CICD 等功能,方便开发人员使用。项目共分为 4 个模块:
Workflow-Dashbord 工作流页面前端工程,负责工作流列表展示,拖拽等功能
Workflow-Api 工作流页面对应后端,负责工作流 Yaml 生成,应用到 K8S 等功能
Workflow-Operator 监听 K8S Workflow 资源,解析 Workflow Yaml 并创建更新 Knative Eventing 等组件,从而编排工作流
Workflow-Syncer 监听 K8S Workflow 资源,更新 Workflow 状态
以创建工作流为例,模块间交互图如下:
Workflow 原理简析
以一个简单的 Workflow 为例,业务场景是 Workflow 从 Rocketmq 接收消息,对消息进行 append,最后 display 到日志中。
1.开发人员登录 Workflow UI 页面,创建 Workflow 拖拽生成 Workflow 定义,并发送至 Workflow-Api。
2.Workflow-Api 创建 git 项目,并根据流程节点属性,初始化项目目录以及 Yaml 配置文件
整体目录结构
进入 cmd 目录中,展现的是业务代码的入口,根据业务节点名称生成目录名,如下图。进入 display 目录中,则会看到 main.go,在 main.go 中写业务代码即可
cmd 子目录结构
进入 config 目录中,展现的是 Workflow 流程的配置文件,各个业务节点的配置文件,以及 Workflow 流程依赖的配置文件。
config 目录结构
其中最为重要的 Workflow Yaml 定义如下:
Workflow Yaml 定义
Yaml 主要由两部分组成,Triggers 和 Steps,其中 Triggers 为 Workflow 触发器,支持 rocketmq,定时任务等触发方式。Steps 为流程定义,会被解析为 Knative Eventing 对应的组件。
3.开发人员 pull 项目,进入 cmd 目录进行业务开发。完善业务逻辑 push 代码后,进入 Workflow UI 点击部署,将服务打包,Workflow 部署到 K8S 中。CICD 采用的是 GitLab-CI,打包部署到 K8S 使用的是 google 的 KO,KO 将 cmd 中 append1,display 目录下的业务代码分别构建镜像,并 push 到 docker 镜像仓库中,将 config 下的配置文件中,带有 KO 前缀的镜像进行替换,替换为刚刚打包的镜像版本。
镜像替换完成后,将 config 目录下 Yaml 文件按顺序 apply 到 K8S 中,其中就包括 Workflow Yaml。
4.Workflow-Operator 与 Api-Server 建立长连接监听 Workflow 资源以及 Workflow 需要整合的资源,解析 Workflow Yaml 并创建更新对应的 Knative Eventing 组件,并将组件按照 Workflow 的定义进行串联,使数据能够按照 Workflow 定义进行流转。细心的同学可能已经发现,Workflow 的资源并不是 K8S 已有的,而是自定义的,apiVersion 为 apps.iqiyi.com/v1alpha1,kind 为 FlowApp。由于需要对 Knative Eventing 组件进行进一步的整合,所以新定义一个 CRD 来描述 Workflow。自定义 CRD 的方式有多种,由于 Workflow-Operator 与 Api-Server 间的通信相对复杂,需要采用较为稳定,成熟度较高的,使用简便的脚手架,最后决定使用 Operator-SDK 作为 CRD 的脚手架框架,很多同学在进行 CRD 脚手架框架选型时,会比较纠结,可以查看 Kubebuilder vs Operator-SDK,希望解决大家的困惑。
Workflow 与 Knative Eventing 组件的对应关系如下:
5. Workflow-syncer 与 Api-Server 建立长连接监听 Workflow 资源状态。待 Workflow 部署完成后,Workflow-syncer 监听到 Workflow 的最新状态,并将状态持久化到 db,供前端查阅,自此,一个 Workflow 就算是部署完成了。
监控报警
Serverless 的工作流监控目前来讲相对朴素。前面说到 Knative Eventing 组件时间数据交互是以 CloudEvent 为标准的,传输协议则是使用 Http,以此为出发点,通过对业务服务的代码进行埋点,使用 Prometheus 客户端对 Http 客户端状态码,响应时长,QPS 进行监控,并通过 urlpath:/metrics 进行暴露。
启用 Rancher 中 Prometheus 集群监控以及项目监控,并自定义监控指标将 urlpath:/metrics 数据进行收集,最终将 metrics 展示在 Rancher 的 Grafana 中,以实现对业务服务的 Http 接口监控。
有了监控数据即可使用 Grafana,Prometheus 等方式进行报警,我们采用的是通过 webhook 方式对接公司统一报警平台。这是一套相对通用的监控,利用了 Knative Eventing 通过 Http 协议通信的原理对业务服务进行 Http 指标相关监控,也从一定程度上反应了该业务服务对应 Workflow 的健康状况。
总结与展望
一直以来,程序员同学就被复杂的业务逻辑和重复的业务开发所困扰,爱奇艺号 Serverless 工作流平台从这两个痛点出发,针对复杂的业务逻辑,以工作流程图的形式呈现,清晰明了,结合项目管理,甚至可以要求产品同学以产品流程图作为需求输入,开发人员按照产品流程图进行 Workflow 开发,这样极大的降低的沟通的成本以及项目维护成本;针对重复的业务开发,爱奇艺号 Serverless 工作流平台以低代码为原则,从配置化,中台化的角度出发,尽量使开发同学只写核心业务代码,减少必要的重复劳作。
爱奇艺号 Serverless 工作流平台目前还在起步阶段,尚有很多功能未完善,后续将从以下几个方面进行完善:
支持更为复杂的工作流节点。Knative Eventing 提供的 Sequence,Parallel 显然还是太简单,要支持复杂的业务逻辑必须要丰富工作流选择控制节点,例如选择,循环等。
工作流监控。当前的工作流监控只针对业务服务,并没有从工作流的角度出发进行监控管理。我们需要对工作流的每次执行进行详细记录,每个节点执行情况,每次执行的结果都要做到可查可追踪。
支持多语言。当前的 Workflow 业务服务受限于 KO 的打包部署方式,只支持 go 语言。后续需要支持 java,python 等多语言打包部署。
支持同步调用。当前 Workflow 是异步模型,同步的场景如果需要提供接口服务是不支持的。同步场景在平时开发中也是很常见,后续需要 Workflow 需要支持同步模型。
本文转载自:爱奇艺技术产品团队(ID:iQIYI-TP)
原文链接:低代码、中台化:爱奇艺号微服务工作流实践
评论