写点什么

Martin Fowler 谈如何理解事件驱动

2017 年 3 月 13 日

去年年底,ThoughtWorks 内部开展了一个研讨会,讨论“事件驱动”应用程序的性质。在过去的几年里,他们建立了许多基于事件的系统,有被称赞,也有被吐槽。ThoughtWorks 的北美办公室组织了一次峰会,来自世界各地的 ThoughtWorks 高级开发人员在会上分享了他们的想法。 峰会的最大结果是得出这样的一个结论:当人们谈论“事件”时,他们实际上意味着一些完全不同的事情。 所以 Martin Fowler 花了很多时间试图从中挑出一些有用的模式, 本文就是对这些内容的简要总结。

事件通知(Event Notification)

事件通知是最基本也是最简单的模型。当一个系统发生了变更,它会通过发送事件消息的形式通知其他系统。发送消息的系统不要求接收消息的系统返回任何响应,即使有响应返回,它也不对其进行任何处理。这也就是所谓的“fire and forget”模式。

事件通知的好处在于它的简单性,并且有助于降低系统间的耦合性。不过,如果在一个复杂的生态系统里使用了太多的事件通知,可能会带来一些问题。太多的事件难以跟踪,发生问题难以调试,除非借助完善的实时监控系统。消息流错综复杂,当其规模开始膨胀开来,就会造成隐患。

通知事件不会包含太多的数据,一般只包含了一些 ID 或者链接之类的信息。对于接收消息的系统来说,如果它们想得到进一步的信息,或者要基于当前事件做出一些变更,那么它们就需要向源系统发起请求,以便获取更多的数据。那么问题来了,额外的请求不仅会造成延迟,而且一旦源系统宕机,后续的流程就无法继续进行。

事件传递状态转移(Event-Carried State Transfer)

事件传递状态转移模型比事件通知更进一步,可以看作是对事件通知的改进。这个模型最大的特点是,事件里包含了发生变更的数据。对于接收事件的系统来说,如果想要采取进一步措施,可以直接使用事件里的数据,而无需再次向源系统发起请求,从而降低了延迟。而且就算源系统宕机,也不会影响到后续的流程。

不过,既然把变更数据放在事件里进行传输,那么占用更多的带宽是不可避免的了。而且,如果有多个系统接收事件,那么这些数据就会有多个拷贝。

除此之外,接收事件的系统需要维护事件的状态,从而将原本存在于源系统的复杂性转移到了接收事件的系统上。

事件溯源(Event-Sourcing)

事件溯源的核心理念是说,在对系统的状态做出变更时,把每次变更记录为一个事件,在未来的任何时刻,都可以通过重新处理这些事件来重建系统的状态。事件存储是主要的事件来源,可以从事件存储中重建系统的状态。对于程序员来说,版本控制系统是一个最好的例子。提交日志就是事件存储,而代码工作副本就是系统状态。在某个指定的工作副本上重播提交日志就可以创建另一个工作副本,也就是重建了某个时刻的系统状态。

使用事件溯源的系统有哪些好处?首先,事件存储结构简单,易于存储,它们可以被存储在数据库里、文件系统或者其他任意的存储引擎里。因为记录事件是插入操作,没有修改也没有删除,就不需要用到事务控制,这也意味着可以避免使用锁。所以,使用事件溯源可以提升系统的性能。其次,事件本身可以充当审计日志的作用。如果不使用事件溯源,那么就需要为系统维护单独的审计日志。使用单独的审计日志就意味着有存在两个“真相源”,如果审计日志发生丢失,那么通过审计日志重建的状态与真实的系统状态会不一致。

不过,事件溯源也存在一些不足。如果事件很多,重放事件是一个耗时的过程,而且在重放过程中可能会涉及与第三方外部系统发生交互,所以需要做一些额外的操作。查询某个时刻的状态会变得很麻烦,因为需要通过重播事件来重建当时的状态。解决办法是使用快照。不过,系统没有必要为每次变更都创建快照,而是阶段性地创建快照。在查询状态时,通过在临近的快照上重放少量的事件就可以获得想要查询的状态。

CQRS

CQRS 是 Command Query Resposibility Segregation(命令查询职责分离)的缩写,它将读操作(查询)和写操作(增、删、改命令)进行分离,不仅让逻辑更清晰,而且可以各自进行优化。对于读多写少的系统来说,就特别适合使用 CQRS,因为可以针对读性能和写性能进行优化,而且可以进行横向扩展。

