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

news/2024/4/30 12:06:46/文章来源:https://blog.csdn.net/toafu/article/details/126619592

在软件开发领域,解耦这个词相信大家都不陌生。在面向对象的语境下,我们会应用SOLID原则来构建高内聚低耦合的应用,实现模块间的解耦;在复杂业务系统分析和建模时,会通过DDD的战略和战术设计帮助划分领域并实现分布式系统中服务的解耦;当我们在组织大型敏捷开发团队协同工作时,通过组建自治团队来减少摩擦,从而实现团队级别的解耦。

可以看到解耦无处不在,并且以此为目的投入,大家都会觉得是无比的政治正确,因为实现了解耦,我们的系统和应用就能更快速的扩展和演进,我们的团队就能更顺畅的合作并能更加快速的实现业务价值。

但是,当我们暂时抛开将得到的种种好处,思考要如何去实现它时,却发现解耦这个词表达的意义过于抽象和模糊,它既没有描述最终的状态也没有提供实现的方法。那当我们谈解耦的时候,具体内容是什么呢?

从字面上理解的所谓耦合,通常是指两个或两个以上的物体或者体系之间相互作用彼此影响,对应到软件研发的以上场景,我们可以转换成是指两个或两个以上的模块/系统/团队之间相互作用彼此影响

在软件需要解决的业务问题越来复杂的今天,单个的系统或者团队很难在不依赖外部的情况下去实现业务目标,所以我理解的解耦并不是要消除耦合(彼此的作用和影响/依赖),而是指我们应该如何通过一定的方式和规则,来设计和管理以上提到的多个元素之间的依赖,降低耦合程度来使整个系统有序顺畅的运转。

本文将从服务间上下游的思维来讨论如何在系统架构演进过程中,持续的保持服务间的松耦合,实现解耦的目标。

上下游思维定义

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


图片出处:https://www.oreilly.com/library/view/what-is-domain-driven/9781492057802/ch04.html

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

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

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

  • Level4: 领域知识互为上下游,业务可用性互为上下游
  • Level3: 领域知识互为上下游, 业务可用性为单向上下游
  • Level2: 领域知识为单向上下游,业务可用性互为上下游
  • Level1: 领域知识为单向上下游,业务可用性为单向上下游

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

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

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

Level2级别的耦合度是建立在清晰的领域限界上下文边界基础上的,在上面包含的订单服务和派送服务的业务中,派送服务作为上游在完成派送进行订单更新这个业务时,它将派送更新的内容发送至订单服务,订单服务再解析派送更新内容并更新关联的订单状态。那么在通过API的方式进行集成时,它们就处于领域知识的单向上下游和业务可用性互为上下游的状态。具体构建服务时,根据团队的组织结构和话语权的大小,又可以通过不同的方式来进行服务的集成。上游服务通常使用Open Host Service(OHS) / Published Language(PL)来提供业务能力,下游服务通过遵循上游的领域模型或者通过防腐层(Anti Cruption Layer - ACL)来完成领域模型的转换。处于这个级别耦合度的上下游服务在开放主机接口不变的情况下可以独立的进行迭代更新,否则需要通知下游服务评估影响并同步进行变更。

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

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

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

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

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

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

对于处在level2级别的系统,由于系统的上下游关系相对清晰,重点可以放在采用合适的方式来完成上下游系统的集成上以实现。一般上游系统通过OHS/PL在保证发布语言不变化的情况下,可以独立的进行迭代更新;下游系统是通过跟随或者添加防腐层来屏蔽上游业务模型变化带来的影响,取决于业务模型变化的频繁程度和添加新一层的成本。通常在绿地项目中,由于能从零开始进行业务建模和组建开发团队,在统一业务语言和明确上下游团队遵从关系的基础上,采用新的服务构建技术和实践,在上下游服务间同时使用OHS/PL和ACL会比较好的隔离相互之间的影响。上游服务专注于领域能力的迭代并通过OHS/PL来发布功能,下游服务通过ACL来隔离上游变化对自身领域模型的影响,同时也可以按需来使用上游提供的新的功能。

