SpringCloud微服务开发实战:如何进行微服务的拆分?

如何进行微服务的拆分

在前面介绍了基于Spring Boot来快速实现一个“天气预报”应用。虽然没有使用太多的代码,但已经实现了数据采集、数据缓存、提供天气查询等诸多的功能,这也是Spring Boot是快速实现企业级应用开发的利器的原因。Spring Boot让企业级应用开发变得不再困难!

很显然,这个“天气预报”应用是一个单块架构的应用。它表面看上去很强大(集成了数据采集、数据缓存、提供天气查询等功能),但从另外一个角度看,它缺乏业务上的有效隔离。例如,如果第三方采集的接口协议变更怎么办?缓存服务失效怎么办?其中任何一个问题的发生,都势必会影响整个应用的可用性。

微服务拆分的意义

把所有鸡蛋放在一个篮子里所带来的风险是显而易见的——一损俱损。微服务架构正是通过分而自治的理念来降低服务故障的风险,从而实现服务的可行性。

1.微服务易于实现

更小的服务意味着更少的代码。更小的服务意味着不必考虑太多整体的技术架构或一站式的解决方案。只需要拿上趁手的兵器(开发工具和语言),奋勇开疆即可!

在实现微服务时,配以Spring Boot类开箱即用的工具,可以使自己更加有信心赶超进度。

2.微服务易于维护

更小的服务意味着更少的代码、更少的业务需求,也就容易被开发人员所理解,包括开发者和维护者。对于软件设计来讲,一个非常大的质量指标,就是软件是否可维护。更小、更内聚的微服务更加易于维护。

3.微服务易于部署

微服务往往采用轻量级的技术来实现,如内嵌容器的方式,这样,它更容易将其自身及所依赖的运行环境打成一个包来进行分发,从而避免了不同的部署导致的环境不一致的问题。再配合Docker等容器技术,可以进一步降低部署的复杂性。

4.微服务易于更新

微服务更容易被维护和修改,再加上每个微服务都是独立部署的,这样替换单个服务,并不会影响整体的软件功能。所以,微服务可以拥有对单块架构更加频繁的更新频率。

越频繁地更新,意味着越早将用户的需求反馈给用户﹔用户越早使用产品,越能发现程序的问题,这样就能及早地提出变更需求,从而形成了一个如图6-7所示的正向的反馈闭环。

SpringCloud微服务开发实战:如何进行微服务的拆分?

拆分的原则

拆分微服务—般遵循如下原则。

1.单一职责原则

单一职责原则(Single Responsibility Principle,SRP)又称单一功能原则,是面向对象的五大基本原则(SOLID ) 之一。一个类只能有一个引起它变化的原因,因为它应该只有一个职责。每一个职责都是变化的一个轴线,如果一个类有一个以上的职责,这些职责就耦合在了一起。这会导致脆弱的设计。当一个职责发生变化时,可能会影响其他的职责。另外,多个职责耦合在一起,会影响复用性。

在架构设计中,业界普遍采用的是分层架构。分层的原则之一就是每一层都是专注于自己所处的那一层的业务功能,即遵守单一职责的原则。划分微服务时也要遵循单—职责原则,每个微服务只专注于解决一个业务功能。通过DDD的指导,可以更加清楚地划清不同业务之间的界限。

组织团队也要遵循单一职责原则,这样才能很好地管理团队成员的时间,提高效率。一个人专注做一件事情的效率远高于同时关注多件事情。同样一个人一直管理和维护同一份代码要比多人同时维护多份代码的效率高得多。这样就能充分发挥每一个人的个性,专注于每个人所擅长的事,这样做起事情来就会事半功倍,整个团队效率也会提高。

⒉.高内聚

内聚性又称块内联系,是指模块功能强度的度量,即一个模块内部各个元素彼此结合的紧密程度的一种度量。若一个模块内各元素联系得越紧密,则它的内聚性就越高。

程序员希望把相关的行为都聚集在一起,把不相干的行为放到其他地方。这样,当他们要修改某个行为的时候,只需要在一个地方修改即可,然后就能对该修改及早地进行发布。如果要在很多不同的地方做修改,那么就需要同时发布多个微服务才能交付这个功能。在多个不同的地方进行修改会很慢,同时也引入了很多测试的工作量,而且部署多个服务的风险也更加高。这两者都是开发人员想要避免的。

所以,确定问题域的边界,保证相关的行为能够放置在相同的地方,并且确保它们与其他边界以尽量低耦合的方式进行通信。

3.低耦合