不过 CQRS 的概念虽然简单,但是实现起来相对复杂,而且涉及到很多领域驱动设计的(DDD)概念,最好结合事件溯源一起使用。

更多资料


感谢郭蕾对本文的审校。

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

2017 年 3 月 13 日 19:001902
用户头像

发布了 321 篇内容, 共 108.2 次阅读, 收获喜欢 101 次。

关注

评论

发布
暂无评论
  • LeetCode 题解:94. 二叉树的中序遍历,使用栈,JavaScript,详细注释

    原题链接:https://leetcode-cn.com/problems/binary-tree-inorder-traversal/

    2020 年 10 月 12 日

  • 底层系统创新 助力云原生发展

    底层系统创新 助力云原生发展

  • 事件溯源系统的追溯与未来事件

    当Thomas Pierrain与一家资产管理公司开始一个新项目的时候,其中有一项重要的需求就是能够回到过去,理解当时为什么会做出一些现在看起来很奇怪决策。在最近于阿姆斯特丹举行的DDD Europe 2018上,Pierrain讨论了他构建事件溯源系统的经历以及所面临的挑战。

  • 如何选取事件架构

    如果你要设计一个分布式系统,它可能是基于微服务的,并且你在考虑采用事件架构(Event Architecture),那么目前存在多种的模型和技术可供使用。David Dawson在近期的博客帖子中介绍了多种风格的事件架构,并指出,非功能性需求是影响架构实现选择的一个主要因素。

  • 第 26 讲 | 传统图像理解技术:图像搜索系统(1)

    2018 年 1 月 31 日

  • 支付宝背后的 OceanBase:国产自研分布式数据库这十年

    蚂蚁金服高级研究员阳振坤:用10年时间打造一个“顶天立地”的产品。

    2019 年 4 月 16 日

  • Zuul 网关对接 Apollo(Lab04)

    2018 年 7 月 8 日

  • 不可靠世界的事件溯源

    Lorenzo Nicora在最近的µCon London2017微服务讨论会上说明道:事件溯源系统的例子通常来自像电子商务这样的领域,这些领域生成事件的指令输入是面向过程的,同时这样的例子也常见于我们能够控制过程的地方。但有些领域是没有过程的,属于我们搜集外部事件的领域。这些领域的事件源本身就不可靠,传输也不可靠。

  • 事件应该成为开发者的一等工具

    这篇文章以Stitch Fix公司的一个工作流程为例,说明了如何使用事件来创建状态机。文章建议我们应该把事件看作是系统中的一等公民,因为它们帮助我们解耦系统,让我们能够独立处理各个部分。最后,文章用代码版本控制为例来帮助读者理解事件思想在实际工作中的应用。

  • 利用事件简化系统架构

    在小型业务组件之间使用事件进行交互可以简化系统架构,上周Russ Miles在探讨“通过事件简化架构(Architectural Simplicity through Events)”时谈到了这一点。

  • 09 丨软件设计实践:如何使用 UML 完成一个设计文档?

    下面我们讨论如何画这7种模型图,以及如何在需求分析、概要设计、详细设计三个阶段使用这7种模型输出合适的设计文档。

    2019 年 12 月 9 日

  • 智慧公安二维码定位报警系统开发

    二维码报警系统它是可以精确的实现定位,而我们只需要通过扫描所在位置附近的二维码,就可以将位置信息发送至警务处理中心,警务人员就会根据获取到的情报来找到用户提供的位置信息和事件信息,并迅速锁定报警人的具体位置,立刻安排任务,派遣警务人员出警执

    2020 年 11 月 30 日

  • 下一代大数据实时监控系统

    演讲嘉宾李双江,阿里巴巴 Senior Engineer内容介绍在大规模网络下,随着gRPC协议方式的采集的普及, 响应速度快,实时性高,采集数据更全面。如何将这些gRPC采集方式带来的众多优点不打折扣的提供给网络运维人员,给下一代的大数据实时监控系统带来了一定的挑战。为此,我们引入了一套基于流式计算(Blink基于开源的Apache Flink)和内存数据存储(Apache Ignite)方式的实时告警系统。借助Kafka和HBase实现数据缓存,Blink进行流式计算,Ignite进行实时的业务告警。并Blink的SQL方式进行实时计算和规则生成,通过Ignite开放SQL开发实现了数据的低延迟实时查询服务。本次分享主要介绍我们在以上方面的一些经验。内容大纲 了解如何设计一套更实时、满足多业务场景需求的大数据监控系统; 了解Blink和Ignite在大数据监控系统中的应用; 了解传统的SQL如何在整个系统中发挥作用,带来更大的灵活性和业务扩展性。

    2018 年 11 月 9 日

  • 第三章 小结

    设计模式与生产环境中的模式

    2020 年 6 月 24 日

  • 智慧公安情报研判系统开发解决方案,微警务系统搭建

    智慧公安情报研判系统开发解决方案,微警务系统搭建

    2020 年 12 月 2 日

  • TensorFlow 产生的历史必然性

    2019 年 1 月 7 日

  • Jonas Boner 谈 Events 将如何重塑现代系统

    Lightbend的创始人兼首席技术官Jonas Boner在最近的Reactive Summit 2017 会议上做了主题发言,谈到了事件驱动型服务(event driven services),以及事件驱动架构(EDA)和事件流处理(ESP)技术将会给基于分布式系统的现代应用程序的设计带来哪些帮助。

  • 食堂就餐系统设计

    食堂就餐系统设计

    2020 年 6 月 10 日

