作者|Mustafa Turan译者|薛命灯架构师 Mustafa Turan 在 Hackernoon 上分享了事件总线的几种实现方式,并总结了每一种实现方式的优缺点。

基于事件驱动的分布式异步架构模式多用于构建高可伸缩的反应式应用程序,适用于各种从简单到复杂的应用场景。它的核心思想是去耦合,将消息的发送和接收分开,实现异步处理消息事件。

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

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

四种实现方式向所有的订阅者发送事件

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

参与者

  • 事件总线

  • 订阅者(事件处理器)

  • 事件创建者

实现

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

功能需求

  • 通知

  • 订阅

  • 退订

优势

实现起来很简单。

不足

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

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

Elixir 的参考实现:

https://github.com/mustafaturan/event_bus/commit/08a955294c1d1c5bec2c7fef28ed255400e5f322

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

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

参与者

  • 事件总线

  • 事件创建者

  • 订阅者

  • 事件存储(Event Store)

  • 事件观察者(Event Watcher)

实现

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

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

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

功能需求

  • 通知

  • 订阅

  • 退订

  • 保存 / 删除 / 获取

  • 标记完成 / 跳过

优势

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

不足

订阅者需要调用额外的方法,比如在收到事件影子之后要调用方法去获取事件数据,在处理完事件后还要调用方法通知事件总线已完成处理,或者通知事件总线跳过某个事件。

另外,在事件总线端还要实现事件存储和事件观察者。这个对事件存储的实现要求比较高,如果订阅者数量很多,事件存储的读负载会很重,而且在写入事件时是阻塞式的。

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

Elixir 的参考实现:

https://github.com/mustafaturan/event_bus/releases/tag/v0.2.1

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

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

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

Elixir 的参考实现:

https://github.com/mustafaturan/event_bus

按顺序传递

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

不足

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

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

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

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

阅读原文

https://hackernoon.com/event-bus-implementation-s-d2854a9fafd5

看完本文有收获?请转发分享给更多人


欢迎关注“互联网架构师”,我们分享最有价值的互联网技术干货文章,助力您成为有思想的全栈架构师,我们只聊互联网、只聊架构,不聊其他!打造最有价值的架构师圈子和社区。

本公众号覆盖中国主要首席架构师、高级架构师、CTO、技术总监、技术负责人等人 群。分享最有价值的架构思想和内容。打造中国互联网圈最有价值的架构师圈子。

  • 长按下方的二维码可以快速关注我们

  • 如想加群讨论学习,请点击右下角的“加群学习”菜单入群

解析事件总线的4种实现方式相关推荐

  1. java用户输入解析_Java中的3种输入方式实现解析

    Java中的3种输入方式实现解析 发布于 2020-8-8| 复制链接 摘记: 这篇文章主要介绍了Java中的3种输入方式实现解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学 ...

  2. android密码dakay,安卓中按钮点击事件onClick的两种实现方式

    很多的语言都有一些共同的特点,比如OnClick这个东西,可能我们能在js中见到,当然在安卓中也有,可能其他的编程语言也会有这个东西,刚好今天学了这个玩意在安卓中的写法. 点击事件大多用在Button ...

  3. java响应事件_Swing中添加事件响应的三种处理方式说明

    举例说明事件响应 在Swing中,事件响应是通过监听器对象来处理事件的方式实行的,这种方式被称为事件委托模型. 以JButton举例,它内部有一个名为listenerList的链表,在点击按钮时,会产 ...

  4. java添加事件监听器_Java事件监听器的四种实现方式

    自身类作为事件监听器 外部类作为事件监听器 匿名内部类作为事件监听器 内部类作为事件监听器 自身类作为事件监听器: 1 import javax.swing.*;2 import java.awt.* ...

  5. python点击事件onclick_巨蟒python全栈开发数据库前端6:事件onclick的两种绑定方式onblur和onfocus事件window.onload解释小米商城讲解...

    1.回顾上节内容(JavaScript) 一.JavaScript概述 1.ECMAScript和JavaScript的关系 2.ECMAScript的历史 3.JavaScript是一门前后端都可以 ...

  6. Vert.x实战 事件总线:Vert.x应用程序的主干

    本章包括: 什么是事件总线 如何在事件总线上拥有点对点通信[point-to-point].请求-应答通信[request-reply].发布/订阅通信[publish/subscribe] 用于在网 ...

  7. vue 事件总线EventBus的概念、使用以及注意点

    vue组件中的数据传递最最常见的就是父子组件之间的传递.父传子通过props向下传递数据给子组件:子传父通过$emit发送事件,并携带数据给父组件.而有时两个组件之间毫无关系,或者他们之间的结构复杂, ...

  8. 【Vue组件间通信】 全局事件总线、订阅与发布

    目录 一.全局事件总线 作用 安装 组件使用案例 案例分析 组件一(小明) 组件二(小红) 效果展示 二.订阅与发布 安装 组件使用案例 案例分析 组件一(小明) 组件二(小红) 效果展示 一.全局事 ...

  9. 第三章: 事件总线:Vert.x 应用程序的支柱

    本章涵盖了 事件总线是什么 如何通过事件总线进行点对点.请求-回复 和 发布/订阅 通信 用于通过网络进行verticle到verticle通信的分布式事件总线 上一章介绍了verticles. 一个 ...

  10. RxJava实现事件总线——RxBus

    事件总线的好处在于方便组件之间的交互,RxBus不是一个库,而是使用RxJava实现事件总线的一种思想.首先介绍一下RxJava与事件总线的不同之处. RxJava使用的是Observable-Obs ...

最新文章

  1. 36.centos 安装文泉驿字体
  2. 找不到或无法加载主类
  3. 反思~我们是否应当克制对新技术的追求?
  4. 您不是订单管理的定向开发者_Web Summit 2020大会:华为在欧洲发布HMS Connect,持续助力合作伙伴与开发者的创新增长...
  5. swi 指令能用在C语言吗,内嵌汇编指令的应用举例
  6. IOS开发笔记之十七——一个关于工程目录读写权限的问题
  7. ConcurrentHashMap的源码分析-resizeStamp
  8. 如何识别一个人是web前端程序员
  9. es6 for...of 循环
  10. VC中将bmp作为资源文件写入EXE或DLL,然后内部调用(转)
  11. php脚本搭vps,#分享#基于宝塔面板的ZFaka(发卡程序)一键脚本
  12. 线程间的通信之wait和notify的使用
  13. WPS Office JS宏实现文件和数据的上传及下载
  14. 测量学-导线测量-测回法
  15. 大学计算机教程王梦倩,【经验共享】中国矿业大学资源学院辅导员王梦倩
  16. python 根据单位名称爬取单位统一社会信用代码
  17. Maven打包 错误: 程序包org.junit不存在
  18. Seismic Unix安装
  19. React18 tearing tree issue 撕裂状态问题
  20. C# WPF 进度条,根据读取数据显示进度条进度,根据Excel文件读取数据,进度条样式...

热门文章

  1. 《vSphere性能设计:性能密集场景下CPU、内存、存储及网络的最佳设计实践》一1.2.4 存储...
  2. Nginx 设置文件缓存时间
  3. 什么是dos及常见命令详解
  4. SqlCommandBuilder自动创建dataAdapter数据库操作命令
  5. 「代码随想录」本周小结!(动态规划系列一)
  6. 如何在Mac上选取打开文件的应用?
  7. 开发工具Charles for Mac(信息抓取) v4.6.3b1
  8. Mac电脑不能识别文本和命令的解决方法
  9. mac如何删除用户或者群组
  10. 16:忽略大小写的字符串比较