架构

架构设计内容分享:微服务如何拆分?微服务拆分的原则是什么?

转载:架构设计内容分享:微服务如何拆分?微服务拆分的原则是什么?

相信每一位程序架构师,在从零开始搭建一套大型软件系统或者要将大型单体应用进行微服务改造的时候,如果采用微服务架构,那么服务如何划分,一定是每一位架构师都避不开的问题。那么本文就从架构演进的视角来分析如何对服务进行拆分。

 

1.拆分时机


微服务拆分绝非是一个大跃进的过程,是要综合人、环境、时机三要素进行评估的,拆分时机不对,很容易把一个应用拆分的七零八落,最终大大增加运维成本,却不会带来明显收益。

 微服务拆分的过程,是要基于某个痛点出发,是业务真正遇到快速迭代和高并发等问题,如果不拆分,将对于业务的发展带来影响,只有这个时候,微服务的拆分才是有确定收益的,增加的运维成本才是值得的。

 

1.1 有快速迭代的需求

互联网时代,业务需求快速迭代,应用的交付需要快速响应式交付。通过微服务架构,采用敏捷开发、快速迭代的方式进行架构演进,将系统拆分成多个独立的微服务,微服务之间彼此独立,通过服务接口交互。当某个微服务遇到问题时发版修复,不会导致整个系统不可用,从而支撑业务的快速恢复与容错。

 

1.2 当代码耦合度过高,牵一发而动全身

单体应用或分布式应用中,某一个应用融合的功能过多。随着需求的不断迭代,该应用的不同功能的界限会不断的模糊,不同功能代码之间可能存在公用的逻辑,且不同功能之间存在相互的调用,各功能之间边界逐渐模糊,甚至融为一体,导致后期代码的升级改造越来越困难,牵一发而动全身,如果需要修改某一块功能,但是不确定这块代码会不会对其他应用造成影响,导致程序员不敢去修改,只能另辟蹊径再写一块相同的代码,长期以往,代码肯定就是杂乱不堪,这种情况就是架构的腐化。针对这种情况,实际上是需要对该应用进行拆分的,降低耦合度。

 

1.3 瀑布式发布

 传统模式单次上线的需求通常较多、风险较大,小功能的错误可能会导致大功能无法上线。因此每次上线都会带来较大的工作量。

 微服务架构由于将应用的功能进行了细分,可带来独立上线的效果。微服务拆分后,在服务接口稳定的情况下,不同的微服务可独立上线。上线的次数增多,单次上线的需求量变小,可随时回滚,风险变小,时间变短,影响面小,从而加快迭代速度。

 

1.4 解决高并发横向扩展问题

 互联网时代,业务应用的高并发要求越来越高,单体应用虽然可以通过部署多份承载一定的并发量,但是会造成资源非常浪费。有的业务需要扩容,例如下单和支付,有的业务不需要扩容,例如注册。如果一起扩容,消耗的资源可能是拆分后的几倍。因此,对于并发量大的系统,选择微服务拆分是很有必要的。

 

2.微服务拆分的原则


2.1. 准备好微服务治理基础设施
重要的事情说三遍:
准备好微服务治理基础设施!准备好微服务治理基础设施!准备好微服务治理基础设施!

 

在决定实施微服务项目之前,必须确保你所在的公司有完备的微服务治理基础设施,如果微服务基础设施不完备,第一件事情就是要思考:以你们公司的规模和项目的规模,有没有必要搭建这么一套基础设施,包括组建微服务运维团队。如果具备条件,那么在进入开发之前,要先搭建微服务基础设施及运维团队。没有微服务基础设施,实践微服务就是一场灾难。

 

2.2. 单一责任原则(SRP)

SRP是微服务架构重要的原则。每个微服务应该只关注一个特定的业务领域或功能,因此其API应该具有明确的职责,只提供与该领域或功能相关的接口。这个业务粒度的大小取决于你对业务和架构综合考虑。