对于处在level1级别的系统,在业务和技术上都具备了松耦合的基础,但是此时需要警惕一种新的依赖产生。由于上游系统在消息格式的设计时没有按照使用场景来设计,或者消息格式不能很好的在向前兼容的情况下进行更新,这带来的后果是上游系统会成为下游新增业务的强依赖,因为任何的新需求可能需要上游系统定义新的消息格式来支持,上游系统会成为响应变化的瓶颈。如果服务在不同的团队中进行维护,那么带来的后果就是团队间的冲突。在这个级别的依赖关系中,合理的消息模式以及兼容性设计是迭代演进的关键。

消息集成通常分为两种风格Event Notification和Event-carried State Transfer,具体又可扩展为以下几种模式:

  1. 消息体包含领域事件发生后领域模型的最新状态和变更内容
  2. 消息体包含领域事件发生后领域模型的最新状态
  3. 消息体包含领域事件发生后领域模型的变更内容
  4. 消息体只包含领域事件发生后领域模型的标识,需要消费者按需通过API来获取相关信息

最后

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


文/Thoughtworks 陈璐
原文链接:如何实现系统解耦-Thoughtworks洞见

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_4215.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java毕业设计-校园活动赞助与宣传管理系统

🔥作者主页:疯狂行者🔥 💖✌java领域优质创作者,专注于Java技术领域技术交流✌💖 💖文末获取源码💖 精彩专栏推荐订阅:在 下方专栏👇🏻👇&#x1…

(分布式缓存)Redis持久化

一、RDB持久化 首先需要在Linux系统中安装一个Redis,如果尚未安装的同学,可以参考下面链接教程安装先: (73条消息) 单机安装Redis_其然乐衣的博客-CSDN博客 修改配置文件 创建一个数据 因为设置了只要5秒内有一次修改就会触发一次备份数据&am…

最全 Burp Suite 最新付费稳定版安装教程

介绍 Burp Suite是web应用程序渗透测试集成平台。从应用程序攻击表面的最初映射和分析,到寻找和利用安全漏洞等过程,所有工具为支持整体测试程序而无缝地在一起工作。 平台中所有工具共享同一robust框架,以便统一处理HTTP请求、持久性、认证、上游代理、日志记录、报警和可扩…

《QDebug 2022年8月》

一、Qt Widgets 问题交流 1.QWidget鼠标事件穿透 对于一些透明或者半透明的QWidget,可能需要点击其下方的按钮或其他组件,但是QWidget本身是会接收这些鼠标事件的,需要一些额外的处理。下面是百度到的一些方法: 方式A.设置setA…

Nacos下载和安装-windows

Nacos官网:https://nacos.io/zh-cn/ Nacos官方文档:https://nacos.io/zh-cn/docs/quick-start.html 一、下载 进入nacos官网,选择相应版本下载 github上nacos的zip资源,下载速度奇慢问题。 百度网盘:https://pan.b…

云原生游戏第 2 讲:OpenKruiseGame 设计理念详解

后疫情时代,游戏行业步入高质量发展期,游戏云原生化势在必行。不久前,针对游戏行业云原生落地的难点、游戏玩家服容器化的困境等问题,阿里云容器服务团队通过直播课程《云原生游戏第1讲:游戏玩家服容器化的困境与解法》…

PMP每日一练 | 考试不迷路-9.1(包含敏捷+多选)

!PMP最新考试通知 ! ​2022年6-8月落考考生可免费重考一次! 11月考试可以报名 ​(9月考试改到11月) 每日5道PMP习题助大家上岸PMP!!! ​1.项目经理接到一个开发新产品的项目,这…

一体式城市内涝监测站

一体式城市内涝监测站 计讯物联一体式城市内涝监测站,智能监测城市重点区域视频监控、水位、雨量、水量、流速等,目标数据实时上报云端,相关部门远程云平台同步监控(视频图像、水雨情、积水、排水工况),智能化管理系统实现城市防…

网课答案公众号题库接口使用详情

网课答案公众号题库接口使用详情 本平台优点: 多题库查题、独立后台、响应速度快、全网平台可查、功能最全! 1.想要给自己的公众号获得查题接口,只需要两步! 2.题库: 查题校园题库:查题校园题库后台&…

