Apache RocketMQ EventBridge:构建下一代事件驱动引擎

2023年 7月 19日 25.8k 0

作者:沈林

前言

事件驱动,这个词在部分人印象中,它是一个过时的技术——没什么新意。从时间上看,确实也是这样,上世纪 60 年代,事件驱动就已经被正式提出,经常会被在 GUI 编程中。但是在有些人印象中,事件驱动又是一个非常陌生,非常新颖的技术。

不管怎么样,现实是已经有越来越多的公司,开始或则经把事件驱动架构应用到企业的核心业务中,包括:阿里巴巴、喜力、联合利华、美国联邦航空管理局、银行资本市场等等。市场上,也有很多公司推出了自己的产品或解决方案,比如阿里云、AWS、Google,Solace。行业里也孕育出了事件的标准:CloudEventsGartener,则把事件驱动定义为未来十大趋势之一;

这个时候,我们就要问了,事件驱动架构到底是什么呢?为什么现在,被越来越多的人,开始关注事件驱动架构了呢?

1.png

5 月 28 日,GOTC 2023 全球开源技术峰会上,阿里云智能技术专家沈林发表主题演讲:Apache RocketMQ 事件驱动引擎。

Apache RocketMQ EventBridge:构建下一代事件驱动引擎-1

Apache RocketMQ PMC&阿里云智能技术专家:沈林

什么是事件?

说到事件驱动架构,大家第一印象往往会把重点放在“架构”这两个字上,但是,事件驱动架构很大的魅力其实来源于前面“事件”两个字,所以今天,我们先一起看下什么是事件。RocketMQ 之前一直给人的印象是一个消息引擎,那为什么我们在前段时间发布的 5.0 版本中,引入了事件?消息跟事件,又有什么区别呢?

事件,如果我们查阅字典,他会给你这样一个解释:事件是指过去已经发生的事,尤其是比较重要的事。

这个很好理解啊。比如,GOTC 大会今天在上海正式开幕了;刚才我的手机铃声响了;这些都是过去已经发生的事件。

但是,如果我们接着刚才的问题问:事件跟消息有什么区别呢?这个时候,大家是不是觉得事件这个定义,好像又不那么清晰了?刚才我们说的那些事件,是不是也可以理解为消息?如果这个时候,老张给我发送了一条短信,那这个短信,算是事件,还是消息呢?

我们可以通过这张图,来简单理解消息和事件的关系。消息包含两类,一类是 Command 消息,另一类就是 Event 消息。

1、Command 消息是什么?我们看下面左边这张图,外部系统发送给本系统的一条操作命令,就是Command消息;

2、那什么是 Event 消息呢?再看下面右边这张图,本系统收到外部 Command 操作请求,系统内部发生改变之后,就产生了 Event;

所以,事件和消息稍微有些不同。事件,可以理解为是一种特殊的消息,那事件特殊在什么地方呢?主要包含 4 个方面:

3.png

事件的特性 1:已发生且不可变的

事件,一定是“已发的”。“已发生”的代表什么呢?不可变的。我们不可能改变过去,除非你有超能力。这个特性非常重要,在我们处理事件、分析事件的时候,这就意味着,我们绝对可以相信这些事件,只要是收到的事件,一定是系统真实发生过的行为,而且是 Immutable,不可修改。

对比 Command 消息,Command 的中文是什么?命令!很显然,它还是没有发生的,而是表达了一种期望。我们知道,“期望的”不一定会成功发生。比如:

  • 把厨房的灯打开;
  • 去按下门铃;
  • 转给 A 账户 10w;

这些都是 Commond,都是期望发生的行为。但是,最终有没有发生呢?并不知道。

Event 则是明确已经发生的事情。比如:

  • 厨房灯被打开了;
  • 有人按了门铃;
  • A 账户收到了 10w

事件的特性 2:无期望的

事件的第二个特性是:无期望的。事件是客观的描述一个事物的状态或属性值的变化,但对于如何处理事件本身并没有做任何期望。相比之下,Commond 则是有期望的,它希望系统做出改变;但是 Event,它只是客观描述系统的一个变化。我们举一个例子:交通信号灯从绿灯变成红灯,它就是一个事件。事件本身并没有任何期望,说要求行人或汽车禁止通行,而是交通法规需要红绿灯,并赋予了其规则。

所以,系统,一般不会定向的、单独向一个指定的系统发送事件,而是统一的告诉“事件中心”。“事件中心”那里面有各个系统上报上来的,各式各样的事件。系统会向事件中心说明:自己这个系统,会产生哪些事件,这些事件的格式是怎么样的;别的系统如果感兴趣,就可以来主动订阅这些事件;真正赋予事件价值的,是事件消费者。事件消费者想看看,某个系统发生了什么变化?OK,那他就去订阅这些事件,所以事件是消费者驱动的。

这跟消息有什么区别呢?Commond 消息的发送和订阅,是双方约定好的,外人不知道,往往是以文档或代码的形式,大家按约定好的协议,发送和订阅消费,这个过程往往是生产者驱动的。

打个比喻,事件就像市场经济,商品被生产出来,具体有什么价值,有多大价值,很大程度上看其消费者。我们能看到系统中各种各样的事件,就像橱窗里摆放了各种各样的商品;而 Commond 消息,有点像计划经济,一出生就带着很强的目的性,“我”就是要“分配”给谁消费。

事件的特性 3:天然有序且唯一的

事件的第三个特性是:“天然有序且唯一的”。同一个实体,不能同时发生 A 又发生 B,必有先后关系;如果是,则这两个事件必属于不同的事件类型。细心的同学,肯定发现了一点,这里其实隐藏了事件的一个额外属性:因为天然有序,跟时间轴上的某一时刻强绑定,且不能同时发生,所以它一定是唯一的。

如果我们看到了两个内容一样的事件,那么一定是发生了两次,而且一次在前,一次在后。这对于我们处理数据最终一致性、以及系统行为分析都很有价值:我们看到的,不光是系统的一个最终结果,而是看到变成这个结果之前的,一系列中间过程。

事件的特性 4:具象化

事件的第四个特性是:“具象化”。事件会尽可能的把“案发现场”完整的记录下来,因为它也不知道消费者会如何使用它,所以它会做到尽量的详尽,包括:什么时候发生?是由谁产生的事件?是什么类型的事件?是谁发送的事件?事件的唯一性标志是什么?事件的内容是什么?等等。

再对比我们常见的消息,因为上下游一般是确定的,常常为了性能和传输效率,则会做到尽可能的精简,只要满足“计划经济”指定安排的消费者需求即可。

什么是事件驱动架构?

讲完事件,我们再回过头来,一起看看,什么是事件驱动架构。为了方便理解,我们举一个简单的例子:我们都知道:交易系统在完成订单交易之后,有很多系统都“需要”知道这个订单信息,比如:

  • 物流系统,需要知道这个订单信息,来安排发货;
  • 积分系统,需要知道这个订单信息,来重新计算这个用户的积分;
  • 营销系统,需要知道这个订单信息,来计算当天的实时交易额。

这里我们有三种方式来实现上游交易系统和下游物流、积分、营销系统的集成。

上下游集成

方式 1:主动调用

一种最简单的实现方式是:交易系统依次调用每个系统,把订单信息发出去。比如下图这种方式:

4.png

但我们都知道,这个设计,是非常糟糕。尤其当越来越多的系统加进来时,不仅开发成本高,而且万一其中一个系统出现问题,处理不好,很容易影响其他系统的发送。

方式 2:消息异步解耦

一个很自然的解决方案是:我们将订单信息,发送到中间的一个消息 broker 服务。然后,物流系统、积分系统、营销系统只需要去订阅 Broker 的这些交易订单消息就可以了,非常简单清晰。

5.png

方式 3:事件驱动架构

