关于阿里云:如何设计一个复杂的业务系统从对领域设计云原生微服务中台的理解开始

2次阅读

共计 8088 个字符,预计需要花费 21 分钟才能阅读完成。

作者:焦方飞

大年初一,看完中国队 1:3 越南队的较量,在思考中国足球江河日下的深层次起因之外,不禁回想起这几年做过的一些大型企业数字化转型我的项目,有得有失,最终回归到根源“如何设计和施行一个简单软件工程”这个问题上,趁着春节长假,把本人的一些对架构设计思考和学习随笔写下来,写的仓促,心愿能引起大家一些启发和探讨。当然本文所说的软件开发次要业务应用软件的开发,而中间件、数据库等技术组件开发的关注点则在其余一些方面,不在这里开展。

如何解决简单业务设计

软件架构设计自身就是一个简单的事件,但其实业界已有一个共识,那就是“通过组件化实现关注点的拆散从而升高部分复杂度”。其实当初咱们用的无论是容器、中间件、音讯、数据库等,在某种意义上都是组件化的产物。这样的益处是在不同的零碎里能够复用。在云原生衰亡的明天,以通用的、组件化的服务模式更容易为咱们所用,所以说当初如果还不享受云原生技术红利,那你就会被时代摈弃。

云原生满足非功能性品质需要

云原生在技术上可能最大水平的解决泛滥非功能性品质和技术需要(如上图),那作为一个企业级利用架构,天然会把专一点转移到业务利用功能性设计自身上来。当初来说对于一个简单业务架构进行设计,咱们要想做到又快又好,无非是两种状况:一是架构师自身对业务了解很深、能力超强、炉火纯青;二是原有的业务零碎自身模型清晰,足够的“高内聚低耦合”,能够疾速在其根底之上剖析业务变动造成新的业务架构设计。咱们应该谋求的是第二种状况,这也就意味着从一开始的企业级模型建设,就要对模型设计、业务流程认真看待,只有做到根底扎实,能力有前面的“疾速迭代”。

咱们再回到架构设计的实质,即为什么咱们要在代码实现前做设计。设计首先是要解决问题的复杂度。于是有人做了一个架构,交给了一个团队去实现,很快发现实现的架构和设计齐全是两回事。当然起因很明确——短少了交换和沟通;其次是要建设团队合作沟通的共识。即便咱们做好了一个团队都达成共识的架构设计,大家都脚踏实地把设计变成了事实,一个长期困扰软件行业的问题呈现了,需要总是在变动,无论事后设计如何“准确”,总是发现下一个坑就在不远处,后果往往是状况越来越蹩脚,也就是咱们常说的架构“腐化”了,最初大家不得不承受重写。这些经验让咱们逐渐明确了软件架构设计的本质是通过外围问题的拆散升高复杂度,并让零碎可能更快地响应外界业务的变动,并且使得零碎可能继续演进。在遇到变动时不须要从头开始,保障实现老本失去无效管制。

所以,我感觉从架构设计角度,以下三点是最为要害的:

  • 让咱们的模型、组件和业务划分尽量凑近变动的实质,比方对于个别电商零碎来说,就是用户、商品、交易、领取等,这样的划分可能让咱们将变动“隔离”在肯定的范畴 (业务模块) 内,从而帮忙咱们无效缩小扭转点。
  • 设计上,业务模型外部是高内聚,模型之间是低耦合,即各自实现的业务是绝对独立的,不会因为一方掉线而株连另外一方,比方商品举荐性能挂掉了,然而交易和领取业务应该持续失常提供服务,可能提醒用户临时无奈提供举荐服务,或者罗唆降级为兜底策略。
  • 模型、组件在业务上尽可能是复用的,正是这样的复用才成就了明天的互联网级架构,咱们不会每做一个电商零碎都从零做起。而被“复用”最多的业务模块显然会重点设计和经营,成为外围业务模块。当然架构上这样的电商零碎必然也会比拟强壮。

下面的三点毫无疑问都指向了业务,从业务登程、面向业务变动是咱们古代架构设计胜利的要害,所以说简单业务架构设计的外围本质是保障面对业务变动时咱们可能有足够快的响应能力。

畛域设计

