微服务的设计要涉及到逻辑边界、物理边界和代码边界等。
演进式架构
很多人认为:“将单体拆分成多少个微服务,是微服务的设计重点。”
真的吗?并非如此!
Martin Fowler 在提出微服务时,他提到了微服务的一个重要特征——演进式架构。
那什么是演进式架构呢?
就是以支持增量的、非破坏的变更作为第一原则,同时支持在应用程序结构层面的多维度变化。
如何判断微服务设计是否合理
只需看是否满足这样的情形:
随着业务的发展或需求的变更,在不断重新拆分或者组合成新的微服务的过程中,不会大幅增加软件开发和维护的成本,并且这个架构演进的过程是非常轻松简单。
这也是微服务设计的重点,就是看微服务设计是否能够支持架构长期、轻松的演进。
那用DDD方法设计的微服务,不仅可以通过限界上下文和聚合实现微服务内外的解耦,同时也可以很容易地实现业务功能积木式模块的重组和更新,从而实现架构演进。
微服务 V.S 小单体
有些项目团队在将集中式单体应用拆分为微服务时,首先进行的往往不是建立领域模型,而只是按照业务功能将原来单体应用的一个软件包拆分成多个所谓的“微服务”软件包,而这些“微服务”内的代码仍然是集中式三层架构的模式,“微服务”内的代码高度耦合,逻辑边界不清晰,这里我们暂且称它为“小单体微服务”。
随业务发展,小单体微服务会慢慢膨胀。当有部分业务功能需拆出去或部分功能需与其它微服务重组,你会发现原来这些看似清晰的微服务,不知不觉已经摇身一变,变成了油腻大单体,而这个大单体内的代码依然是高度耦合且边界不清。
这个时候你就需要一遍又一遍地重复着从大单体向单体微服务重构的过程。代价是不是有点高?
其实这个问题已经很明显了,那就是边界。
这种单体式微服务只定义了一个维度的边界,也就是微服务之间的物理边界,本质上还是单体架构模式。微服务设计时要考虑的不仅仅只有这一个边界,别忘了还要定义好微服务内的逻辑边界和代码边界,这样才能得到你想要的结果。
一定要避免将微服务设计为小单体微服务,那具体该如何避免?
微服务边界的作用
你应该还记得DDD设计方法里的限界上下文和聚合吧?它们就是用来定义领域模型和微服务边界的。
事件风暴中会梳理出业务过程中的用户操作、事件以及外部依赖关系等,根据这些要素梳理出实体等领域对象。根据实体对象之间的业务关联性,将业务紧密相关的多个实体进行组合形成聚合,聚合之间是第一层边界。根据业务及语义边界等因素将一个或者多个聚合划定在一个限界上下文内,形成领域模型,限界上下文之间的边界是第二层边界。
为方便理解,将这些边界分为:逻辑边界、物理边界和代码边界。
逻辑边界主要定义同一业务领域或应用内紧密关联的对象所组成的不同聚类的组合之间的边界。事件风暴对不同实体对象进行关联和聚类分析后,会产生多个聚合和限界上下文,它们一起组成这个领域的领域模型。微服务内聚合之间的边界就是逻辑边界。一般来说微服务会有一个以上的聚合,在开发过程中不同聚合的代码隔离在不同的聚合代码目录中。
逻辑边界在微服务设计和架构演进中具有非常重要的意义!
微服务的架构演进并不是随心所欲的,需要遵循逻辑边界。微服务架构演进时,在业务端以聚合为单位进行业务能力的重组,在微服务端以聚合的代码目录为单位进行微服务代码的重组。
由于按照DDD方法设计的微服务逻辑边界清晰,业务高内聚,聚合之间代码松耦合,因此在领域模型和微服务代码重构时,我们就不需要花费太多的时间和精力了。