作者 | 史明伟(世如)
距离阿里云事件总线(EventBridge)和 Serverless 函数计算(Function Compute,FC)宣布全面深度集成已经过去一年。站在系统元数据互通,产品深度集成的肩膀上,这一年我们又走过了哪些历程?
从事件总线到事件流,从基于 CloudEvents 的事件总线触发到更具个性化的事件流触发,函数计算已成为事件总线生态不可或缺的重要组成部分,承载了 EventBridge 系统架构中越来越多的角色,事件流基础架构的函数 Transform,基于函数计算的多种下游 Sink Connector 投递目标支持,函数作为 EventBridge 端点 API Destination;基于事件总线统一,标准的事件通道能力,和基于函数计算敏捷、轻量、弹性的计算能力,我们将又一次起航探索云上事件驱动架构的最佳实践。
本文主题围绕事件总线+函数计算,构建云上最佳事件驱动架构应用。希望通过下面的分享,帮助大家深入理解 Serverless 函数计算、EventBridge 事件总线对于构建云上事件驱动架构应用的价值和背后的逻辑、 为什么函数计算是云上事件驱动服务最佳实践?为什么我们如此需要事件总线服务?伴随着这些谜题的解开,最后,让我们一起了解应用于实际生产的一些 Serverless 事件驱动客户案例。
事件驱动架构的本质
Back to the Nature of Event-Driven
大家可能会疑惑,事件驱动家喻户晓,为什么我们又要重新讨论事件驱动呢?我想这也正是我们需要讨论它的原因,回归本质,重新起航。
事件驱动可能是一个比较宽泛的概念,而本文聚焦事件驱动架构的讨论,事件驱动架构作为一种软件设计模式,的确不是一个新的概念,伴随着计算机软件架构的演进,它已经存在了一段很久的时间,大家对它的讨论也从未停止过,当我们需要重新讨论一个已经存在的概念的时候,我想我们有必要重新回到它最开始的定义,一起探索那些本质的东西,重新认识它。

上面的这些内容是我从相关的一些资料上摘录的关于事件驱动架构的一些描述,“abstract”,“simple”,“asynchronous”,“message-driven” 这些具有代表性的词汇很好的给予事件驱动架构一个宏观的描述;从事件驱动架构的抽象概念,到它简洁的架构,以及事件驱动架构要达成的目的,和它在实际的系统架构中所展现的形态。
事件驱动架构基本概念及形态
在了解了关于事件驱动架构的一些基本描述之后,我们需要进一步明确事件驱动架构所涉及的一些基本概念和架构形态。根据维基百科描述,事件驱动架构涉及的核心概念如下所示:

事件驱动架构基本形态

围绕事件的流转,根据事件驱动架构的概念和基本形态,主要涉及以下四个核心部分:
事件驱动架构要达成的目的
了解了事件驱动架构的基本形态,架构中事件通道的引入,解耦了事件生产和事件处理这两个最基本的系统角色,那么这样的架构模型所要达成的最终目的到底是什么?

系统架构松耦合
事件生产者与事件订阅者在逻辑上是分开的。事件的生成与使用的分离意味着服务具有互操作性,但可以独立扩缩、更新和部署。
只面向事件的松散耦合可以减少系统依赖项,并允许您以不同的语言和框架实现服务。您无需更改任何一个服务的逻辑,即可添加或移除事件生成方和接收方。您无需编写自定义代码来轮询、过滤和路由事件。
系统的可伸缩性
基于事件驱动架构的松耦合特性,意味着可以独立对事件生产者,事件通道服务,以及事件处理引擎进行独立的扩缩容;尤其对于后端事件处理引擎,可以根据消息处理响应 SLA 和后端资源供给进行弹性扩缩容;同时可以基于事件粒度构建不同规格的后端处理服务,实现更细粒度的系统弹性伸缩。
系统的可扩展性,主要表现在当系统需要增加新的功能,如何快速的基于现有系统架构快速构建支持新的业务逻辑,在事件驱动架构应用中,围绕事件粒度的处理模式,能够天然快速支持增加新的基于事件的数据流抽象。
当系统中增加新的事件类型的时候,无需调整变更发布整个系统,只需要关注需要订阅的事件进行事件处理逻辑的开发和部署即可,也可以基于原来的系统做很少的代码变更即可实现,也可以在业务初期通过独立的服务订阅指定的事件完成特定的业务逻辑支持。
**为什么函数计算是云上事件驱动服务最佳实践?
**
在讨论完事件驱动架构基本模型之后,我想关于事件驱动的概念,形态我们有了统一的认识和理解,接下来我们进入议题的第二个部分,为什么函数计算是云上事件驱动服务最佳实践?
函数计算简介
**函数计算 FC **是一款基于事件驱动的全托管计算服务,相关的产品细节可以见官网介绍。作为一款通用的事件驱动型计算服务,接下来我会从三个方面进行详细的介绍。

