⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 码哥跳动 「码哥」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言都将得到认真回复。甚至不知道如何读源码也可以请教噢。
  4. 新的源码解析文章实时收到通知。每周更新一篇左右。
  5. 认真的源码交流微信群。

你是否还在为微服务架构的拆分而苦恼?本文揭秘 7 大拆分原则,助你轻松驾驭微服务架构!

随着云计算的普及,微服务架构成为企业数字化转型的重要选择。

然而,如何合理拆分微服务却成为许多开发者的难题。本文将揭秘 7 大拆分原则,助你轻松驾驭微服务架构,提升系统性能和可维护性。

无论你是架构师还是开发者,这些原则都将为你带来实实在在的帮助。

今天,码哥带大家从不同角度来剖析微服务架构设计的 7 大原则,做到合理且正确地拆分出微服务,避免打造一个被人诟病的伪微服务架构大单体,徒增运维和开发成本。

01 一个反例

这是码哥亲身经历的一个事情,当时我作为架构师角色将公司原 saas 团队的供应链金融系统重新打造成一个标准化应用,基于插件机制,业务开发只需要专注于功能,实现快速得到一个客户想要的软件。

该系统的团队负责人带着 IT 人的傲娇对我说这是一个微服务架构系统……

打开项目代码发现这是一个披着微服务外衣的大单体巨石服务。

我真是太难了,该团队的开发人员把这个系统拆分成了八九个‘微’服务,可实际上业务功能系统压力全集中在 web-service 服务上。

至于拆出来其他的“微”服务,只干了一件事:Myabtis 作为 ORM 框架操作数据库,我问他们为何这样拆?

对方的老开发一脸骄傲的说:“这样可以做到单一职责,解耦……”

单一职责不是这样理解的,大兄弟。真的是「黛玉骑鬼火,该强的强,该弱的弱」。

铁观因:“码哥,微服务架构设计哪些原则可以指导我们正确的设计?避免设计出「依托答辩」的架构。”

好问题,一共有 7 大原则可以帮助我们设计一个好的微服务架构。

02 单一职责

简单的就是最好的!

每个微服务都只负责一个单一的业务,并确保做好这个业务,保证微服务职责单一性、功能完整性拆分, 这样,就便于维护、测试和部署。

另外,每个微服务都有自己的数据库来存储数据,避免一个微服务与其他微服务共享数据库,在数据层解耦,以确保可扩展性和可靠性。

2-1

03 基于可靠性拆分

Dora:这个我懂,不能让一颗老鼠屎搞坏一锅汤。

你这么理解没毛病。

在单体应用中,一个组件的故障可能导致整个系统的崩溃。

通过微服务架构,我们可以将系统拆分为多个独立的服务,从而将故障隔离在单个服务内,避免故障扩散到整个系统。

将可靠性要求高的核心服务和可靠性要求低的非核心服务拆分开来,然后重点保证核心服务的高可用。

当重要策划高难度较低的服务发生故障时,不会影响核心模块的服务。

比如将账号信息、登录信息、服务中心等重要度最高的要害模块单独拆分在一个服务颗粒上(因为这类模块不可用之后,整个系统基本完全瘫痪),再做成服务集群,来保障它的高可用。

04 DDD 领域驱动原则

微服务架构设计其实非常采用 DDD。因为每个微服务本就可以设计成特定领域的实现。

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

  • 战略设计主要从业务视角出发,建立业务领域模型,划分领域边界,建立通用语言的限界上下文,限界上下文可以作为微服务设计的参考边界。
  • 战术设计则从技术视角出发,侧重于领域模型的技术实现,完成软件开发和落地,包括:聚合根、实体、值对象、领域服务、应用服务和资源库等代码逻辑的设计和实现。

使用 DDD(领域驱动建模) 进行业务建模,从业务中获取抽象的模型(例如订单、用户),根据模型的关系进行划分限界上下文。

从 DDD 的限界上下文往微服务转化,并得到系统架构、API 列表、集成方式等产出。

限界上下文可以视为逻辑上的微服务,或者单体应用中的一个组件。

Dora:“码哥,如何找到系统的边界呢?爱情起码还能根据生理上的喜欢来辅助判断。”

DDD 边界上下文可以通过事件风暴来找到,把系统状态做出改变的事件作为关键点,从系统事件的角度触发,提取能反应系统运作的业务模型。

再进一步识别模型之间的关系,划分出限界上下文,可以看做逻辑上的微服务。

例如系统管理员可以创建商品、上架商品,对应的系统状态的改变是商品已创建、商品已经上架;

相应的顾客创建订单、支付,对应的系统状态改变是订单已创建、订单已支付。

商家发货:选择快递公司、顾客填写收货地址……

2-2

05 按照业务稳定性原则

这个很容易理解,需要区分系统中变与不变的部分,不变的部分一般是成熟的、通用的服务功能。