发现更多内容

软件开发:软件设计的基本原则

NORTH

极客大学架构师训练营

Spring-AliasRegistry

CoderLi

Java spring 程序员 源码分析 后端

编译Spring5.2.0源码

CoderLi

Java spring 程序员 后端 Java 25 周年

Spring 容器的初始化

CoderLi

Java spring 程序员 源码分析 后端

架构师训练营第二周 - 作业

Eric

极客大学架构师训练营

程序一定要从main函数开始运行吗?

程序喵大人

c++

后疫情时代给技术经济发展带来的挑战和机遇

CECBC区块链专委会

区块链技术 林左鸣 机遇与挑战

架构师训练营第 2 周——学习总结

在野

极客大学架构师训练营

CDN百科第四讲 | 如何优雅地在云上“摆摊”——做直播带货,你不得不关注的技术

阿里云Edge Plus

CDN 边缘计算 直播 直播带货

别教我女儿该怎么穿,教你儿子别去强奸

小天同学

教育 日常思考 个人感悟 自我保护

Spring 获取单例流程(二)

CoderLi

Java spring 程序员 源码分析 后端

ARTS 第 2 周

乌拉里

LinkedList竟然比ArrayList慢了1000多倍?(动图+性能评测)

王磊

Java 数据结构 性能优化 性能 链表

618 将至,融云通信云技术如何助力电商销售

Geek_116789

【大厂面试05期】说一说你对MySQL中锁的理解?

NotFound9

Java MySQL 后端

数字产品开发那些事

涛哥

产品开发 数字化

Spring-资源加载

CoderLi

Java spring 程序员 后端 Java 25 周年

Spring 获取单例流程(三)

CoderLi

Java spring 程序员 源码分析 后端

蚂蚁金服部门面试题解析:MySQL+Redis+MongoDB+Zookeeper+Ngnix

周老师

Java spring 编程 程序员 面试

Easy-Monitor 3.0 开源 - 基于 Egg 的 Node.js 性能监控解决方案

hyj1991

node.js 开源 前端监控

重学 Java 设计模式:实战享元模式「基于Redis秒杀,提供活动与库存信息查询场景」

小傅哥

设计模式 小傅哥 重构 代码坏味道 代码优化

Websocket直播间聊天室教程 - GoEasy快速实现聊天室

GoEasy消息推送

直播 websocket 即时通讯 聊天室 弹幕

谈谈程序链接及分段那些事

程序喵大人

c++

Java 诊断利器 Arthas 优雅排查生产环境

ytao

架构师训练营-课后作业-Week-2

Chasedreamer

Spring 获取单例流程(一)

CoderLi

Java spring 程序员 源码分析 后端

架构师训练营第二周总结

一剑

架构师训练营第二周 - 学习总结

Eric

架构是训练营

iOS Universal link 30分钟入门指南

行者

ARTS-Week Four

shepherd

Java algorithm

以太坊颠覆了以太坊:引入密码学实现2.0性能突破

安比实验室SECBIT

以太坊 分布式系统 节点 密码学

Martin Fowler谈如何理解事件驱动-InfoQ