事件集成和领域事件(事件集成和领域事件集成区别)

4747 944 2022-10-30

本站部分文章、图片属于网络上可搜索到的公开信息,均用于学习和交流用途,不能代表睿象云的观点、立场或意见。我们接受网民的监督,如发现任何违法内容或侵犯了您的权益,请第一时间联系小编邮箱jiasou666@gmail.com 处理。

本文目录一览:

用上下游思维实现系统解耦

在软件开发领域 解耦 这个词相信大家都不陌生。在面向对象的语境下,我们会应用SOLID原则来构建高内聚低耦合的应用,实现模块间的解耦;在复杂业务系统分析和建模时,会通过DDD的战略和战术设计帮助划分领域并实现分布式系统中服务的解耦;当我们在组织大型敏捷开发团队协同工作时,通过组建自治团队来减少摩擦,从而实现团队级别的解耦。可以看到解耦无处不在,并且以此为目的投入大家都会觉得是无比的政治正确,因为实现了解耦,我们的系统和应用就能更快速的扩展和演进,我们的团队就能更顺畅的合作并能更加快速的实现业务价值。但是,当我们暂时抛开将得到的种种好处思考要如何去实现它时,却发现解耦这个词表达的意义过于抽象和模糊,它既没有描述最终的状态也没有提供实现的方法。那当我们谈解耦的时候,具体内容是什么呢?从字面上理解的所谓耦合,通常是指 两个或两个以上的物体或者体系之间相互作用彼此影响 ,对应到软件研发的以上场景,我们可以转换成是指 两个或两个以上的模块/系统/团队之间相互作用彼此影响 。在软件需要解决的业务问题越来复杂的今天,单个的系统或者团队很难在不依赖外部的情况下去实现业务目标,所以我理解的 解耦 并不是要消除耦合(彼此的作用和影响/依赖),而是指我们应该如何通过一定的方式和规则来设计和管理以上提到的多个元素之间的依赖,降低耦合程度来使整个系统有序顺畅的运转。本文将从服务间上下游的思维来讨论如何在系统架构演进过程中,持续的保持服务间的松耦合,实现解耦的目标。

上下游思维定义

关于服务的上下游的定义,在DDD建模方法中,在确定了限界上下文(bounded context)后通过在上下文映射(context mapping)中使用上下游来表示上下文依赖的方向,其确定的依据是下游需要了解上游的领域知识,反之则不会。引申的含义就是上游的业务能力可以不用关心下游业务的存在,下游业务的开展依赖于上游提供的业务能力。下图是限界上下文映射的一个例子:

当我们基于以上的限界上下文设计领域模型并进行落地时,理想的情况是一个限界上下文对应一个应用服务。参考限界上下文的上下游关系,我把上下游思维定义为: 上游服务不受下游服务的业务能力和可用性影响,反之则相反 。我们会发现服务间的上下游关系比限界上下文中领域知识的上下游关系更复杂,而且上下游关系也会随着集成方式的不同而变化。

基于上下游思维的耦合级别定义

基于服务上下游的思维,我把服务间依赖按以下维度进行耦合度分级:

Level4 : 领域知识互为上下游,业务可用性互为上下游

Level3 : 领域知识互为上下游,  业务可用性为单一上下游

Level2 : 领域知识为单一上下游,业务可用性互为上下游

Level1 : 领域知识为单一上下游,业务可用性为单一上下游 

由于松耦合的业务模型利于松耦合的架构设计和业务的演进,同时松耦合的架构也利于组建松耦合的团队结构。业务模型作为松耦合设计的基础,以上的级别依据于这个思路定义的。

一种常见的 Level4 级别的情况是处于伙伴关系的上下文。比如订单服务与派送服务之间通过同步API的方式进行通信,用户订单下单成功,通知派送服务,派送服务完成,更新订单状态。两个服务通过API进行集成,服务需要相互知道对方的部分领域知识来完成API的调用以实现功能,同时业务的可用性互相关联,一方服务不可用,导致整个业务的中断。

如果希望耦合度向 level3 演进,不希望服务的可用性产生直接的依赖,我们通常会通过引入消息中间件来进行解耦,服务间通过消息的方式进行集成,由于某些原因,它们都按照对方的领域模型定义的消息结构进行通信。那么这种情况下,服务间的领域知识相互耦合,业务可用性与具体的服务解耦,与消息中间件的可用性耦合,我们需要关注如何提高消息中间件的可用性来保障业务的可用性。

