写点什么

事件总线实现方式汇总

  • 2017-08-07
  • 本文字数:1744 字

    阅读完需:约 6 分钟

基于事件驱动的分布式异步架构模式多用于构建高可伸缩的反应式应用程序,适用于各种从简单到复杂的应用场景。它的核心思想是去耦合,将消息的发送和接收分开,实现异步处理消息事件。架构师 Mustafa Turan 在 Hackernoon 上分享了事件总线的几种实现方式,并总结了每一种实现方式的优缺点。

事件总线是实现基于事件驱动模式的方式之一,或者可以将其称为“Broker Topology”。事件发送者将事件消息发送到一个中心broker 上,事件订阅者向中心broker 订阅和接收事件,然后再处理接收到的事件。当然,订阅者不仅可以接收和消费事件,它们本身也可以创建事件,并将它们发送到事件总线上。下面列出了4 种事件总线的实现方式,并对它们的优缺点进行了总结。

事件总线和多个订阅者(绿色箭头)和通知发送者(红色箭头)

1. 向所有的订阅者发送事件

事件总线直接将输入事件(红色箭头)发送给订阅者(蓝色方块)

参与者

事件总线、订阅者(事件处理器)、事件创建者

实现

事件创建者向事件总线发送事件,事件总线将收到的事件发送给所有的订阅者。订阅者既可以处理接收到的事件,也可以创建新事件,然后把它们发送给事件总线。事件总线不关心订阅者是否成功接收到消息。

功能需求

通知、订阅、退订。

优势

实现起来很简单。

不足

事件总线需要将每一个事件消息复制一份给订阅者,也就是说,如果有 1000 个订阅者,每一个事件都会有 1000 份拷贝,这样会占用大量的内存。

事件总线不保证消息传递的可靠性,它会尝试给订阅者发送消息,而且只会尝试一次,如果出现错误,比如网络连接错误,订阅者可能就会收不到消息。
另外,事件总线不负责过滤消息,所以订阅者需要自己实现过滤逻辑。

Elixir 的参考实现

2. 向所有订阅者发送事件影子


事件总线和事件存储及事件观察者

参与者

事件总线、事件创建者、订阅者、事件存储(Event Store)、事件观察者(Event Watcher)

实现

事件总线在收到事件创建者发送过来的事件后,把事件保存到事件存储里,然后将事件影子(Event Shadow,也就是对原始事件的引用)发送给所有的订阅者。订阅者根据事件影子从事件存储里获取事件数据,再对数据进行处理。

事件总线为每一个事件创建一个事件观察者,观察者持有订阅者列表,当所有的订阅者都接收到消息后,观察者负责把事件从事件存储里删除。

事件总线仍然不保证订阅者一定会收到所有事件影子。如果有订阅者接收消息失败,相应的观察者就会被标记为“skipped”。

功能需求

通知、订阅、退订、保存 / 删除 / 获取、标记完成 / 跳过

优势

因为事件消息被保存在事件存储里,发送给订阅者的只是事件引用,所以占用内存会小很多。

不足

订阅者需要调用额外的方法,比如在收到事件影子之后要调用方法去获取事件数据,在处理完事件后还要调用方法通知事件总线已完成处理,或者通知事件总线跳过某个事件。另外,在事件总线端还要实现事件存储和事件观察者。这个对事件存储的实现要求比较高,如果订阅者数量很多,事件存储的读负载会很重,而且在写入事件时是阻塞式的。

这种实现方式仍然不会为订阅者过滤事件,所以订阅者还是需要自己实现事件过滤。

Elixir 的参考实现

3. 向经过过滤的订阅者发送事件影子

第三种实现方式与第二种是一样的,只不过不是将事件影子发送给所有订阅者,而是发送给经过过滤的订阅者,也就是说只发送给其中的一部分订阅者。事件总线需要记录订阅者感兴趣的主题,在这里可以使用正则过滤器为订阅者过滤主题。

这种方式的优势与不足和第二种也是一样的,只是多了事件过滤功能。

Elixir 的参考实现

4. 按顺序传递

为了保证顺序传递,可以对事件进行分区。关于如何通过分区来保证顺序传递,可以参考 Kafka 的论文,基本原理是让消费者消费属于自己的分区。