变的部分一般是改动比较多的需求、满足业务迭代扩展性需要的功能,我们可以将不变的部分拆分出来,作为共用的服务,将变的部分独立出来满足个性化扩展需要。

根据二八原则,系统中经常变动的部分大约 20%,80% 是很少变动的,这种拆分方式还能避免 80% 那部分服务的频繁发布。

比如一个电商系统,用户信息、商品信息等管理模块一般是比较稳定的;而运营类的活动和页面是经常变化的。

06 基于吞吐量原则

这是一个拓展原则,是针对特定场景的微服务拆分,简单的说就是访问量特别大,访问频率特别高的业务,又要保证高效的响应能力,这些业务对性能的要求特别高。

比如积分竞拍、低价秒杀、限量抢购。

尽可能把这部分业务拆分出来,既能保证高性能的要求,又能保证业务的独立性。

如果这种访问量巨大的业务如果与其他通用业务放一块,很容易因为某个链路阻塞,导致雪崩效应影响其他业务。

2-3

07 演进式原则

微服务拆分并不是一步到位的,应当根据实际情况逐步展开。

如果一开始不知道应该划分多细,完全可以先粗粒度划分,然后随着需要,适当将粒度划分更细拆分。

Chaya:如果拆分粒度太细会增加运维复杂度,粒度过大又起不到效果,那么改造过程中如何平衡拆分粒度呢?

从两个方面做权衡,一是业务发展的复杂度,二是团队人员规模。

比如一个电商一开始索性可以拆分为商品服务和交易服务,一个负责展示商品,一个负责购买支付。

随后随着交易服务越来越复杂,就可以逐步的拆分成订单服务和支付服务、库存服务、价格服务、物流服务等等。

虽然业务复杂度已经满足了,如果公司此时没有足够的人力(招聘不及时或员工异动比较多),服务最好也不要拆分,拆分会因为人力的不足导致更多的问题,如研发效率大幅下降(一个开发负责与其不匹配数量的服务)。

Chaya:恋爱是两个人的事,3+ 以上就大乱了,所以一个微服务究竟需要几个开发维护是比较合理呢?

三个!

系统规模

从系统规模来讲,3 个人负责开发一个系统,系统的复杂度刚好达到每个人都能全面理解整个系统,又能够进行分工的粒度。

如果是 2 个人开发一个系统,系统的复杂度不够,开发人员可能觉得无法体现自己的技术实力。

团队管理

从团队管理来说,3 个人可以形成一个稳定的备份,即使 1 个人休假或者调配到其他系统,剩余 2 个人还可以支撑。

如果是 2 个人,抽调 1 个后剩余的 1 个人压力很大。

一个人更不用说了,如果他去大保健被抓了,系统出问题就没人维护了。

技术提升

从技术提升的角度来讲,3 个人的技术小组既能够形成有效的讨论,又能够快速达成一致意见。

如果是 2 个人,可能会出现互相坚持自己的意见,或者 2 个人经验都不足导致设计缺陷。

一个人的话,没人进行技术讨论,容易陷入思维盲区。

08 避免环形、双向依赖

微服务拆分还有一个重要原则,就是避免避免环形、双向依赖。

服务之间的环形/双向依赖会使得服务间耦合加重,在服务升级的时候会比较头疼,不知道应该先升级哪个,后升级哪个,难以维护。

产生这种情况大多数是因为服务之间的调用可没有约束导致,为了方便获取或者更新某个表的数据,服务之间任意调用。

也说明我们的功能划分不够清楚或者通用功能没有下沉下来。

消除环形依赖的方法

要解决循环依赖,必须要在微服务之间建立一些原则来约束微服务之间的通信,定期通过这些原则来审视我们的系统,找到问题并进行重构,这些原则应该包括:

  • 定义服务上下游关系,上游服务可以直接依赖下游服务,反之则不可。
  • 上游服务的变更对下游服务产生影响需要通过领域事件(异步)的方式来实现。
  • 服务之间要通过数据 Id(或类 Id,能够唯一代表数据且不变的属性)来进行关联,尽量不做过多的数据冗余。
  • 一旦需要上游服务调用下游服务才能完成业务时,要考虑是否上游服务缺少业务概念
  • 为满足前端逻辑而导致的服务间交互逻辑要放到 BFF(Backend for frontend)中来编排,而不是增加服务间的调用。
文章目录
  1. 1. 01 一个反例
  2. 2. 02 单一职责
  3. 3. 03 基于可靠性拆分
  4. 4. 04 DDD 领域驱动原则
  5. 5. 05 按照业务稳定性原则
  6. 6. 06 基于吞吐量原则
  7. 7. 07 演进式原则
  8. 8. 08 避免环形、双向依赖
    1. 8.0.1. 消除环形依赖的方法