微服务从诞生到现在,经历了很长时间。期间不同公司,不同的团队有各自独特的见解,但慢慢对于微服务的各个方面的理解,如服务发现一致性、容错、事务、熔断、降级、配置等等趋于一致。随着微服务在团队中应用,服务的划分越来越细致,单个服务的职责简单清晰,服务易于维护。微服务化确实给团队带来非常大的好处,同时微服务也会带来一些问题。
- 单个服务逻辑简单,职责清晰,但从整体上来讲,业务的复杂度是没有消失的,那业务的复杂度去哪里了?没错!就是服务间的直接或间接调用。业务逻辑如果很复杂,服务之间调用链路将变得很长,梳理服务之间的调用关系就成了很复杂的事情,代码同样会变得难以维护,新同学的业务学习成本依旧很高。
- 微服务带来了额外的复杂度,服务发现,一致性,分布式事务等问题在单体应用的时代是不存在的。即便随着微服务的发展,这些功能封装的那么完整,服务中也会出现大量的模板引用,模板代码,增加了开发的成本,为了解决这个问题,服务网格出现了,服务网格将大量公用的复杂度封装在边车中,使开发人员专注于编写业务代码。那么在现有的解决方案中能否更近一步,使开发人员尽量的少些代码呢?
综上所述,如何以尽量少的代码,清晰地体现复杂的业务逻辑呢?在调研了很多方案后,最终将目光锁定在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基于事件的发布订阅机制,封装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中写业务代码即可
进入config目录中,展现的是Workflow流程的配置文件,各个业务节点的配置文件,以及Workflow流程依赖的配置文件。
其中最为重要的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需要支持同步模型。
本文暂时没有评论,来添加一个吧(●'◡'●)