那如果是在事件驱动架构中,应该怎么做呢?交易系统,依旧会将交易订单发送到我们中间的 Broker 服务,但是下游服务不再需要主动订阅 Broker 中的交易订单,而往往是 Broker 推送给下游系统。这个时候,大家可能既有疑问了,这个好像跟方式 2 消息异步解耦,没有太大的区别吧?难道事件驱动架构,就是简单的把 Pull 模式变成了 Push 模式?

6.png

这里我们围绕上游和下游,看看事件驱动架构带来了什么改变。

面向下游

1、耦合的膨胀

这里我们衍生一下,很多时候,下游的营销系统它不是只依赖一个交易系统产生的订单数据,比如:它可能同时需要淘宝的交易订单、京东的交易订单、拼多多的交易订单,来实时计算一个当前时刻汇总值。这个时候,在“消息异步解偶” 的架构中,客户的营销系统需要做两件事:

第一,订阅三个 Broker 服务,来获取淘宝、京东、拼多多的交易订单数据;

第二,由于淘宝、京东、拼多多的交易订单数据格式,是不同的,所以客户的营销系统,需要对三种数据格式进行适配,先转换成营销系统内部期望的数据格式,然后再处理。

而且,如果后面客户又在抖音开店,客户的营销系统需要再适配一遍;如果某家的订单数据格式发生变化,那客户营销额系统也必须联动的进行更新。

7.png

如果在事件驱动架构中,客户的营销系统,需要怎么做呢?他什么都不需要,只要登高一声大喊:“我需要什么样的订单事件格式,我提供一个 API,其他系统就按这个订单事件格式发给我就可以了”。EventBroker 会将上游的事件转换成客户营销系统需要的数据格式,发送给他的 API。不管接多少系统的交易订单、不管外部系统怎么变,反正我不变。

8.png

2、耦合方向

这里我们分析下这三种方式的耦合关系:我们要知道,耦合是有方向性的。

  • 方式 1-直接调用:是上游 A 依赖下游 B;(一旦下游 B 发生改变,A 需要同步的改变)
  • 方式 2-消息异步解偶:是 B 依赖于 A;(一旦上游 A 的数据格式,发生改变,B 需要同步的改变)
  • 方式 3-事件驱动:A 不依赖于 B,B 也不依赖于 A;(所有的耦合,都由中间的 Event Broker 来统一处理和维护)

9.png

3、影响系统稳定的因子有哪些?

除了降低依赖,下游系统在开发的时候,最关注的是什么?对大部分业务场景来说,最重要的是:开发维护成本低、稳定又可靠。不过,在消息异步解偶架构中,大家有没有发现,影响当前下游这个系统发生变化的入口,是不是有两个?(就是下面咖啡色的部分) 一个是 API;一个是消息订阅。

一个系统,有两个入口会引起发生变化,是一件非常麻烦的事。这意味着:我们在开发和维护这个系统的稳定性时,需要守护好两个口子:无论是身份认证、审计、安全、流控、测试、维护等等,我们都要两边考虑。不仅成本高,而且很容易出问题。

10.png

4、可测试性和可维护性

在事件驱动架构模式中,下游系统只需要提供一个 API 入口。

  • 对外:这个 API,既是用来接收上游的事件,也可以用来和其他系统间的通讯;
  • 对内:这个 API 的设计,是围绕下游系统当前自己的领域模型去设计的,不需要去适配任何其他系统。

所以整个系统,会非常简约。简约的好处是:当我们需要变更系统时,只需要保障我们提供的 API 可靠,可测试性和可维护性都大大提升。

11.png

5、Serverless

事件驱动还有一个非常大的优势是可以通过事件的方式,按量驱动 Serverless,去进行消费。还是在我们交易订单这个场景下:

  • 有些小商家的的订单量其实没有那么多,那单独部署一个积分系统服务,7*24 小时一直跑着,是很浪费的一种行为。这个时候,如果通过事件驱动模式:当只有交易订单事件产生时,才去触发下游 Serverless 服务,按量计算付费,能够极大的降低我们的成本;
  • 而对有些商家,交易订单量非常大,尤其是遇到节日大促的时候,流量峰值会非常高,这个时候,如果通过事件驱动模式,按量触发 Serverless 进行计算,能够更好的提升系统的处理能力的峰值。
  • 另外,如果下游系统会因为某些异常事件,影响系统稳定性。那通过事件驱动触发 Serverless 的方式,天然的,就可以提供很好的隔离性,并实现快速恢复。

Serverless 已经逐步成为云原生时代一股势不可挡的趋势,而事件驱动和 Serverless 则是一对最好的兄弟组合。

12.png

面向上游

SaaS 集成

上面都是围绕下游展开,那对于上游系统来讲,事件驱动的意义在哪呢?我们想一下,对上游系统来讲,它最关心的是什么?它关心的肯定不是系统的稳定性和解耦这些东西,不是说这些东西不重要,而是对上游系统来讲,发送到消息 Broker,和事件 Broker 没什么区别。那什么对上游系统来说是最重要的呢?这里本质上是,上游系统希望可以和更多的系统实现集成,来打造自己的生态位。

这个怎么理解呢?我们举一个例子:门禁打卡系统。

门禁打卡系统,卖给不同的公司,需要支持员工打卡的记录信息同步到不同公司的 ERP 系统中,这个时候,如果门禁打卡系统自己 One By One 去集成适配各个公司的 ERP 系统,成本是非常高的,几乎不现实;如果不去集成,可能很多公司可能就不买你的了。

所以,对于上游系统来说,能够省心省力的与生态内的产品方便集成,是最重要的事情。而在事件驱动架构模式中,门禁打卡系统只需要以事件的形式,把员工打卡事件记录下来,交给事件中心,剩下的事情就不用操心了。事件中心会统一负责下游生态的集成对接。

13.png

另外,对于门禁打卡系统本身,它也需要知道新员工的入职事件,因为只有这样,在新员工打卡的时候,才能够及时识别。如果通过事件驱动模式,门禁打卡系统就可以轻松的在 SaaS 生态中,从零开始,快速打造自己的生态位。

如何做一个优秀的事件驱动引擎

前面讲了这么多,了解了什么是事件以及什么是事件驱动架构。也了解到事件驱动架构独特的一些魅力:为什么事件驱动架构,被越来越多的公司喜欢。

最后,我们讲一下,如果要做一个优秀的事件驱动引擎,需要具备哪些能力?我们 RocketMQ EventBridge 怎么做的?

需要什么样的能力?

第一,我们肯定得有一个事件标准。因为事件不是给自己看的,也不是给他看的,而是给所有人看的。事件没有明确的消费者,所有都是潜在的消费者,我们得规范化事件的定义,让所有人都能看得懂,一目了然;

第二,我们得有一个事件中心,事件中心里有所有系统注册上来的各种事件。这个有点类似市场经济大卖场,玲琅满目,里面分类摆放了各种各样的事件,所有人即使不买,也都可以进来瞧一瞧,看一看,有哪些事件,可能是我需要的,那就可以买回去;

第三,我们得有一个事件格式,用来描述事件的具体内容。这相当于市场经济的一个买卖契约。生产者发送的事件格式是什么,得确定下来,不能总是变;消费者以什么格式接收事件也得确定下来,不然整个市场就乱套了;

第四,我们得给消费者一个,把投递事件到目标端的能力,并且投递前,可以对事件进行过滤和转换,让它可以适配目标端 API 接收参数的格式,我们把这个过程统一叫做订阅规则。

第五,我们还得有一个存储事件的地方,就是最中间的事件总线。

14.png

如何描述事件

关于刚才提到的第一点事件标准,这个很重要。事件标准,就相当于不同系统之间交流的语言,如果语言都不通,相互交流肯定会出很多问题。我们推荐使用 CNCF 旗下的开源 CloudEvents 协议,目前已经很多公司广泛集成,算是一个事实上的标准。CloudEvent 协议也很简单,我们有一个简单的例子, 详细可以参考官网 [ 1] :

{
  "specversion":"1.0",
  "type":"com.github.pull_request.opened",
  "source":"https://github.com/cloudevents",
  "subject":"123",
  "id":"A234-1234-1234",
  "time":"2018-04-05T17:31:00Z",
  "comexampleextension1":"value",
  "comexampleothervalue":5,
  "datacontenttype":"text/xml",
  "data":""
}

事件中心

另外,我们必须得有一个事件中心。事件中心对于事件驱动架构来说,是非常重要的一个角色。他就像我们刚才说的市场经济的大卖场,所有的事件,在这个大卖场里,都有详细的使用说明,大家都可以进来瞧一瞧,看一看,觉得合适,就订阅买走。

至于事件中心如何管理,我们可以从API管理里学习很多经验:我们知道 API 包含注册、Schema 描述、Sample、文档、SDK、测试、监控。Event,其实也是一样,它需要在事件中心被注册,定义 Schema 描述、Sample、文档、CodeBinding、测试、监控。

这样消费者拿到这个事件的时候,才知道是什么,怎么用,用的放心。

15.png

Schema

事件的 Schema,是用来描述事件中有哪些属性、含义等等信息。为什么我们要引入Schema?一方面是,为了让下游能够理解事件的格式,方便使用事件;另一方面,也是为了限制上游发送事件的格式,发送和修改都必须保障兼容,一旦契约签订,不能轻易修改。我们推荐使用 Json Schema 和 OpenAPI 3.0。

事件过滤和转换

关于事件的过滤和转换,RocketMQ 事件驱动引擎 提供了丰富的事件过滤和转换方式。这些我就不具体一一展开了,详细大家可以上图描述。

16.png

RocketMQEventBridge 技术架构

最后,我们 RocketMQ 围绕事件驱动推出的产品,叫做 EventBridge,他的整个架构可以分为两部分:上面是我们的控制面、下面是我们的数据面。

控制面:面向上游,做好事件的管理。通过 EventSource,把上游产生的事件,管理起来,让大家找得到需要的事件,找到事件后,知道怎么用;面向下游,可以通过 EventRule,让消费者,方便的把事件转换成需要的格式,并推送给自己。中间的 EventBus,是我们存储事件的地方,底下使用的是我们 RocketMQ 自己的Broker;数据面:是事件的通道,我们除了可以通过 API 发送事件到 EventBus 之外,还可以通过 Source Connector 主动拉事件到 EventBus。消费者创建 EventRule 之后,则可以通过 Sink Connector 将事件,推送到目标端;除此之外,我们还会有:事件追踪、事件回放、事件分析、事件归档等等。

17.png

欢迎加入我们

大家如果想进一步了解 EventBridge,可以点击下方链接,也可以一起参与社区的建设。

RocketMQ EventBridge:

github.com/apache/rock…

RocketMQ 学习社区体验地址

RocketMQ 学习社区重磅上线!AI 互动,一秒了解 RocketMQ 功能源码。RocketMQ 学习社区是国内首个基于 AIGC 提供的知识服务社区,旨在成为 RocketMQ 学习路上的“贴身小二”。

PS:RocketMQ 社区以 RocketMQ 5.0 资料为主要训练内容,持续优化迭代中,回答内容均由人工智能模型生成,其准确性和完整性无法保证,且不代表 RocketMQ 学习社区的态度或观点。

相关链接:

[1] 官网github.com/cloudevents…

点击此处,立即体验RocketMQ 学习社区(建议 PC 端体验完整功能)

相关文章

KubeSphere 部署向量数据库 Milvus 实战指南
探索 Kubernetes 持久化存储之 Longhorn 初窥门径
征服 Docker 镜像访问限制!KubeSphere v3.4.1 成功部署全攻略
那些年在 Terraform 上吃到的糖和踩过的坑
无需 Kubernetes 测试 Kubernetes 网络实现
Kubernetes v1.31 中的移除和主要变更

发布评论