ATF启动(四):BL31

1、BL2跳转BL31 在上一页在bl2_main函数中的最后一句是: smc(BL1_SMC_RUN_IMAGE, (unsigned long)next_bl_ep_info, 0, 0, 0, 0, 0, 0); 这个是触发smc操作。这个smc的handle在bl1的阶段就被制定了。 这个handle smc id是BL1_SMC_RUN_IMAGE。对应的handle函数是…

猿创征文|全方位快速了解事务的4种隔离级别

MySQL事务隔离级别事务以及事务的隔离级别1. 概念2. 事务的特性3. 事务的隔离级别3.1 Q:那么为什么事务需要有隔离级别呢?3.2 Q:那么什么事务并发会产生的问题?总结:不可重复读的和幻读很容易混淆3.3 Q:事务…

Dubbo - 远程debug

由于Dubbo的特性是远程调用,因此正常来说无法在本地进行debug 因为你调用的方法在别台机器上跑,你只能知道给他的input和他返回的结果,但没办法知道这个接口内部的执行,所以也没办法在裡面打断点进行debug 就算在本地有dubbo代码…

UE4 C++学习 浅析UProperty属性说明符

浅析UE4 UPROPERTY本文就 UProperty是什么?以及UProperty怎么用?做一个简单的总结。 什么是UPROPERTY? 首先看下官方的解释: 感觉还是比较模糊没看懂有什么用,我们接着往下看要知道UPROPERTY有什么用,我们首先要知道反射(Refection)这个机制。这个机制在Java和C#等语言都…

freeswitch的3XX重定向

概述 sip协议标准RFC3261中,对3XX重定向有明确的定义。 freeswitch中如何使用3XX redirect的特性,如何落地,应用场景有哪些?环境 centos:CentOS release 7.0 (Final)或以上版本 freeswitch:v1.8.7 GCC:4.8.53XX重定向 RFC3261中对3XX的响应定义是这样的。 3xx response…

版本4校园兼职软件遇到的问题和解决方法

出现问题: 每次只能保存一位用户信息,后面输入用户信息前面的用户信息会被覆盖 出现原因及解决方法: 因为暂存的temp对象被定义为全局变量,所以每次进去都被刷新为新对象,将其 User temp new User(); 放在方法内即…

【JAVAWEB开发】基于Java+Servlet+Ajax+jsp网上购物系统设计实现

哈喽~大家好呀,这篇给的大家带来的是网上购物系统设计。在传统电商时代,用户是先有需求再购买,用户对平台较为依赖,商家对消费者很难有直接的影响力,而如今社交 电商解决了产品质量的信息不对称问题,电商已…

卷积神经网络卷积层公式,卷积神经网络层数计算

卷积神经网络算法是什么? 一维构筑、二维构筑、全卷积构筑。 卷积神经网络(ConvolutionalNeuralNetworks,CNN)是一类包含卷积计算且具有深度结构的前馈神经网络(FeedforwardNeuralNetworks),是深度学习&a…

【校招VIP】[产品][一本][6分]简历原则上写一页

校招的简历原则上只能写一页,尤其是电子版。因为校招是集中面试,会有太多简历,所有人都只有一页的话,写两页的很容易被漏掉一页关注【校招VIP】公众号,回复【简历】,添加校招顾问微信,即可获取简历指导! 简历背景:21届一本产品 简历评分:6分 一、学员简历 ​​​二、…

安装mkimage工具,解决报错“Invalid CPU Type - valid names are:”

问题 前两天在编译博雅芯片厂商提供的内核时,总是无法编译通过,试了好几次都提示如下错误: Invalid CPU Type - valid names are: alpha, arm, x86, ia64, m68k, microblaze, mips, mips64, nios2, powerpc, ppc, s390, sh, sparc, sparc64…

神经网络架构图讲解教程,神经网络架构图讲解图

什么是全连接神经网络?怎么理解“全连接”? 1、全连接神经网络解析:对n-1层和n层而言,n-1层的任意一个节点,都和第n层所有节点有连接。即第n层的每个节点在进行计算的时候,激活函数的输入是n-1层所有节点的…