使用函数计算,用户无需采购与管理服务器等基础设施,只需编写并上传代码。函数计算为你准备好计算资源,弹性地、可靠地运行任务,并提供日志查询、性能监控和报警等开箱即用功能,编程范式带来开发的“简单,快捷”。
按照函数粒度进行独立的功能单元开发,快速调试,快速的部署上线,省去了大量资源购买,环境搭建的运维工作;同时函数计算是一个事件驱动的模型,事件驱动,意味着用户不需要关注服务产品数据传递的问题,省去了在编写代码中涉及的大量服务访问连接的逻辑;“事件驱动” + “函数粒度开发” + “免服务器运维”等几个维度特征帮助函数计算支撑“聚焦业务逻辑敏捷开发”的底层逻辑。

除了开发模式带来的研发效能提升之外,函数计算提供非常细粒度的计算资源和毫秒级计费模型,支撑按需计算,按量收费;能够支持按用户的请求,根据用户流量的模型为计算付费;当然按用户请求付费存在技术上巨大的挑战,要求函数计算实例的启动小于用户的 RT 要求,冷启动性能尤为重要,这时候极致弹性成为了 Serverless 按需付费,业务降本的底层技术支撑。函数计算通过“极致弹性” + “按需付费”的模型帮助 Serverless 函数计算实现真正的按需计算逻辑。

在基于云的开发环境,云产品承载的服务相对内聚,各自扮演着分布式系统架构中的各个重要角色,云产品之间的事件触发机制能够帮助客户更好的基于多个云产品构建自己的业务系统;否则需要用户自己负责云产品事件的监听,串联云服务,进行复杂的错误处理,这是非常复杂,开发代价极其昂贵的一件事;
除了产品连接带来的开发效率之外,当用户订阅某个事件,并提供处理逻辑的时候,客户已经潜在的过滤掉了不需要处理的事件请求,事件驱动意味着每一次的事件触发请求都是一次完全有效的计算。

函数计算对于事件驱动架构的价值
为什么函数计算是云上最佳的事件驱动架构服务?函数计算对于事件驱动架构的核心价值到底是什么?
事件驱动架构一直存在,在没有函数计算的时候,同样也有事件驱动架构,在微服务的时候也同样有事件驱动架构。如今,当我们重新再来讨论事件驱动架构的时候,到底是什么发生了变化,有哪些本质的区别?在整个事件驱动架构中,函数计算最大的价值在于帮助构建 “Event Processing Engine” 这个角色,我想主要是以下两个方面发生了本质的变化:

开发模式发生了本质的变化:函数计算提供的框架能力及编程模型,最大化的消除了客户业务逻辑之外的处理内容,极大的加速了客户业务开发,同时基于这样这样的开发模式,用户对于新增事件处理逻辑能够在最短的时间完成处理并上线,细粒度,专注业务的敏捷开发模式能够加速业务快速上线。
计算模式发生了本质的变化:基于事件驱动架构事件粒度的处理逻辑和函数计算更细粒度力度计算弹性能力,能够从多个维度实现 “Event Processing Engine” 组件的弹性能力, 这我想这也是函数计算对于事件驱动架构的一个最核心价值。
为什么我们如此需要事件总线服务?
构建云上事件驱动架构挑战
函数计算以其轻量,快捷,能够利用事件驱动的方式与其他云产品进行联动的特点, 成为很多客户利用事件驱动架构构建业务系统的首选,随着业务及客户需求的不断增加,客户对于函数计算和更多云产品及服务的连接需求变得越来越多,同时对于其他云产品的客户而言, 也希望能够利用 Serverless 函数计算的特点帮助处理一些系统任务和事件。
尽管函数计算和云上的众多云产品进行了集成,提供了一些开箱即用的事件触发能力,那么我们为什么还需要事件总线服务来构建事件驱动应用架构呢?
围绕函数计算构建事件驱动架构生态的过程中,我们面临主要来自三个方面的挑战。面对这些挑战,基于函数计算和事件总线帮助云上客户构建完备的事件驱动架构生态迫在眉睫。

事件驱动作为函数计算产品核心竞争力,打通函数计算和其它云产品,以及用户自定义应用,SaaS 服务的连通成为函数计算生态集成的迫切需求,但系统集成,生态建设从来都不是一件容易的事情。
函数计算系统在和 EventBridge 集成之前,已经和 OSS,SLS 等用户典型场景的云产品进行了集成,也和阿里云的其它大概十多款产品进行了集成,不同系统具有不同的事件格式,不同系统的注册通知机制也各不相同,以及上游不同系统的失败处理机制也各不相同。
部分系统支持同步的调用方式,部分系统支持异步的调用方式,调用方式的差异主要取决于上游系统在接入函数计算的时候当时面临的产品业务场景,对于新的产品能力和业务场景的扩展支持,在当时并未有太多的考虑。随着和更多云产品的集成,集成的投入,集成的困难度和底层数据管理难度越来越大。面对多种事件源集成的客观困难,函数计算急需提高和其他云产品的集成效率。
除此之外, 函数计算希望提升用户体验,保证用户只关心事件的处理;同时希望能够在面对大量的云产品时保证系统授权层面的复杂度。用户在使用事件触发的时候, 需要了解不同产品接入函数计算的权限要求,针对不同的产品需要提供不同的授权策略,对于客户使用函数计算带来了非常大的困难,为了加速产品接入,大量用户经常使用 FullAcees 权限,造成较大产品安全隐患, 和其它云产品的集成急需统一的授权界面,统一用户体验。
面对上游不同的事件源, 如何更好的投递事件、更好的消费事件?如何进行事件的错误处理?函数计算调用方式如何选择?以及函数计算后端错误 Backpressure 能力的反馈、重试策略和上游系统参数设置、触发器数量的限制等问题获成为函数计算事件触发不得不面对的问题。
为了更好的服务客户,提供可靠的消费处理能力,函数计算希望能够有一个统一的接入层,基于统一的接入层进行消费能力和流控能力的建设。通过沉淀在这样一个标准的层面,在保证调用灵活性的同时,提供可靠的服务质量。
事件总线简介
阿里云事件总线(EventBridge) 是一种无服务器事件总线,支持将用户的应用程序、第三方软件即服务 (SaaS)数据和阿里云服务的数据通过事件的方式轻松的连接到一起,这里汇聚了来自云产品及 SaaS 服务的丰富事件;

从整个架构来看,EventBridge 通过事件总线,事件规则将事件源和事件目标进行连接。首先,让我们快速普及下 EventBridge 架构中涉及的几个核心概念:
通过上面的流程,完成了事件的产生,事件的投递,事件的处理整个过程。当然事件并不是一个新的概念,事件驱动架构也不是一个新的概念,事件在我们的系统中无处不在,事件驱动架构同样伴随着整个计算机的架构演进,不断地被讨论。
对于 EventBridge,采用云原生事件标准 CloudEvents 来描述事件;带来事件的标准化,这样的标准化和事件标准的开放性带来一个最显著的优势:接入的标准化,无论是对于事件源还是事件目标。
消息产品凭借其异步解耦、削峰填谷的特点,成为了互联网分布式架构的必要组成部分,Serverless 函数计算有着与其完全吻合的应用场景,针对消息产品生态集成,函数计算在架构层面做了专门的建设,基于 EventBridge 产品提供的 EventStreaming 通道能力建设了通用的消息消费服务 Poller Service,基于该架构对用户提供了 RocketMQ,Kafka,RabbitMQ,MNS 等多个消息类型触发能力。
将消费的逻辑服务化,从业务逻辑中剥离由平台提供,消费逻辑和处理逻辑的分离,将传统架构的消息拉模型转化成 Serverless 化的事件驱动推模型,能够支撑由函数计算承载消息处理的计算逻辑 ,实现消息处理的 Serverless 化。
基于这样的架构,能够帮助客户解决消息客户端的集成连接问题,简化消息处理逻辑的实现,同时对于波峰波谷的业务模型,结合函数计算提供细粒度的计算弹性能力,能够实现资源的动态扩容,降低用户成本。

事件总线对于事件驱动架构的价值



利用函数计算提供的 HTTP 函数 URL 能力,结合事件总线端点 API 能力,能够快速的帮助客户进行系统扩展和集成。

客户场景案例分享
总线模式+函数计算用户案例



事件流模式+函数计算用户案例
利用函数计算细粒度资源弹性特征,结合业务波峰波谷的特点,实现快速的消息清洗和处理。



在购物车加购,商品变更通知场景,利用函数计算异步系统(内部自带 Queue 能力),触发大量运营通知,利用函数异步的 Destination 能力将运营通知结果写入 MQ,然后利用事件流能力对 MQ 数据进行再次处理,写入 HBase 数据库中。

更多内容关注 Serverless 微信公众号(ID:serverlessdevs),汇集 Serverless 技术最全内容,定期举办 Serverless 活动、直播,用户最佳实践。
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此
我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r
刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr
我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭10年前。问题1)我想知道rubyonrails是否有功能类似于primefaces的gem。我问的原因是如果您使用primefaces(http://www.primefaces.org/showcase-labs/ui/home.jsf),开发人员无需担心javascript或jquery的东西。据我所知,JSF是一个规范,基于规范的各种可用实现,prim
是否可以在应用程序中包含的gem代码中知道应用程序的Rails文件系统根目录?这是gem来源的示例:moduleMyGemdefself.included(base)putsRails.root#returnnilendendActionController::Base.send:include,MyGem谢谢,抱歉我的英语不好 最佳答案 我发现解决类似问题的解决方案是使用railtie初始化程序包含我的模块。所以,在你的/lib/mygem/railtie.rbmoduleMyGemclassRailtie使用此代码,您的模块将在
是否有简单的方法来更改默认ISO格式(yyyy-mm-dd)的ActiveAdmin日期过滤器显示格式? 最佳答案 您可以像这样为日期选择器提供额外的选项,而不是覆盖js:=f.input:my_date,as::datepicker,datepicker_options:{dateFormat:"mm/dd/yy"} 关于ruby-on-rails-事件管理员日期过滤器日期格式自定义,我们在StackOverflow上找到一个类似的问题: https://s