不足

动态增加分区或减少分区会变得很困难,而且需要自己实现分区器,消费者的实现也很复杂。

在实现订阅者时要注意的一些问题

对于第一种和第二种方式,需要通过阻塞的方式进行事件类型(也就是主题)匹配,避免进行不必要的事件拷贝,浪费了内存。

对于第三种和第四种方式,需要通过非阻塞的方式进行事件类型(也就是主题)匹配,因为订阅者只接收感兴趣的事件。


感谢郭蕾对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们。

2017-08-07 19:004922
用户头像

发布了 322 篇内容, 共 150.6 次阅读, 收获喜欢 148 次。

关注

评论

发布
暂无评论
发现更多内容

【立哥】【每日一个小知识】铁扇公主和太上老君到底是什么关系?

Lee Chen

webpack配置优化,让你的构建速度飞起

Geek_02d948

利用规则引擎的M2M实现设备之间联动——实践类

阿里云AIoT

小程序 物联网 智能硬件 网络性能优化

堡垒机采购注意事项说明-行云管家

行云管家

网络安全 数据安全 堡垒机

js作用域、作用域链和它的一些优化

hellocoder2029

JavaScript 前端

字节前端经典面试题(附答案)

hellocoder2029

JavaScript 前端

NGINX Ingress Controller 在动态 Kubernetes 云环境中的性能测试

NGINX开源社区

nginx NGINX Ingress Controller 企业号 2 月 PK 榜

2023秋招前端面试必会的面试题

coder2028

JavaScript 前端

如何整理自己的前端面试题库

Geek_02d948

JavaScript 前端

中创中间件:基于鲲鹏DevKit开发统一监管平台,性能提升55%

极客天地

物联网平台华南1(深圳) 实例化开发实战——实践类

阿里云AIoT

监控 物联网 开发工具 智能硬件 消息中间件

碎片化NFT系统开发模式定制智能合约部署详情

开发微hkkf5566

webpack热更新原理(面试大概率会问)

Geek_02d948

JavaScript 前端

ATC:一个能将主流开源框架模型转换为昇腾模型的神奇工具

华为云开发者联盟

人工智能 华为云 昇腾 企业号 2 月 PK 榜 华为云开发者联盟

PGLBox 超大规模 GPU 端对端图学习训练框架正式发布

百度Geek说

百度飞桨 框架学习 企业号 2 月 PK 榜

前端二面经典面试题指南

hellocoder2029

JavaScript 前端

如何应对突发的流量激增和服务器过载问题

NGINX开源社区

nginx 流量 应用交付 企业号 2 月 PK 榜

Memblaze 联合 OpenCloudOS 完成技术兼容互认证

OpenCloudOS

Linux SSD

js函数式编程讲解

hellocoder2029

JavaScript 前端

全新CorelDRAW2023矢量图软件更新内容介绍

茶色酒

CorelDraw2023

植根中国,开放合作,英特尔中国开源技术委员会成立

科技之家

koa实战

coder2028

JavaScript 前端

使用JAVA读取和写入EXCEL文件

石臻臻的杂货铺

Java

PingCAP 唐刘:一个咨询顾问对 TiDB Chat2Query Demo 提出的脑洞

PingCAP

TiDB

跬智信息全新推出云原生数据底座玄武,助力国产化数据服务再次升级

Kyligence

云原生 大数据分析

软件测试 | 持续集成的开源方案攻略(二)jenkins pipeline

测吧(北京)科技有限公司

测试

行云管家免费吗?安全吗?好用吗?

行云管家

安全 行云管家 行云管家堡垒机

美团前端面试题集锦

coder2028

JavaScript 前端

不会用“函数选项模式”的朋友看过来,这么写很优雅

王中阳Go

Go golang 高效工作 学习方法 后端

Nodejs:ESModule和commonjs,傻傻分不清

coder2028

JavaScript 前端

MatrixOne 0.7.0: 更稳定,性能更优

MatrixOrigin

数据库 分布式 MatrixOrigin MatrixOne

事件总线实现方式汇总_架构_Mustafa Turan_InfoQ精选文章