后面说了业务软件开发的常见病:从一个小的我的项目一直开发演变变成一个大型业务零碎,但随着新需要的一直减少,最终演变成了开发团队的噩梦。而这些噩梦大部分是源于软件的概念完整性(“概念完整性”一词来源于软件工程的经典著作《人月神话》)受到了毁坏。这些业务代码可能是一代又一代的开发人员各行其道的重叠起来的(咱们又称之为“屎山”),而这个过程中没人无意识的去保护软件的概念完整性。而 DDD 畛域设计,特地是 DDD 提供的策略建模层面的概念,是保护软件概念完整性的良药。

“技术服务于业务、业务驱动技术”是目前大部分人的共识,尤其是对商业公司而言。而 DDD 畛域设计主张在软件设计中把业务畛域自身作为关注的焦点(换句话说就是软件开发人员要懂业务)十分合乎这种思维;并且,DDD 提供了切实可行的面对简单业务软件设计的解决办法,这也是我十分提倡作为一个架构师去深刻学习和探讨 DDD 畛域设计的相干常识。

策略建模

在策略层面,DDD 十分强调对业务问题的剖析和合成,通过辨认外围问题来升高问题的复杂度。DDD 在策略层面保护模型的概念完整性的办法,最重要的两个概念就是界线上下文(Bounded Context)和防腐层(Anti-Corruption Layer)。

  • 定义好界线上下文

对于界线上下文的定义,轻易一本讲 DDD 的书上都会具体解说,这里我只想分享一下本人的一些了解。这时,有人会问:界线上下文多大能力适合呢,划分上下文有没有能够遵循的规定呢?

划分上下文的规定,无非就是放之四海而皆准的“高内聚、低耦合”,这么说可能还是太虚。其实真正让大家感到纠结的是,不知如何切分的那些货色之间所存在的关联,有的甚至罗唆都纳入到一个上下文里。其实,我认为与其关注上下文的“大小”,不如关注模型的“品质”,关注概念的完整性是不是容易被毁坏。我感觉,判断大小是不是适合,要联合利用开发团队的能力,看开发团队能在多大的一个范畴内掌控软件的概念完整性。只有是开发团队没有问题,这个范畴就算再大也都是能够的。

如果开发团队的程度在业界属于上游,那么保护上下文的范畴往往是很大的;一些公司开发团队的程度参差不齐,所以在我的项目的施行过程中,可能须要划分绝对小的上下文,尽可能减少“屎山”的一直沉积。

  • 做好防腐层

界线上下文须要时刻爱护好本人所保护的边界,以及边界内概念的完整性,这时须要将某个上下文的概念转化为另一个上下文概念的中央就叫做“防腐层”。防腐层的实现有很多种,典型的比方作为适配器 Adaptor 来实现,另外狭义上讲,Gateway 也是一个典型性的防腐层组件,当然,防腐层的代码和其余外部业务模型之间要存在显著的物理边界(当然不肯定说要把防腐层作为一个个独立部署的过程),至多咱们能够思考把防腐层作为一个独立的类库来进行构建和保护,阿里外部的比方星环、其实就是这个思路。

一个典型的防腐层的设计

战术建模

DDD 在战术上最外围的概念就是实体和聚合,为了更好的了解什么是聚合、聚合根、聚合外部实体,上面举例说明一下。设想一下一个电商零碎的订单相干的模型,咱们可能会失去订单 Order、订单头 OrderHeader、订单行项 OrderItem 三个互相关联的概念:

  • 一个叫做 Order 的聚合。
  • 这个订单聚合的聚合根是一个叫做 OrderHeader 的实体,实体 OrderHeader 的 ID 叫做 OrderId(订单号)。
  • 通过 OrderHeader 实体,咱们能够拜访 OrderItem 实体的一个聚合。OrderItem 这个实体的部分 ID 叫做 ProductId(产品 ID)。因为业务善变不容许在同一个订单的不同订单项内呈现同一个产品,所以咱们能够抉择产品 ID 作为订单项的部分 ID。

“聚合是数据批改的单元”,基于这个准则,咱们能够做到“聚合内强统一、聚合外最终统一”,比方,咱们能够不能承受一个订单内的所有订单项的金额之和不等于订单头的总金额,咱们就必须把订单头和订单行项这两个实体划分到同一个聚合内。

  • 设计聚合的准则

