《微服务设计》第三篇 :如何建模服务

现在你已经知道什么是微服务了,希望你对它的主要优点也有所理解。你可能已经迫不及待地想要实现它了,对吗?但是从何做起呢?在本章中,我们会讨论如何确定服务之间的边界,以期最大化微服务的好处,避开它的劣势。

1.什么样的服务是好服务

专注在两个重要的概念上:松耦合和高内聚。

这两个概念在不同的上下文中被大量使用,尤其是在面向对象编程中,所以,我们先讨论一下这两个概念在微服务中是什么含义。

1.1松耦合

如果做到了服务之间的松耦合,那么修改一个服务就不需要修改另一个服务。使用微服务最重要的一点是,能够独立修改及部署单个服务而不需要修改系统的其他部分,这真的非常重要。

什么会导致紧耦合呢?一个典型的错误是,使用紧耦合的方式做服务之间的集成,从而使得一个服务的修改会致使其消费者的修改。

一个松耦合的服务应该尽可能少地知道与之协作的那些服务的信息。这也意味着,应该限制两个服务之间不同调用形式的数量,因为除了潜在的性能问题之外,过度的通信可能会导致紧耦合。

1.2高内聚

我们希望把相关的行为聚集在一起,把不相关的行为放在别处。为什么呢?因为如果你要改变某个行为的话,最好能够只在一个地方进行修改,然后就可以尽快地发布。如果需要在很多不同的地方做这些修改,那么可能就需要同时发布多个微服务才能交付这个功能。在多个不同的地方进行修改会很慢,同时部署多个服务风险也很高,这两者都是我们想要避免的。

所以,找到问题域的边界就可以确保相关的行为能放在同一个地方,并且它们会和其他边界以尽量松耦合的形式进行通信。

2.限界上下文

Eric Evans 的《领域驱动设计》一书主要专注如何对现实世界的领域进行建模。该书中有很多非常棒的想法,比如通用语言、仓储、抽象等。其中 Evans 引入的一个很重要的概念是限界上下文(bounded context),刚听到这个概念的时候,我深受启发。他认为任何一个给定的领域都包含多个限界上下文,每个限界上下文中的东西(Eric 更常使用模型这个词,应该比“东西”好得多)分成两部分,一部分不需要与外部通信,另一部分则需要。每个上下文都有明确的接口,该接口决定了它会暴露哪些模型给其他的上下文。

另一个我比较喜欢的限界上下文的定义是:“一个由显式边界限定的特定职责。”(http://blog.sapiensworks.com/post/2012/04/17/DDD-The-Bounded-Context-Explained.aspx)如果你想要从一个限界上下文中获取信息,或者向其发起请求,需要使用模型和它的显式边界进行通信。在这本书中,Evans 使用细胞作为比喻:“细胞之所以会存在,是因为细胞膜定义了什么在细胞内,什么在细胞外,并且确定了什么物质可以通过细胞膜。”

2.1共享的隐藏模型

财务部门和仓库就可以是两个独立的限界上下文。它们都有明确的对外接口(在存货报告、工资单等方面),也都有着只需要自己知道的一些细节(铲车、计算器)。

WechatIMG191.jpeg

有时候,同一个名字在不同的上下文中有着完全不同的含义。比如,退货表示的是客户退回的一些东西。在客户的上下文中,退货意味着打印运送标签、寄送包裹,然后等待退款。在仓库的上下文中,退货表示的是一个即将到来的包裹,而且这个包裹会重新入库。退货这个概念会与将要执行的任务相关,比如我们可能会发起一个重新入库的请求。这个退货的共享模型会在多个不同的进程中使用,并且在每个限界上下文中都会存在相应的实体,不过,这些实体仅仅是在每个上下文的内部表示而已。

2.2模块和服务

明白应该共享特定的模型,而不应该共享内部表示这个道理之后,就可以避免潜在的紧耦合(即我们不希望成为的样子)风险。我们还识别出了领域内的一些边界,边界内部是相关性比较高的业务功能,从而得到高内聚。这些限界上下文可以很好地形成组合边界。

就像在第 1 章中讨论过的,在同一个进程内使用模块来减少彼此之间的耦合也是一种选择。刚开始开发一个代码库的时候,这可能是比较好的办法。所以一旦你发现了领域内部的限界上下文,一定要使用模块对其进行建模,同时使用共享和隐藏模型。

所以,如果服务边界和领域的限界上下文能保持一致,并且微服务可以很好地表示这些限界上下文的话,那么恭喜你,你跨出了走向高内聚低耦合的微服务架构的第一步。

2.3过早划分

过早地划分带来的问题:例如一个服务没有划分好,后期导致了很多跨服务的修改,而这些修改的代价相当高。团队逐渐又把这些服务合并成了一个单块系统,从而给所有人时间去理解服务边界到底应该在哪。一年之后,团队识别出了出非常稳定的边界,并据此将这个单块系统拆分成多个微服务。当然这并不是我见过的唯一一个过早划分的例子。过早将一个系统划分成为微服务的代价非常高,尤其是在面对新领域时。很多时候,将一个已有的代码库划分成微服务,要比从头开始构建微服务简单得多。

3.业务功能

当你在思考组织内的限界上下文时,不应该从共享数据的角度来考虑,而应该从这些上下文能够提供的功能来考虑。比如,仓库的一个功能是提供当前的库存清单,财务上下文能够提供月末账目或者为一个新招的员工创建工资单。为了实现这些功能,可能需要交换存储信息的模型,但是我见过太多只考虑模型从而导致贫血的、基于 CRUD(create,read, update,delete)的服务。所以首先要问自己“这个上下文是做什么用的”,然后再考虑“它需要什么样的数据”。

建模服务时,应该将这些功能作为关键操作提供给其协作者(其他服务)。

4.逐步划分上下文

一开始你会识别出一些粗粒度的限界上下文,而这些限界上下文可能又包含一些嵌套的限界上下文。举个例子,你可以把仓库分解成为不同的部分:订单处理、库存管理、货物接受等。当考虑微服务的边界时,首先考虑比较大的、粗粒度的那些上下文,然后当发现合适的缝隙后,再进一步划分出那些嵌套的上下文。

5.关于业务概念的沟通

修改系统的目的是为了满足业务需求。我们会修改面向客户的功能。如果把系统分解成为限界上下文来表示领域的话,那么对于某个功能所要做的修改,就更倾向于局限在一个单独的微服务边界之内。这样就减小了修改的范围,并能够更快地进行部署。

微服务之间如何就同一个业务概念进行通信,也是一件很重要的事情。基于业务领域的软件建模不应该止于限界上下文的概念。在组织内部共享的那些相同的术语和想法,也应该被反映到服务的接口上。以跟组织内通信相同的方式,来思考微服务之间的通信形式是非常有用的。事实上,通信形式在整个组织范围内都非常重要。

6.技术边界

按照技术边界对服务边界进行建模会形成洋葱架构,因为它有很多层。但是也并不总是错误的。比如,当一个组织想要达到某个性能目标时,这种划分方式反而更合理。然而一般来讲,这不应该成为你考虑的首要方式。

7.总结

在这篇中,你学到了什么是好的服务,以及如何在问题空间中寻找能达到高内聚低耦合的接缝。限界上下文是寻找这些接缝的一个非常重要的工具,通过将微服务与这些边界相匹配,可以保证最终的系统能够得到微服务提供的所有好处。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

会飞的架狗师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值