三、微服务拆分

3.1优秀的微服务

好的微服务,有两个最重要的概念:高内聚与低耦合。


其实不只有微服务,软件设计的追求也在此,对于这个概念,相信在学习开发的初始阶段就会听说,但并不是所有人听说后就会理解,我们在研发经验逐步累积到一定程度后,就会真正想清楚这两个概念背后的含义。

3.2高内聚

把相关的行为聚集到一起,把不相关的行为放在别处。这个说法与SRP很像,因为如果你想要改变某个行为的话,最好能够只在一个地方进行修改,然后就可以尽快发布。


好的微服务要基于这一点,将相关的业务集中到一个微服务中实现。要做到准确内聚,就要找到需求边界,而这个边界有可能是慢慢摸索出来的。

3.3低耦合

如果你的微服务做到了低耦合,那么修改一个服务就不需要修改另一个服务。


那么什么会导致高耦合呢?一个典型的错误是,在做服务之间的集成时,修改一个服务会导致其消费者也进行修改。一个号的服务应该尽可能少的知道与之协作的那些服务的信息,应该尽量限制服务之间不同形式的调用,过度通信会导致高耦合。这个说法与Law of Demeter很像,其实,设计六大原则就是将高内聚低耦合完整的抽象出来了。

3.4共享模型与隐藏模型

任何一个特性的行业业务,都包含着多个上下文边界,所谓的上下文边界,就是各个业务模块之间的交互点,在程序中就是模块的接口。 


一个业务模块,正常来说有两部分模型(实体)组成,一部分不需要与外部通信,另一部分则需要。
让我们来看一个具体的例子:


 
图中,财务与仓库两个模块是两个独立的界限上下文,他们都有明确的对外接口(存货报告、工资单),也有只需要自己知道的细节(铲车、计算器)。


财务模块不需要知道仓库模块的内部细节,但它需要知道库存水平,以便于更新账户,为了算出公司的估值,需要知道库存信息。


在平常,设计者会将库存信息作为对外接口的模型,将其变成模块间的共享模型,这种做法其实是不太可取的,不要盲目的把库存信息内容全部都暴露出去。仓库模块应该设计暴露给财务模块的库存信息(库存项),有时候,同一个名字在不同的上下文中有着完全不同的含义。


总结起来就是,应该共享特定的模型,而不应该共享内部模型。


做到上述事情,可以大量避免高耦合,而且在明确了各个边界,可以实现高内聚。所以,一旦你发现了业务模块的边界和模型,一旦要对其进行建模,同时使用共享模型和内部模型。


对于一个新系统或新业务领域来说,可以先使用一段时间单体架构,因为如果服务之间的边界搞错了,会付出很大的代价,所以最好能够等到系统稳定下来、熟悉业务后,在对单体架构进行微服务的拆分。


当你在思考业务边界时,不应该从共享数据的角度来考虑,而应该从这些业务边界能够提供的功能来考虑。比如,仓库的一个功能是提供当前的库存清单,财务能够提供月末账目或者为一个员工创建工资单。为了实现这些功能,可能需要交换存储信息的模型。如果只考虑模型,你有可能只设计出一个贫血服务(只基于CRUD的服务)。

3.5拆分的建议

新项目开始阶段,你会识别出一些粗颗粒度的业务边界,而这些业务中可能会包含另一些业务。比如,可以把库存模块分解为不同的子模块:订单模块,库存管理模块,货物接收等。


在被外部服务调用时,这些嵌套的子模块对外部是不可见的。例如:


 
但有时候你会认为,高层次的业务模块不应该被显示地建模成一个服务,应该把子模块拆分出来:
 
通常很难说那种规则更合理,但是应该根据组织结构来决定,如果订单、库存等由不同的团队或者个人维护,那么他们大概都会希望这些服务是顶层服务。单如果他们由一个团队或个人来维护,那么使用嵌套结构会更合理。


另一种倾向于嵌套方法的原因是,它可以使得架构更方便的测试,当测试仓库的消费者时,不需要对仓库中的每个服务进行打桩,只专注于粗粒度的API测试即可。


基于行业业务的软件建模不应该止步于业务边界的拆分,在组织内部共享的那么相同的术语和想法,也应该被反映到服务的接口上。沟通、通信形式在整个组织范围内都非常重要。

3.6小结

总结了什么是好的服务,以及如何做到高内聚与低耦合。


并且聊到了在进行微服务的拆分时,应该先基于业务功能去拆分,这样自然而然会得出一个正确的共享模型,而后,对服务的拆分颗粒度进行了建议。


若想进一步了解如何准确的拆分业务功能,可以读一读Eric Evans的《领域驱动设计》一书。
 

猜你喜欢

转载自my.oschina.net/u/2450666/blog/1817728