咱们无妨先看一下《实现畛域驱动设计》一书中对聚合设计准则的形容,原文是有点不太好了解的,我来略微解释一下:

  1. 在一致性边界内建模真正的不变条件。聚合用来封装真正的不变性,而不是简略地将对象组合在一起。聚合内有一套不变的业务规定,各实体和值对象依照对立的业务规定运行,实现对象数据的一致性,边界之外的任何货色都与该聚合无关,这就是聚合能实现业务高内聚的起因。
  2. 尽量设计小的聚合。如果聚合设计得过大,聚合会因为蕴含过多的实体,导致实体之间的治理过于简单,高频操作时会呈现并发抵触或者数据库锁,最终导致系统可用性变差。而小聚合设计则能够升高因为业务过大导致聚合重构的可能性,让畛域模型更能适应业务的变动。
  3. 通过惟一标识援用其它聚合。聚合之间是通过关联内部聚合根 ID 的形式援用,而不是间接对象援用的形式。内部聚合的对象放在聚合边界内治理,容易导致聚合的边界不清晰,也会减少聚合之间的耦合度。
  4. 在边界之外应用最终一致性。聚合内数据强一致性,而聚合之间数据最终一致性。在一次事务中,最多只能更改一个聚合的状态。如果一次业务操作波及多个聚合状态的更改,应采纳畛域事件的形式异步批改相干的聚合,实现聚合之间的解耦(相干内容我会在畛域事件局部详解)。
  5. 通过应用层实现跨聚合的服务调用。为实现微服务内聚合之间的解耦,以及将来以聚合为单位的微服务组合和拆分,应防止跨聚合的畛域服务调用和跨聚合的数据库表关联。

下面的这些准则是 DDD 的一些通用的设计准则,还是那句话:“适宜本人的才是最好的。”在零碎设计过程时,你肯定要思考我的项目的具体情况,如果面临应用的便利性、高性能要求、技术能力缺失和全局事务管理等影响因素,这些准则也并不是不能冲破的,总之所有以解决理论问题为出发点。

  • 设计聚合的步骤

DDD 领域建模通常采纳相似事件风暴,个别通过用例剖析、场景剖析和用户旅程剖析等办法,通过头脑风暴列出所有可能的业务行为和事件,而后找出产生这些行为的畛域对象,并梳理畛域对象之间的关系,找出聚合根,找出与聚合根业务严密关联的实体和值对象,再将聚合根、实体和值对象组合,构建聚合。

电商零碎大家都比拟相熟了,而且对于电商业务来说有许多比拟成熟的模型能够间接借鉴;那上面咱们以另外一个场景 - 保险投保业务为例,看一下聚合的构建过程次要都包含哪些步骤,当然这个例子我是从其余的学习材料里看到的,比拟典型,能够当作示例来进行阐明:

保险投保业务简略示例(From 学习材料)

  • 第一步:采纳用例剖析或事件风暴等办法,依据业务行为,梳理出在过程中产生这些行为的所有的实体和值对象,比方投保单、标的、客户、被保人等等。
  • 第二步:从泛滥实体中选出适宜作为对象管理者的根实体,也就是聚合根。判断一个实体是否是聚合根,上一章也说过,你能够联合以下场景剖析:是否有独立的生命周期?是否有全局惟一 ID?是否能够创立或批改其它对象?是否有专门的模块来管这个实体。图中的聚合根别离是投保单和客户实体。
  • 第三步:依据上一章说的设计聚合的准则,找出与聚合根关联的所有严密依赖的实体和值对象。构建出一个蕴含一个聚合根、多个实体和值对象的对象汇合,这个汇合就是聚合。在图中咱们构建了客户和投保这两个聚合。
  • 第四步:在聚合内依据聚合根、实体和值对象的依赖关系,画出对象的援用和依赖模型。这里须要阐明一下:投保人和被保人的数据,是通过关联客户 ID 从客户聚合中获取的,在投保聚合里它们是投保单的值对象,这些值对象的数据是客户的冗余数据,即便将来客户聚合的数据产生了变更,也不会影响投保单的值对象数据。从图中咱们还能够看出实体之间的援用关系,比方在投保聚合里投保单聚合根援用了报价单实体,报价单实体则援用了报价规定子实体。
  • 第五步:多个聚合依据业务语义和上下文一起划分到同一个限界上下文内。

那以上就是一个聚合诞生的残缺过程了。

不同场景下的领域建模策略

因为企业内状况千差万别,倒退历程也不一样,有遗留单体零碎的微服务革新,也有全新未知领域的业务建模和零碎设计,还有遗留零碎局部优化的状况。不同场景下,领域建模的策略也会有差别。上面咱们就分几类场景来看看如何进行领域建模。

新建零碎