Level2 级别的耦合度是建立在清晰的领域限界上下文边界基础上的,在具体构建服务时,根据团队的组织结构和话语权的大小,又可以通过不同的方式来进行服务的集成。上游服务通常使用Open Host Service(OHS) / Published Language(PL)来提供业务能力,下游服务通过遵循上游的领域模型或者通过防腐层(Anti Cruption Layer - ACL)来完成领域模型的转换。处于这个级别耦合度的上下游服务在开放主机接口不变的情况下可以独立的进行迭代更新,否则需要通知下游服务评估影响,并同步进行变更。

接下来可以更近一步,我们通常会通过引入消息中间件来对服务可用性依赖进行解耦来达到 Level1 的级别。处在这一级别的服务之间,由于有明确的上下文边界和依赖关系,消息的结构也是上游系统来定义和维护的。那么如何基于业务场景来设计消息结构、集成和更新规则,以及支持兼容性的消息格式更新方式是这一级别需要关注的问题。

四种耦合级别中,从高到低对团队的业务建模和技术能力要求越来越高,也随着耦合度的减轻对变化的业务适应能力越来越强。

通过耦合级别来做出架构上的权衡

那么基于上述耦合级别的区分,如何在设计架构时进行取舍呢?

对于处在 level4 级别的系统,如果服务都在团队的职责范围内,在保证高可用的前提下,在业务需求变化不频繁的情况下,它暂时可以工作。如果系统由不同的团队维护,或者需求变更频繁的情况下,需要对业务模型进行优化,通过定义清楚的上下游关系以达到 level2 级别以增强架构的适应性。

对于处在 level3 级别的系统,由于领域知识的耦合,服务都需要有其它领域的知识来完成自己的业务能力,随着服务的增多很容易退化成网状的依赖,通常新的业务变更需要同时修改多个服务,异步的集成方式也增加了扩展和维护的难度。处在这一层级的系统,优先级还是通过优化业务模型,定义清楚的上下游关系,至于是否需要使用异步的方式集成,需要综合权衡业务的实时性和一致性要求来进行权衡是过度到 level2 还是 level1 。

对于处在 level2 级别的系统,由于系统的上下游关系相对清晰,重点可以放在采用合适的方式来完成上下游系统的集成上以实现。一般上游系统通过OHS/PL在保证发布语言不变化的情况下,可以独立的进行迭代更新;下游系统是通过跟随或者添加防腐层来屏蔽上游业务模型变化带来的影响,取决于业务模型变化的频繁程度和添加新一层的成本。通常在绿地项目中,同时使用OHS/PL和ACL会比较好的隔离相互之间的影响。

对于处在 level1 级别的系统,在业务和技术上都具备了松耦合的基础,但是此时需要警惕一种新的依赖产生。由于上游系统在消息格式的设计时没有按照使用场景来设计,或者消息格式不能很好的在向前兼容的情况下进行更新,这带来的后果是上游系统会成为下游新增业务的强依赖,因为任何的新需求可能需要上游系统定义新的消息格式来支持,上游系统会成为响应变化的瓶颈。

消息集成通常有以下几种模式:

消息体包含领域事件发生后领域模型的最新状态和变更内容

消息体包含领域事件发生后领域模型的最新状态

消息体包含领域事件发生后领域模型的变更内容

消息体只包含领域事件发生后领域模型的标识,需要消费者按需通过API来获取相关信息

以上是对于分布式系统中关于服务解耦的一些思考,希望上下游的思维能够在做设计和系统开发时给大家提供对照参考,帮助我们实现松耦合的目标,同时也有助于减小团队之间的依赖和摩擦。

建筑工程领域突发事件以什么突发事件为主

项目工程质量。

建筑工程领域突发事件以项目工程质量突发事件为主分。建筑工程领域突发事件指工程建设、建筑业以及城市设施领域突然发生,造成或可能造成严重社会危害,需要采取应急处置措施予以应对的各类突发事件。

建设安全事故应急工作应坚持早发现、早报告、早处置方针。以人为本,明确职责。以保护人民群众生命财产安全为首要目标,实行强化行业监管与企业规范经营相结合的长效管理原则。建立健全安全事故风险防范体系,提高安全事故预防和处理能力,尽可能避免或减少安全事故发生。

建筑工程领域突发事件应急处置机制

1、服从局应急指挥部的统一指挥,及时派遣队伍实施抢险救援工作。

2、落实应急抢险救援人员,并进行应急抢险救援纪律、程序和注意事项的教育。

3、按规定集中存放配备、装备,并派专人负责四、应急保障机制。

如何设计文件服务

在面向架构编程一文中,我阐述了自己对架构和代码之间的关系的看法:「 代码需要反映出架构 」!

本文通过对文件服务 核心功能 的设计与实现,来验证这一观点。设计过程融合了「用例驱动设计」和「领域驱动设计」!

文件服务器的核心功能就两个:「 文件上传 」和「 文件下载 」!其中上传可能需要支持断点续传、分片上传。而下载可能需要进行下载保护,例如非指定客户端无法下载。

除了这两个核心功能,一般都会有一个额外功能,就是「转换」!转换包括:

除了上面的业务功能外,还包括如下非功能性约束:

根据功能,可划分如下功能模块:

首先通过分层架构对模块进行一个大致的划分,按照领域设计的分层方式:

从上面的流程可以看到「上传模块」对「转换模块」有一定的依赖,像下面这样:

但是,「上传模块」是核心模块,而「转换模块」是非核心模块。核心模块的功能相对稳定,非核心模块的功能相对不稳定。让稳定的模块去依赖不稳定的模块,会导致稳定的模块也不稳定,所以需要对依赖进行「倒置」。

「依赖倒置」解决了模块依赖问题。但是转换是个很耗时的过程,例如用户上传视频,在不转换的情况下,只要上传完成就可以得到响应,但是如果转换的话,可能就需要双倍甚至三四倍的时间才能得到反馈,体验非常的不好。且一般上传和观看的时效性并不需要即时性,所以转换应该是个异步的过程。

异步执行的方式很多,比如基于事件,自定义线程等。这里通过事件的方式来进行处理。(领域事件可参考领域设计:领域事件)

文件上传会创建UploadEvent,UploadListener监听UploadEvent事件,当监听到了UploadEvent,则执行转换。

转换流程异步化后,如何告知客户端转换结果呢?有几种方案:

另外对于下载来说,实际直接通过Nginx这样的web服务器就可以了,所以下载模块可以直接独立。

对于配置模块来说,配置可以分为两种:

「静态配置」可以使用属性文件进行配置即可。「动态配置」需要根据不同的系统进行相应的配置,故针对图片和视频等资源配置,创建对应的配置类,根据参数通过Respository动态构建。

整体结构如下:

基于上面的设计,流程需要进行相应的调整。

下载流程不变,多了一个获取转换后文件链接的流程:

相应的模块也有调整,新增了一个 消息模块 ,用于处理消息的发送与监听。这个消息属于领域事件,所以也放在领域层。

上传流程 :

下载流程 :

获取真实链接流程 :

例如,现在要新增一个「秒传功能」,即对于服务器已经存在的文件,不再进行上传操作,直接返回文件URL!那么需要做如下扩展:

上面的修改不需要对现有流程做任何改动。

事件串联了整个上传流程:

由于目前大部分是内部事件,故使用Spring事件来处理,代码逻辑如下:

为了提高文件服务器的灵活性,对于转换逻辑可进行配置。如果没有进行相应的配置,则不会进行对应的处理。

下面的四个类是对各个文件类型的配置:

对应的Respository是对其保存与恢复的仓储类:

此处基于属性配置来实现(原因请见「技术选型」)!以VideoConfigRespository为例:

通过Spring的ConfigurationProperties注解,将属性文件中的属性配置到videoConfigList中。

转换结果通过ConvertResult和ConvertFileInfo表示:

ConvertResultRespository是这个聚合的仓储,用于保存与恢复此聚合。此处没有使用数据库,而是直接使用的文本形式保存(原因见「技术选型」)。

转换服务根据配置委托对应的工具类来进行相应的操作(代码略):

提供两个接口:

本文给出了一个文件服务相对完整的架构设计与实现过程。整个架构设计流程如下:

整个过程对各个约束做出了对应的决策,并进行了验证。代码结构与架构设计完全匹配。从架构设计图依图索骥即可理解代码逻辑。

如有不妥或纰漏之处,欢迎大家探讨指教!

如何解释DDD中领域事件中的event和command

Event: 领域事件

Command: 领域事件的输入属性.

两者均为DDD领域驱动设计中的概念。

参考:DDD领域设计的一些总结: 事件风暴,领域事件

名词解释 媒体领域突发事件

媒体领域突发事件主要有以下三条:

第一条 为了预防和减少突发事件的发生,控制、减轻和消除突发事件引起的严重社会危害,规范突发事件应对活动,保护人民生命财产安全,维护国家安全、公共安全、环境安全和社会秩序,制定本法。

第二条 突发事件的预防与应急准备、监测与预警、应急处置与救援、事后恢复与重建等应对活动,适用本法。

第三条 本法所称突发事件,是指突然发生,造成或者可能造成严重社会危害,需要采取应急处置措施予以应对的自然灾害、事故灾难、公共卫生事件和社会安全事件。

上一篇:Java开发精英应该了解底层原理
下一篇:什么是系统性能测试方法的简单介绍
相关文章

 发表评论

暂时没有评论,来抢沙发吧~