作者|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. Ubuntu16.04安装qt
  2. 【数据】短视频识别,都有那些行业标准?
  3. beyond compare 不自动比较解决办法(没解决,可以ctrl + F5手动比较)
  4. Linux Kernel 3.8.8/3.4.41/3.0.74 发布
  5. system函数_自学C++基础教程【函数】
  6. h5如何上传文件二进制流_HTML5新特性之文件和二进制数据的操作
  7. 解决方案 | MySQL DBA主从复制出错怎么办?
  8. 【力扣】NO.13.罗马数字转整数
  9. 目标检测——YOLOv5的学习笔记
  10. 一致性Hash与负载均衡
  11. [kuangbin带你飞]专题四 最短路练习
  12. Windows 配置 Aria2教程
  13. 微信群二维码活码生成 微信活码
  14. The Flee Plan of Groundhog(DFS)
  15. 判断是否微信打开实现跳转
  16. blog10 提取候选词的输入文本
  17. 遗传算法(Genetic Algorithm)之deap学习笔记(一): 基础概念
  18. Trac - Trac Download - Trac下载
  19. 台式计算机开关电源的电压规格,开关电源电压如何调整如我的电脑开关电源有12V的直流电我想调整为14V的直流为其它电器供电,应该如何调整...
  20. Windows 2003上Oracle通过端口映射访问连接超时的解决办法

热门文章

  1. [MVC学习笔记]4.使用Log4Net来进行错误日志的记录
  2. HttpSendRequest向服务端发送数据,构造请求http头
  3. SQL Server 数据库做读写分离
  4. 975分过CCNA 640-801体会分享
  5. 「leetcode」57. 插入区间:【模拟插入】详细讲解!
  6. Illustrator 教程,如何在 Illustrator 中添加文本段落?
  7. SwitchResX Mac屏幕分辨率调整工具
  8. 如何制作macOS Monterey启动U盘
  9. Fundebug前端JavaScript插件更新至1.6.0,新增test()方法用于测试 1
  10. 浅谈RSTP的快速收敛机制 P/A机制