新建零碎对于简单的业务畛域,畛域可能须要多级拆分后能力开始领域建模。畛域拆分为子域,甚至子域还须要进一步拆分。比方:保险它须要拆分为承保、理赔、收付费和再保等子域,承保子域再拆分为投保、保单治理等子子域。简单畛域如果不做进一步细分,因为问题域太大,领域建模的工程量会十分盛大。你不太容易通过事件风暴,实现一个很大的领域建模,即便勉强实现,成果也不肯定好。

对于简单畛域,咱们能够分三步来实现领域建模和微服务设计。

  • 拆分子域建设畛域模型,依据业务畛域的特点,参考流程节点边界或性能聚合模块等边界因素。联合领域专家和我的项目团队的探讨,将畛域逐级分解为大小适合的子域,针对子域采纳事件风暴,划分聚合和限界上下文,初步确定子域内的畛域模型。
  • 畛域模型微调梳理畛域内所有子域的畛域模型,对各子域畛域模型进行微调。微调的过程重点思考不同畛域模型中聚合的重组。同步思考畛域模型和聚合的边界,服务以及事件之间的依赖关系,确定最终的畛域模型。
  • 微服务的设计和拆分依据畛域模型和微服务拆分准则,实现微服务的拆分和设计。

单体遗留零碎

如果咱们面对的是一个单体遗留零碎,只须要将局部性能独立为微服务,而其余仍为单体,整体放弃不变,比方将面临性能瓶颈的模块拆分为微服务。咱们只须要将这一特定性能,了解为一个简略子畛域,参考简略领域建模的形式就能够了。在微服务设计中,咱们还要思考新老零碎之间服务和业务的兼容,必要时可引入防腐层。

云原生时代下的挑战

随着云原生技术的衰亡,当初企业级架构就更加的云化,而云化的架构格调有了新的关注点:弹性边界。弹性边界是一个云原生企业级利用架构的外围概念,它指把弹性作为最优先的思考因素而划定的零碎边界,决定了咱们是否可能充分发挥云原生平台的全副能力。于是咱们就须要新的办法来补救以前业务模型的有余,以满足新的云原生化的须要。当初能够说,微服务基本上就是以云原生架构作为根底,而在固定弹性的平台上应用微服务架构,有极高的施行老本。能够说,云原生实际上就应该是微服务的前置条件。

在云原生时代,咱们须要将弹性作为首要思考的因素,纳入建模的考量。那么弹性边界,就是咱们划分零碎的重要依据。而且,咱们还须要思考弹性边界间的依赖关系,尽量避免弹性耦合。对于业务建模来说,为了配合云原生时代的架构,我感觉要做到如下几点:

  • 确立一种模型构造可能反映弹性边界,而这时候须要思考不同弹性边界的准则来划分界线上下文;如果两个上下文显著具备不同的弹性诉求,那就应该拆分。而如果具备统一的弹性诉求,能够思考先不拆。那这个时候拆分微服务到底能多“微”呢?简略说就是“微”到可能更好的利用弹性来管制老本的大小。
  • 从异步模型的视角,去优化业务逻辑;典型就是 MQ 音讯队列零碎,因为有 broker,所以生产者和消费者不用在同一时间都放弃可用性以及雷同的吞吐量,而且生产者也不须要马上等到回复。
  • 地位的松耦合:典型就是服务注册核心,生产端齐全不须要间接晓得提供端的具体位置,而都通过注册核心来查找服务来拜访。
  • 在弹性边界切分业务上下文时,同一个弹性边界外部保护业务强一致性。
  • 在异步调用产生两头态异样时,须要保护业务最终一致性。

不要漠视组织构造的影响

“康威定律”通知咱们,组织构造会决定团队沟通的构造,也会决定产品的构造。对组织构造的梳理,在需要调研的时候会常常做。如果是信息收集而言,业务架构设计在这里并没有什么非凡之处。区别在于,业务架构的指标是企业级的能力布局,心愿可能冲破壁垒、造成合力。正是这个起因,组织构造对业务架构设计的反作用力也是很大的,企业级数字化转型计划要与组织构造相匹配,否则落地的时候会困难重重。能够说,部门利益是做企业级架构的最大阻碍之一,逾越这个阻碍也是对架构师的能力的要求之一。当然,有些状况下,没有更好的解决方案时,不动也是一种抉择。

以我的教训,这种问题没有特地好的方法,无非是两种:一是有超强能力者主导,在最高层的反对下,强力推动这种决策,然而企业越大,尤其是以业务为主导地位的企业中,这种构造就愈难造成;二是增强企业外部的业务架构人员的能力和数量(最好各个部门都有相似的角色),让这些企业机构人员以合作伙伴的形式全程参加到我的项目中,在我的项目的施行过程中搭建起合作网络,晋升决策效率,能力使组织构造不再是企业数字化转型的瓶颈。