耦合性也称块间联系,是指软件系统结构中各模块间相互联系紧密程度的一种度量。模块之间联系越紧密,其耦合性就越强,模块的独立性则越差。模块间耦合程度的高低取决于模块间接口的复杂性、调用的方式及传递的信息。

能够独立地修改及部署单个服务,而不需要修改系统的其他服务组成。

一个低耦合的服务,应尽可能少地了解其他服务的信息。这同时意味着,两个服务之间需要限制不同调用形式的数量,因为除了潜在的性能问题以外,过度的通信往往是造成紧密耦合的“原罪”。

4.恰当的“微”

服务间的低耦合是指修改一个服务,就不需要修改另一个服务。使用微服务最重要的一点就是,微服务到底多微才算“微”,这个业界也没有一定的标准。微服务也不是越小越好。服务越小,微服务架构的优点和缺点也就会越来越明显。服务越小,微服务的独立性就会越高,但同时,微服务的数量也会激增,管理这些大批量的服务也将会是一个挑战。所以服务的拆分也要考虑场景。例如,当开发人员认为自己的代码库过大时,往往就是拆分的最佳时机。代码库过大意味着业务过于复杂,明显已经超出了开发人员理解的范围,所以也是需要考虑进行拆分的。当然,代码库的大小不能简单地以代码量来评价,毕竟复杂业务功能的代码量,肯定比简单业务的代码量要高。同样地,一个服务,其功能本身的复杂性不同,代码量也截然不同。

5.拥抱变化

好的系统架构都不是一蹴而就的,而是通过不断地完善、不断地演进而来。在构建微服务架构时也是如此,应该是一个循序渐进的过程,允许架构在适当的时候做出调整,做出改变。在项目初始阶段,团队的队员之间肯定需要一个磨合,大家对于微服务的理解肯定也是各有差异,在构建微服务的过程中,往往也会出现划分服务不恰当的问题。此时,最重要的是能够容忍并改正错误,应清醒地认识到,错误是不可避免的,发现问题并努力去解决问题才是“王道”。在这之中,最关键的是团队要始终保持一个“拥抱变化”的心态。

拆分的方法

根据上面提到的拆分原则,拆分微服务主要有下面几种方法。

1.横向拆分

横向拆分,即按照不同的业务功能,拆分成不同的微服务,如天气数据采集、数据存储、天气查询等服务,形成独立的业务领域微服务集群,如图6-8所示。

SpringCloud微服务开发实战:如何进行微服务的拆分?

2.纵向拆分

纵向拆分,即把一个业务功能里的不同模块或组件进行拆分。例如,把公共组件拆分成独立的基础设施,下沉到底层,形成相对独立的基础设施层,如图6-9所示。

SpringCloud微服务开发实战:如何进行微服务的拆分?

图6-9是一个纵向拆分的例子,其中各层次的职责如下。

  • 用户界面层(User Interface):也称为用户接口层或表示层(Presentation Layer),负责向用户显示信息或解释用户指令。这里的用户可以是另外一个计算机系统,而不一定是一个使用用户界面的人。
  • 应用层(Application Layer):定义软件要完成的任务,并且指挥表达领域概念的对象来解决问题。该层主要负责的工作对于业务来说意义重大,也是与其他系统的应用层进行交互的必要渠道。应用层应该尽量简单,不包括业务规则或只是为下一层中的领域对象协调任务、分配工作,使它们互相协作。它没有反映业务情况的状态,但却可以具有另外—种状态,为用户或程序显示某个进度。
  • 领域层(Domain Layer):或称模型层(Model Layer),主要负责表达业务概念、业务状态信息及业务规则。尽管保存业务状态的技术细节是由基础设施层实现的,但是反映业务情况的状态是由本层控制并且使用的。领域层是业务软件的核心。
  • 基础设施层(Infrastructure Layer):为上面各层提供通用的技术能力,如为应用层传递消息、为领域层提供数据访问及持久化机制、为用户界面层绘制屏幕组件等。基础设施层还能够通过架构框架来支持这4个层次间的交互。

3.使用DDD

一个微服务,应该能反映出某个业务的领域模型。使用DDD,不但可以减少微服务环境中通用语言的复杂性,而且可以帮助团队搞清楚领域的边界,理清上下文边界。

建议将每个微服务都设计成一个DDD限界上下文(Bounded Context)。这为系统内的微服务提供了一个逻辑边界,无论是在功能还是在通用语言上。每个独立的团队负责一个逻辑上定义好的系统切片。最终,团队开发出的代码会更易于理解和维护。

您可能还会对下面的文章感兴趣: