在 2021 年 11 月 12 日落地的 ArchSummit 全球架构师峰会(深圳站)上,我们邀请了微众银行的资深技术专家陈广胜为大家带来了《分布式应用提效框架 Apache EventMesh》的分享,他从 EventMesh 的特征入手,为大家深入介绍了 EventMesh 在微众银行的探索与实践。本文为演讲整理文章~
今天分享 Apache EventMesh 事件驱动的分布式应用运行时,这是一个比较新的概念,希望可以通过本次的分享,给大家带来一些启发。
我们都了解两个概念——消息和事件,消息指的是具体事件的更新,这种更新是从一个点发送到另外一个点之后,消息就会被删除,消息是临时存在的状态;而事件是指在特定时间发生的,它并没有绑定到具体的接收者或客户端,它往往是可以被回放、回溯和再加工。
根据 Gartner 的一份报告显示,随着时间的推移,数据的价值将逐渐减少。在很多实时场景下,如果能够对事件进行实时的分析和数据挖掘,那将会带来很大的价值,像现在非常火的流式计算 Flink、Spark 以及 ClickHouse 等,他们都非常关注数据的实时性,EventMesh 可以及时地传递数据。
我们先来了解 EventMesh 架构图,EventMesh 的定位是事件驱动分布式应用运行时。EventMesh 可以提供非常轻量级、多语言的客户端以及各种各样的协议,例如 MQTT、Cloudevents、Web Socket 和 MQP,与此同时,它可以提供 gRPC、TCP 和 HTTP 等传输的协议。
EventMesh Runtime 是一个插件化的架构,可以对接到后端的中间件或者服务,比如事件的存储 RocketMQ、Kafaka 以 及 Apache Pulsar 等;如果需要有一些状态更新维护的时候,可以对接到后端的 redis、MySQL 以及 Mongo DB 等;如果需要有一些冷数据更新的时候,也是可以通过插件化的形式连接到 S3,ES 等存储。
在控制层面,如果需要对事件的调用链进行跟踪、元数据进行管理以及分布式协调性的时候,EventMesh Runtime 也可以对接到 ETCD、NACOS、 Prometheus、Zipkin、Skywalking
、OpenTelemetry 等。我们内部最常用的是 RocketMQ 以及 Redis 两个插件,不过 EventMesh 也可以很方便地与 Kube.NETes 进行集成,这是因为 EventMesh Runtime 可以作为 Sidecar 部署,也可以作为 Gateway 部署。
我们再看一下当前在微服务领域的 REST Drive 和 Event Drive,他们各自的优缺点非常明显。就 Spring Cloud、HTTP2、gRPC 通信而言,当 REST 调用服务的时候,由于工业界非常完善的工具文档以及开发工具客户端,开发起来非常方便,但是 REST Drive 的所有调用都是同步的,同步则意味着阻塞。如果在一个链中,任何节点的服务出现缓慢调用或故障,那么便会影响到最前端的服务调用,那么当 Spring Cloud 与 Dubbo 服务建立通信的时候,需要付出更多的成本。
然而在事件驱动领域,当接入网关或进行业务层面的框架层适配的时候,它的调用是异步的,所有的状态是最终一致的,并且可以与很多的服务以及中间层解耦。另外像 Queue 订阅发布方式,扩容非常方便。但是它需要依赖一层中间件,中间件的复杂度需要人工处理,不过这层复杂度可以使用 EventMesh 屏蔽掉,所以对应用的开发本身而言,轻量又便捷。
接下来分享一下 SeviceMesh vs EventMesh 的区别。
SeviceMesh 需要 Sidecar,所有数据层面的通信是在 Sidecar 之间的转发,不过在 EventMesh 中,我们看到单个或多个服务可以挂在 EventMesh 的单个节点,EventMesh 具备较强的微服务编排能力,但是 EventMesh 并不能解决所有的问题,它的优势在于事件驱动,它也可以做到 Request、Reply。
服务有同步和异步之分,同步调用可以采用 SeviceMesh,异步调用可以采用 EventMesh 。当然 EventMesh 也可以做同步调用,SeviceMes 也可以做异步调用,但是两者本身的定位以及处理的场景不一样,所以 SeviceMesh 与 EventMesh 可以结合使用。
例如,前端 Web App 通过 API 网关进来的调用,转发到前置或某个业务领域的服务,它会进行内部服务之间的调用,这个过程便会产生数据,数据会进入到关系型数据库或者 NoSQL 数据库。但是入数据库的这一动作,可能需要让其他的服务订阅或关注到,这个时候,我们可以将事件或者服务转发给 EventMesh,让 EventMesh 驱动关心这些事件的服务进行后续工作。
接着,我们一起看看 EventMesh 的作用。
在 DMZ 区或 ECN 区域,部署网关或者前置服务的作用是为了进行协议的转换——从外部的 HTTP 或 HTTPS 接口协议的服务,转换到内部不同的服务框架(例如 Dubbo、Spring Cloud)的协议。当外部、公网或者合作方流量进入此区域的时候,内部区域将会形成非常复杂网状的结构,边界区流量治理非常不方便。
现在的通用做法是在边界布置网关,但是当有了 EventMesh 之后,我们只需要在外联区和内部区域布置两个 EventMesh(可以是集群,也可以是节点),这样边界区的服务只需要在 EventMesh 之间进行通讯,而且当请求到了内部服务的时候,通过内部区域的 EventMesh 可以形成很多网格,每一个 EventMesh 网格代理了向其注册的服务。不同的 EventMesh 以及其代理的服务连接起来,形成较大的事件网格,很多复杂调用场景的治理将会变得极其简单。
这一部分我将会介绍几个重要的 EventMesh Feature。
现在有非常多各种云以及私有部署环境下的服务,服务与服务之间的连接可以通过 EventMesh 来完成。不同的区域的服务,使用的协议和语言不一样,但是通过 Pub/Sub+的形式增加的任何协议、节点、服务,都可以统一汇聚到 EventMesh 形成的网格中。
举个例子,当大家在亚马逊云上发布事件之后,私有化部署 Kubernetes 的某服务节点订阅了这个消息,消息可以跨越很多节点路由到 Kubernetes 服务。同时,当多个区域的服务订阅了相同的主题,只要将消息发送到对应的主题,对应的服务会自动将消息接收下来。EventMesh 可以解决连接协议的多样性、语言的多样性,并且可以解决边界区的连接问题。
事件驱动架构(EDA)是一种以事件为纽带,将不同系统进行解耦的异步架构设计模型。在 EDA 中,事件驱动的运行流程天然地划分了各个系统的业务语义,用户可以根据需求对事件与针对此事件做出的响应灵活定制,这使得基于 EDA 架构可以方便地构建出高伸缩性的应用。
HTTP Source 事件源是 EventMesh 支持的事件源的一种,它以 Webhook 形式暴露了发布事件的 HTTP 请求地址,用户可以在有 URL 回调的场景配置 HTTP Source 事件源,或者直接使用最简单的 HTTP 客户端来完成事件的发布。HTTP Source 事件源提供了支持 HTTP 与 HTTPS,公有云 VPC 等不同请求方式、不同网络环境的 Webhook URL,便于用户将其集成到各类应用中。接入时无需使用客户端,仅需保证应用可以访问到对应 Webhook URL 即可,这使得接入过程变得简单而高效。
在将 HTTP 请求转换为 CloudEvent 的时候,EventMesh 会将请求的头部和消息体部分置于 CloudEvents 字段中,其余字段会依据用户 EventMesh 资源属性以及系统默认规则进行填充。用户可以在事件规则中,对所需的内容进行过滤、提取,最终按照模板拼装成所需的消息内容投递给事件目标。
在当前的微服务下,当我们进行流量调度的时候,肯定需要解码消息头,根据消息头的特定字段,路由到对应的服务上以便增加策略。
实际上在事件驱动中,首先我们不需要解码报文,我们在它的消息主题设计上,可以解决类似的问题。比如可以设计非常多 Topic 层级,层级与层级之间有递进关系,以此来实现动态的过滤。其次,当消息到达之后,可以很方便地针对消息进行报文解析,在产生的事件上面,我们可以增加非常多的 Match 处理函数,产生的消息可以实时地经过 filter chain 的处理。事件的处理都可以由 EventMesh 来完成。
在上图的左边区域,当写入复杂的 Case、If else 条件或引入工作流之后,它的编排有很多串行的分支,但是如果采用 EventMesh 编排,看起来将会非常简洁。
我们只需要订阅感兴趣的事件,发送对应的事件到对方主题上就可以,我们并不需要关注对方 IP 的所在地,也不需要关注服务部署在虚拟机还是在容器上,以及对方服务实例数量,当然更不需要关注对方实例挂了之后,我们是否需要进行熔断等等。下游的 EventMesh 可以完成所有的事情,例如,当它下游的服务发生故障,消息将会自动分发到当前在线的服务实例。从上面这张图,大家可以看出,采用 EventMesh 可以使得编排与协调过程更加清晰。
接下来是扩缩容场景,当现有的 Kubernetes 在进行扩缩容的时候,有两个常见的场景。
首先是扩容场景,例如,在当前的 CPU 占用很高的时候,正常情况会触发扩容事件,但我们在消息队列中,并没有看到特别多的消息堆积,也就是说,这个时候并不需要扩容,实际上这个扩容是浪费的;其次是缩容场景,例如在消息队列里,当前没有消息堆积,理论上实例是可以缩容,甚至可以缩容到零,但是因为 CPU 的使用导致无法顺利缩容。
但是这两种场景,如果在事件驱动的服务下,我们采用 Queue 队列堆积的监控方式可以实现以下效果。首先是在资源占用很高,但队列的任务没有堆积的情况下,可以不进行扩容;其次,在占用当前的 CPU 的资源,但没有任务处理的情况下,可以进行缩容。在我看来,伸缩监控的指标应该根据当前处理的任务堆积情况来判断。
没有治理前,就如下图一样,各个不同区域之间形成了数据的孤岛。
但当治理之后,就变成了下图一样的这样网格状态,清晰且简洁。
在过去十年的大部分时间里,企业都在与数据孤岛作斗争,数据孤岛是孤立的持久性存储,拥有无数但无法访问的知识,他们的主要武器是数据湖:一个巨大的集中式数据存储,将 TB 级的特定于域的数据保存在一个逻辑位置。没有领域知识的数据专家试图从不同的数据集中挖掘数据价值是很困难的,而且几乎没有动力向数据湖贡献高质量数据的数据生产者。
EventMesh 具备实时分析、大规模数据收集、平台无关的连接以及对开放标准的支持等能力,理想情况下,对客户数据的任何更改都应通过事件网格之类的东西实时推送给依赖的消费者,但如果数据不太重要或不及时,数据消费者可以在需要时提取(或查询)数据。
我们正在从数据无政府状态过渡到联合治理和成熟的企业数据策略——理想情况下,可以将策略有效地表示为代码的最终状态。联合治理需要特定于任务的工具、事件目录和 AsyncAPI 等标准。企业级数据策略还包括访问控制、法规(即 GDPR)、机密性(如 PII 和 PHI)、编辑和加密等特性/功能。功能的示例可能包括强制性标头元数据(将数据上下文化)、可观察性要求、主题结构(用于路由)以及通过模式验证和其他工具实现的数据质量。
在微众银行,已经开源的消息总线 DeFiBus 如上图所示,这里以三个 EventMesh 的节点为例,每一个 EventMesh 节点,可以在其上面订阅服务。当发送方发布一个事件之后,其他的 EventMesh 上的任何服务,只要订阅了 Topic,这个事件便可以发送到对应的服务上,它能够自动地学习和更新路由表。
EventMesh 在微众银行内部解决了以下问题,首先是多语言治理问题,例如 AI 计算使用 Python/ target=_blank class=infotextkey>Python、很多银行的系统使用 C 语言,EventMesh 能够简化接入消息总线的复杂度,同时我们知道,推动业务的 SDK 的升级非常麻烦,当 SDK 轻量简化之后,我们只需要负责中间件层的发布,就可以节省掉应用推动升级的成本。除了应用在业务系统外,EventMesh 还应用在流量复制回放平台,消息旁路过滤,消息多活路由,AI 联邦学习,区块链等场景,更多的场景在持续探索实践过程中,未来有机会再分享给大家。
今天的 IT 系统正在生成、收集和处理比以往更多的数据。而且,他们正在处理高度复杂的流程(正在自动化)以及跨越典型组织边界的系统和设备之间的集成。同时,预计 IT 系统的开发速度更快、成本更低,同时还具有高可用性、可扩展性和弹性。为了实现这些目标,开发人员正在采用架构风格和编程范式,例如微服务、事件驱动架构、DevOps 等。正在构建新的工具和框架来帮助开发人员实现这些期望。开发人员正在结合事件驱动架构 (EDA) 和微服务架构风格来构建具有极强可扩展性、可用、容错、并发且易于开发和维护的系统。
EventMesh 作为事件基础设施,主要负责事件的传输、路由和序列化。它可以提供用于处理事件流的 API。事件基础设施提供对多种序列化格式的支持,并对架构质量(例如容错、弹性可伸缩性、吞吐量等)产生重大影响,也可以存储事件以创建事件存储,事件存储是恢复和弹性的关键架构模式。
了解更多软件开发与相关领域知识,点击访问 InfoQ 官网:https://www.infoq.cn/,获取更多精彩内容!