SRP能够确保微服务职责单一性、功能完整性进行微服务拆分, 这样,就便于维护、测试和部署。

 

2.3. 松耦合原则

松耦合是指每个微服务都应该是独立的,并通过API与其他服务进行通信。松耦合的优势:可以降低 级联故障 的风险,也可以提高服务可扩展性,提高微服务的可复用性。

尽量做彻底解耦,包含数据库层的解耦:

  • 数据库层的解耦,就是避免一个微服务与其他微服务共享数据库,因为这可能会导致数据不一致,并且会使故障排查变得非常困难。
  • 每个微服务也都应该只管理自己的数据,每个微服务都有自己的数据库来存储数据,以确保可扩展性和可靠性。

 在设计微服务时,应该专注于创建小型、松散耦合和高度内聚的服务。

 

2.4. 领域驱动原则   

对于服务的拆分,不是数据驱动原则,也不是界面驱动原则。   DDD是一种软件设计方法,它专注于特定业务领域的软件设计。   微服务架构、微服务设计非常适合采用DDD,为啥呢?   因为每个服务都可以设计为特定业务领域的具体实现。

领域驱动设计,首先应建立领域模型,确定领域限界上下文,然后才进行微服务拆分,

如果是数据驱动原则/界面驱动原则 ,那么是一上来就定义数据库表结构,就去调整领域逻辑代码。

领域模型和领域服务应具有高度通用性、稳定性,通过接口层和应用层屏蔽外部变化对业务逻辑的影响,保证核心业务功能的稳定性。

基于领域模型进行拆分,围绕业务领域按职责单一性、功能完整性进行拆分。

 

2.5. 架构分层职责明确,严守调用规范,规避 “微服务小泥球”

老的单体架构, 常常被称为大泥球。“大泥球”单体,主要的问题:

  • 代码腐化:业务代码经过长时间的迭代,有很多重复代码。比如一个功能可能有 3,4 种实现。
  • 业务逻辑交织:业务应用经过长时间发展,功能变多,业务功能里的逻辑代码可能相互引用,交织不清。
  • 代码复杂:功能多,业务逻辑复杂,只有少数员工能理解。这也是代码腐化一种。
  • 维护性变差:修改 bug 或增加新功能时,牵一发而动全身。一个 bug 没修好可能导致整个软件不可用。
  • 扩展性变差:增加新功能时,牵一发而动全身。
  • 编译发布变长:软件代码量大,编译时长变长,导致发布时长也变长。

     化解“大泥球”单体的措施,是微服务架构。微服务架构最基本的一个点:分而治之,由大化小。

  • 松耦合:划分为一个一个小的微服务,代码之间逻辑交织降低。

  • 独立部署:每个划分的微服务都是一个独立的项目,可以独立部署。

  • 编译发布改善:划分为独立的小项目,编译时长变短,发布时长变短。

  • 故障隔离:由于划分为一个一个微服务,故障仅发生在独立的微服内。

  • 可扩展性:每个服务可以独立横向扩展,也可以从应用程序中提出独立功能变成服务,扩展变强。

  • 职责单一团队:每个小的微服务都由一个小型的高度专注的团队负责。

  • 技术异构:每个团队可以选择适合该业务的技术。

微服务架构目的就是把一个大单体划分为各种微服务,松耦合,独立自治。微服务架构把一个大泥球,变成了很多个小而美的颗粒。每个小颗粒职责单一,边界明确,可以通过简单组装完成大的功能,自然就比之前的大泥球好处理得多。

 但是,迭代过程中,出现了一种奇怪现象,微服务内部没有进行规范的内部的模块划分,代码耦合严重,调用关系混乱,就像一个小泥球。比如在老的微服务架构中,如果团队缺乏明确的微服务技术规范,很容易出现分层不明确,下层服务过度理解业务逻辑,存在下层调用上层的问题,出现了代码耦合严重,调用关系混乱的 “微服务小泥球”。

 严格遵守分层架构原则,上层服务可调用下层服务,下层服务不涉及业务逻辑。如上下层服务需交互,可通过逻辑解耦方式实现,如消息队列或中转。

  如何规避 “微服务小泥球”?

各层职能定位清晰,只能上层调用下层,也就是说只能从外层调用内层服务,下层服务通过封装、组合或编排对上层暴露,服务粒度由细到粗。

  • 基础层为各层提供资源服务
  • 领域层负责领域业务逻辑的实现
  • 应用层负责服务的编排和组合
  • 接口层对外进行服务暴露

 

2.6. 进行全方位的监控、记录     

实施微服务,必须从架构搭建开始,就时刻注重调用链路的记录、跟踪及监控。监控和日志记录对于微服务架构的安全、维护和调优都至关重要。     在拥有数百个微服务的项目中开发的主要困难之一是调试非常困难,因为服务分散、日志分散,很难找到失败的原因。     因此,每个服务都应该有日志记录和监控措施,以跟踪其性能并检测错误。

 

2.7. 通过CI/CD实现devops (开发运维一体化)   

CI/CD是一种软件开发运维过程实践,打通开发和运维环节,实现应用程序的构建、测试和部署自动化。大大提升研发效能。     任何微服务都应该是可持续部署的,实现微服务的快速高效部署,缩短了微服务上线时间。

总之,采用微服务架构开发有许多优势,但要确保为微服务系统成功实施就需要遵循一些设计原则。

包括但不限于上面介绍的几个基础原则,在此基础上还需要有与所在领域或者行业的做定制化优化实践。

  

3. 有了上述的原则,具体如何进行微服务的拆分?


  微服务的拆分应遵循上述拆分时机、拆分原则,并选择合适的拆分方法,逐步拆分。在实际拆分过程中,除了要遵循拆分原则,还要从实际业务领域出发,并结合考虑非业务的因素,比如需求变更的频率、高性能、安全性、团队规模以及技术异构等因素。这些非业务因素对于最终落地也会起到决定性的作用,因此在微服务拆分时需要重点关注。

3.1. 基于业务需求变化频率进行拆分

分离“变和不变”, 是 设计领域最应该遵守的一条核心的原则。识别变动频繁的业务需求和领域模型,考虑业务变更频率与相关度,将业务需求变动较高和功能相对稳定的业务进行分离。

 经常性变动必然会导致代码的频繁修改和版本发布,分离变和不变,可以有效降低频繁变动业务对稳态业务的影响。

 

3.2. 基于吞吐量进行微服务拆分

识别领域模型中性能压力较大、高吞吐量的功能,并且进行解耦,解除独立的微服务。这样做有两个好处:

  • 避免高吞吐服务,拖累整个系统的性能, 由于局部的性能拖累整体性能。
  • 解耦之后,可以对高吞吐量服务定制个性化的扩容缩容策略、熔断保护策略、限流策略。

 

3.3. 基于技术异构因素进行微服务拆分

 领域模型中有些功能虽然在同一个业务域内,但在技术实现时可能会存在较大的差异,也就是说领域模型内部不同的功能存在技术异构的问题。

 比如,在go+java 双语言云原生架构实操中, 有的可能用go,有的则是 Java,当然,还有的微服务用大数据架构。所以,对于这些存在技术异构的功能,可以考虑按照技术边界进行拆分。

 

3.4. 基于组织架构和团队规模进行微服务拆分

 除非有意识地优化组织架构,否则微服务的拆分应尽量避免对组织架构和团队的调整,避免由于功能的重新划分,而增加大量且不必要的团队之间的沟通成本。在进行微服务拆分和组建项目团队时,应尽量将沟通边界控制在团队内。

 

3.5. 基于业务领域拆分

 基于领域模型,围绕业务界限上下文边界,将同类业务划归为一个微服务,按单一职责原则、功能完整性进行微服务的拆分。

对于有特殊安全要求的业务,应独立出来,避免因不同的安全要求,而带来不必要的成本,或带来泄密的风险。