SOA- 微服务 - 中台:斗争的艺术

多年前,这些传统的大型 ERP 业务软件,其实都是在一个很大的范畴内保护业务概念的完整性。一个 ERP 装置结束后,数据库有七八百张表(也就是七八百个实体)处于同一个界线上下文之内。然而这些 ERP 在这样一个微小的界线上下文内依然很好的保护了业务概念的完整性,切实令人钦佩。

然而实现它十分艰难,然而毁坏它却非常容易。一套 ERP 定制我的项目施行下来,数据库里可能又多了几百张表,更不用说不标准的命名看起来千奇百怪。这些厂商的 ERP 施行参谋和开发人员,披星戴月的保护这个宏大的“屎山”。咱们不能让这些宏大的“单体利用”无限度的增长,于是咱们又一次祭起了“分而治之”的大旗。想 SOA 这样的软件组件化技术给咱们提供了拆分的工具。咱们把一个大的界线上下文依照利于拆分成几个相对来说小一些的界线上下文;在物理上,咱们把一个大的单体利用拆分成若干服务。

一般来说,咱们会让服务的物理边界和界线上下文的畛域边界根本堆砌,一个界线上下文对一个或多个能够独立部署的服务利用,服务利用蕴含了界线上下文的外围业务逻辑的实现。SOA 的服务组件的物理边界给服务间的调用减少了一些艰难,这就使得开发人员简化对象之间的关系,编写更加“高内聚、低耦合”的代码。当服务组件不多的时候,构建防腐层的工作量也不会很大,咱们只有解决好组件之间的代码即成就好了。

然而,咱们的架构师和开发人员太喜爱“分而治之”了,微服务的宽泛应用甚至说是滥用,让咱们看很多微服务真的是很“微”,简直是一个 DDD 的聚合就能够对应一个能够独立部署的微服务。这样的微服务单单靠自身做不了太多的业务,这就须要更多更多的微服务“聚合”起来一起能力对外提供业务服务。

当然,微服务技术基础设施的倒退也为服务之间的调用提供了更多的便当,逾越微服务的边界成为了常态;这个时候,业务开发人员辨别“同一个上下文内的服务调用”和“上下文之间的防腐层”就要时刻放弃头脑清醒,这时候的界线上下文和微服务的物理边界往往很难对齐,这就必然减少了保护每个界线上下文概念完整性的难度。

既然保护一个个“渺小”的独立的界线上下文概念完整性越来愈难,那么咱们罗唆将它们再聚合起来吧?将它们交融到一个大小适度的界线上下文,那这就是所谓的企业级业务架构,也就是咱们当初说的业务中台,最终目标能够说想要取得“企业级”的大谐和。

所以在肯定水平上讲,软件工程就是斗争的艺术,是“中庸之道”。咱们要不要中台,要大的中台,不论企业的大小,都应该联合本身的业务指标以及领有的资源,在“保护更大范畴的概念完整性”和“保护更多的防腐层代码”之间做出均衡,那这也是一个企业级架构师所要做的最外围的事件之一。

咱们团队这些年的确做了一些“业务中台方法论”的积攒和实际,并且在一些我的项目中做了实际,当然其中最灵魂的局部之一还是后面说的畛域设计。以前很多人说 DDD 畛域设计乃至业务中台方法论最难的就是没有一个适合的工具或者平台来实际,明天其实阿里开源的 COLA 以及外部应用的星环、BizWorks 都是很好的工具和平台。

结语

企业级利用架构是在一直的演进和迭代,然而我始终感觉企业应用架构的造成过程是在一种看起来迷信的方法论下,然而又不齐全迷信的过程中实现的。认真想一下,做软件架构的其实很艳羡做修建架构的,因为修建架构有谨严的力学根底作为基座,有很多能够准确计算的货色,而软件架构却没有多少能够准确计算出来的成分,所以,后面说的“一直的斗争”不失是一种可行的设计思路和设计艺术;其实这也应验了那句“没有银弹”。

因为工夫仓促,有些内容简略带过,有些本应该联合实例来阐明的中央在本文中也简略而过,前面有工夫的话我会联合更多的理论案例来对本文说的观点进行补充。也心愿本文可能激发大家一起对目前云原生时代的企业级利用架构设计的思考和探讨,互相学习,共同进步。

正文完
 0