如何进行微服务的划分

标签: | 发表时间:2024-02-08 16:45 | 作者:
出处:https://zhuanlan.zhihu.com

本文是我在 2021 GIAC 上的一次分享 《Hints for Microservice design》的精简过后的讲稿。

前言

本次分享的内容主要是关于业务架构的讨论,业务架构不像技术架构一样有明确的好坏衡量标准,例如评价数据库的技术架构好不好,就可以在限定的资源限制下去 benchmark 进行评判,但是业务架构不能 benchmark。你现在不能证明某个业务架构是好的,未来也不能。所以我把我分享的内容称为 hint,而不是 Guide,Principle;这些只是写个人经验的简单总结而已,所以「Don't Belive Me!」

本次分享总共分为两大部分

  • 提出问题
  • 如何衡量是否解决了问题和可能的解决方法

即「 期待解决的问题,目标,现状」和「 如何设计架构,有哪些维度,好的标准是什么

期待解决的问题,目标,现状

我们不从微服务的定义开始进行讨论,而是从我们期望解决的问题开始进行讨论。

期望微服务解决什么问题?

首先需要回答一个问题是「研发团队做得好坏的标准是什么」?我个人喜欢用 four key metrics进行衡量。即

  • Deployment Frequency—How often an organization successfully releases to production.
  • Lead Time for Changes—The amount of time it takes a commit to get into production.
  • Change Failure Rate—The percentage of deployments causing a failure in production.
  • Time to Restore Service—How long it takes an organization to recover from a failure in production.

这四个指标从研发速度和研发质量两个维度进行了衡量。

架构设计成什么样子有利于提高研发的速度和质量呢?其实是尽可能的自治,不互相依赖,自己搞自己的;我在公司的技术群里发起过一个投票「期望微服务解决什么问题?」,也一定程度印证了这个观点;

现状

现状是怎样的呢?大部分业务系统如下面两个动画所示


目标

理想的情况又是怎样的呢?如果用一张图表示,我希望理想的业务系统可以像乐高一样,每一类乐高组件是一个子系统(业务能力),可以利用不同类的组件基础能力组合成复杂的业务能力(系统)。

那我们来看看大部分公司的真实拆分微服务的历程,最后有没有达到像乐高一样各组件尽可能的自治,又能拼装出来复杂业务系统的目的。即「满足一定规范的尽可能的自治,又能自由组合」。接下来我们来看拆分案例

案例

最开始业务模型比较简单,要满足的需求比较少,只有一个系统。

后来发现供应链很重要,出现问题就是重大故障。所以需要把供应链系统单独拆出来单独维护。

后来大家发现课时 CRUD 模块是公用模块也拆出来吧

拆着,拆着就总结出了如下几条规律

最后把系统拆成了这个样子,一个十分复杂的系统

根据我们总结的规律最后拆分出来的系统,做到「在一定的规范下尽可能的自治」了吗?解决了所谓的耦合问题了吗?貌似没有解决,而且出现了下面的新问题。

那么如何衡量是否做到了「在一定的规范下尽可能的自治」,标准是什么?又如何做到呢?我们在第二部分进行讨论

如何设计架构,有哪些维度,好的标准是什么

从哪些维度设计架构?

1995 年有一篇相关的论文 Architectural Blueprints—The “4+1” View Model of Software Architecture即围绕业务场景从四个视角设计和观测架构。借鉴这个思路,但是我们简化一下重点讨论两个维度

  • Logical view: 业务架构,业务模块的设计与划分
  • Process view:物理运行时架构,运行时进程组的设计与划分

其实也就是要达到的目的「自治要达到业务模块和物理模块(物理层面的弹性与隔离)的自治」


Logical view 可以通过部署与 Process view 进行对应

那接下来我们开始讨论 Logical view 和 Process view

Logical view(业务架构)

提起业务业务架构我们一般会想到哪些建模方法和指导原则?更重要的是衡量业务架构的好的标准是什么?因为只要把好的标准搞清楚了,才能真正的讨论问题,

这些我们经常提到的方法和原则实际能帮到我们吗?确实有一定的指导意义。但是它们还是太笼统了,不够具体。不够具体造成的问题

  • 不同的人理解差距太大,不能达成共识
  • 不能真正的实施,不能通过工具以数据的方式体现
  • 极难进行知识的传达

那么好的标准到底是什么呢?接下来我们尝试通过一些现象来总结一下

分层

下图是我们写代码时最常见的结构,将代码分成了这几层。对应到微服务上很容易地变成按照层次拆分成四类(DAO Service Application View)服务的实践。

下图是我在 知乎的技术架构是什么样的?中的一张关于基础架构的一张架构图。也是明显的分层架构。

从业务架构视角来看,与上图的分层最大的区别是什么呢?

最大的区别是第一个分层很多时候并没有达到分层的目的,很多时候一个新需求或者修改一个已有的需求都需要从头(view)改到尾(DAO),层与层之间的接口是不稳定的;第二张图里层与层之间的接口是稳定的,一般一个新需求只改一层就可以了,层与层是不知道彼此的存在的。

什么样的分层架构是好的?如何进行衡量呢?

层与层之间接口是否稳定,层与层之间是否必须知道彼此的存在也许是分层架构一个好的衡量标准

问答社区

再看下经过简化过后的问答社区的业务架构,这个架构看清来比较清晰。没有我们第一部分遇到的问题,看起来也达到了自治的目的。

这个架构为什么比较清晰?

因为模块除了 feed 之外模块之间没有任何数据和逻辑共享,彼此之前不互相影响。

从业务架构角度还有哪些可以优化的地方吗?

也许由 Feed 定义接口其他的系统(文章,问答,广告,知识市场)来实现会更好。这样更能保证接口的稳定。即业务架构上将 Feed 系统放到下边;下边电商的例子也会提到

电商(订单,价格)

订单

电商领域一般被认为是比较复杂的,电商团队一般也是加班最多,最繁忙的;那我们一起来分析下单的这个业务。即用户点击「提交订单」,相关信息(收货人信息,支付方式,送货清单,发表信息,优惠券等)被保存,然后开始履约。

对于这个业务场景,最直观地业务架构设计是将所有的信息存储到订单系统里,然后各方履约的时候从订单系统里获取(getOrderByID)。这样的设计十分容易理解。如果部分履约系统发生了发生了业务变化是怎样的;例如买了免费商品不需要付费了怎么办?新增了某种支付方式或者开发票的信息怎么办?都需要通知订单系统进行修改,进行接口的变动,跨团队的沟通。是不够自治,十分影响开发效率的。

可以换一种思路来设计,最极端情况下订单是不是可以只一个 orderID,然后各个履约方存储自己关心的信息(不让订单系统代为存储),并且与 orderID 关联。这样各个履约方如果发生业务迭代的时候只需要改动自己的系统和存储就可以,与其他系统业务相对隔离,保持足够的自治。

价格

再看下图中右下角的价格,价格理论上是根据多方的信息计算出来的。例如商品的原始价格,优惠券,支付方式,配送方式等;实现价格系统时我当然可以把所有的信息都存储在一起,并且把所有价格相关的计算逻辑也写到一个模块里;这样维护价格的团队可能是全公司最忙的了,因为每个业务系统都想改变价格,频繁调整价格来强调自己业务的重要性<(* ̄▽ ̄*)/。

价格计算有两种计算逻辑。一种是类似 Chain-of-responsibility pattern,价格计算按照一定顺序交给各个系统轮流处理,报价系统按照特定顺序进行调用即可。另一类稍微复杂一些,必须根据各方系统的信息综合判断才能计算出价格,例如用户是会员,持有特定优惠券,并且选择特定支付方式的前提下才能计算出最后的价格,这种情况下报价系统从各方系统获取必要信息,进行小部分的计算的集成算出最后的价格

这里需要特别注意的是:接口一定是由报价系统定义,然后由其他系统(优惠券,会员,团购,支付等)来实现的。而不是直接调用其他系统暴露出来的 getCouponByID 类似的接口,这样才能更好的保持在价格这个业务逻辑里接口的稳定,从而保证足够的自治。这也正是 Dependency inversion principle 在业务架构里的重要体现。

数仓

在很多公司做业务数仓的工程师和与业务数仓合作的业务研发工程师都很痛苦,因为面临如下问题

  • MySQL schema 的变化导致数仓同学改一个月,如果没有通知到数仓的同学直接导致数仓的故障
  • 业务研发想把 MySQL 换成其他的存储如 Redis,HBase;但是数仓同学不同意,因为不能像 MySQL 一样监听 binlog 进行数据统计
  • 数仓的数据错了,debug 超级困难

造成这些问题的根本原因是什么呢?MySQL 即为业务服务又为数仓的数据服务,双方都强耦合了 MySQL 的 schema 的这个接口,但是这个接口却不稳定。可以有其他的解决方案吗?

也许我们可以像维护 RPC 接口一样去维护数仓数据的接口,而不是依赖业务 MySQL schema。也就是说让每个业务团队定义好自己对外提供数据的接口,并将其实现,同时将接口注册到类似微服务注册中心的数据接口注册中心。从组织架构上直接上业务研发团队具备数据处理能力,统一的业务数仓团队从各个业务研发获取数据,做数据的互联互通,而不是把所有的细节的业务数据处理放到统一的数仓团队。这也是最近比较火的 Data Mesh的核心思想。

总结

从上文的各个例子中,能否总结出一个业务架构好的标准是什么?如何才能做到在一定的规范下尽量自治,从而提高开发效率和质量。也许是这样的(按照顺序从上到下,越上边越好)

  • 不同模块间完全没有影响
    • 问答社区例子,能做这样是最好的。这种情况最理想,但是很多业务不会这么简单。
  • 只共享 immutable data
    • 电商订单的例子中不同的系统间只共享了 orderID,是不可变数据。不同系统间的影响是可控的
  • 共享 mutable data,但是 interface 少,而且几乎不变
  • interface 变化次数 / implementation 变化次数比例小
    • 电商报价系统与业务数仓的例子,系统间共享的数据是会变化的,但是系统间的接口是稳定变化的的;哪怕会变化,接口的变化次数也是大大小于实现的变动次数的。

再看一下这张图,为什么我们在第一部分总结的「拆得越细越好」不对呢?乐高可以使用小组件组合成不同的模型是最核心原因是因为「拆得细」吗?其实并不是,而是「乐高小组件形状是不变的,即组件的接口是稳定不变的」

稍微上升一下高度,如果只用一个词来概念系统面临的问题,就是 Complexity。Complexity的核心来源又是什么?是「不同模块间的相互影响」。我们前边总结的业务架构好的标准和设计方法不就是在想办法衡量复杂度,控制复杂度吗?

那么有哪些具体的 hints 可以帮助我们达到上文提到的好的标准呢,如下图琐事。具体在这里就不详细介绍了,后再单独另开其他的 topic 进行展开。到此 Logical veiw 告一段落。

Process view(物理运行时架构)

首先要问为什么要做物理运行时隔离?目的其实就是达成物理层面的自治。

这是物理运行时自治带来的好处?那又有哪些负面影响呢?一方面是 Fallacies of distributed computing,另一方面是违背了 Law of Demeter

https://www.wikiwand.com/en/Fallacies_of_distributed_computing

物理运行时的隔离面临这么多问题,那有什么好的解决方案吗?希望在做到物理层次的隔离的同时,又尽可能不受分布式的影响,并能尽量少的暴露 API ,不违背 Law of Demeter

此图表示的是一个业务模块,但是在运行时有不同的 SLA 和弹性边界的要求,需要把 HTTP,RPC,Consumer 进行物理运行时的隔离。那么我们可以把整个业务模块的代码写到一个 git repo 里,同一个 git repo 跑起来后所有的通信都是进程内通信,把有物理隔离诉求的服务编译成不同的可运行可运行的包,然后分别部署到不同的进程组就可以了。如上图可以把 HTTP,module A,module B,backend 和 RPC ,module B,module C,backend 和 Consumer ,module B,backend 分别编译之后部署到不同的进程组,这几个进程组一定要一起部署一起回滚,从而保证版本分化的风险;这样的物理运行时设计就做到了物理层面的自治的目标了。

到这里大家也看到了,也是需要重点强调的是业务架构模块与物理运行是模块并不是一一对应的,这也是大家普遍对于微服务的误解。千万不要把两者混为一谈,而是要先设计业务架构再设计物理运行时架构。

总结

简单回顾一下,整个分享我们先看了我们面临的问题,现状和要达到的目标。然后第二部分通过一些现象总结了业务架构好的标准,并且给出了如何做到业务架构自治的标准与物理自治的一些 hints。整个分享内容很多,如果只记住两个 hint 的话,我希望是这两点。

后记

回头看起来这个分享有以下几个问题,需要进行改善。

  • 想要表达的东西太多,造成了重点不是十分明确;
  • 目录划分不好,逻辑不够清晰,有些头重脚轻;
  • 笼统的现象举得太多,造成讲得都不够透彻,不如只讲一两个具体的案例。

此外需要声明的是文中的主要思想都是来源于 @陶文 业务逻辑拆分模式 Udi Dahan在此郑重感谢两位老师的指导。

希望大家多多评论或者以私信的方式提出批评和质疑。

PS.如果上文对你有一点点儿帮助,欢迎来我和 @陶文 @flaneur @lfyzjck《打开引擎盖》一起深入讨论

参考

相关 [何进 微服务] 推荐:

如何进行微服务的划分

- -
本文是我在 2021 GIAC 上的一次分享. 《Hints for Microservice design》的精简过后的讲稿. 本次分享的内容主要是关于业务架构的讨论,业务架构不像技术架构一样有明确的好坏衡量标准,例如评价数据库的技术架构好不好,就可以在限定的资源限制下去 benchmark 进行评判,但是业务架构不能 benchmark.

初识微服务

- - ITeye博客
微服务架构越来越火,有必要学习一下. 软件开发过程中碰到什么问题. 一个简单的应用会随着时间推移逐渐变大. 在每次的sprint中,开发团队都会面对新“故事”,然后开发许多新代码. 几年后,这个小而简单的应用会变成了一个巨大的怪物. 一旦你的应用变成一个又大又复杂的怪物,那开发团队肯定很痛苦. 敏捷开发和部署举步维艰,其中最主要问题就是这个应用太复杂,以至于任何单个开发者都不可能搞懂它.

谈微服务架构

- - 人月神话的BLOG
其实在前面很多文章谈到SOA,特别是系统内的SOA和组件化的时候已经很多内容和微服务架构思想是相同的,对于微服务架构,既然出现了这个新名称,那就再谈下微服务架构本身的一些特点和特性. 从这个图可以看到微服务架构的第一个重点,即业务系统本身的组件化和服务化,原来开发一个业务系统本身虽然分了组件和模块,但是本质还是紧耦合的,这关键的一个判断标准就是如果要将原有的业务系统按照模块分开部署到不同的进程里面并完成一个完整业务系统是不可能实现的.

微服务性能模式

- - 互联网 - ITeye博客
前言:基于微服务系统越来越普遍. 下面我们就来看看五种常见的特定微服务性能的挑战,以及如何应解他们. 背景:在IT界微服务架构为基础的系统越来越多, 每一个应用系统都集成了不同的组件和服务,几乎所有的特定业务应用程序都需要集成一个或更多的应用服务. 但是一个综合性系统集成不同的服务这无疑是一个巨大的挑战.

微服务与架构师

- - 乱象,印迹
因为工作的关系,最近面试了很多软件架构师,遗憾的是真正能录用的很少. 很多候选人有多年的工作经验,常见的框架也玩得很溜. 然而最擅长的是“用既定的技术方案去解决特定的问题”,如果遇到的问题没有严格对应的现成框架,就比较吃力. 这样的技能水平或许适合某些行业,但很遗憾不符合我们的要求. 软件架构师到底应该做什么,又为什么这么难做好,这都是近来的热门问题,我也一直在和朋友们讨论.

从Excel到微服务

- - 乱象,印迹
Excel很老,Excel很土,Excel一点也不sexy;微服务新,微服务很潮门,微服务很高大上. 那么,Excel和微服务有什么关系. 上个月看了篇文章,The Unbunlding of Excel. 作者认为,对于初创公司(尤其是非“纯IT”初创公司)来说,Excel几乎包办各种工作. 想做轻量级的CRM,可用Excel.

微服务拆分之道

- - DockOne.io
微服务在最近几年大行其道,很多公司的研发人员都在考虑微服务架构,同时,随着 Docker 容器技术和自动化运维等相关技术发展,微服务变得更容易管理,这给了微服务架构良好的发展机会. 在做微服务的路上,拆分服务是个很热的话题. 我们应该按照什么原则将现有的业务进行拆分. 接下来一起谈谈服务拆分的策略和坚持的原则.

微服务之saga模式

- -
你已经使用 database ber service 模式. 每个service拥有自己的database. 一些业务事务会跨越多个service,所以你需要来确保data consistency. 例如,假设你正在构建一个电子商务网站,这个网站的用户的会有一个最大欠款限制,应用程序必须确保一个新订单不能超过用户的最大前款限制,但是orders表和customers表不在同一个数据库,所以应用程序不能简单的使用本地的ACID事务.

微服务安全简介

- - 掘金 架构
​由于其可扩展性、灵活性和敏捷性,微服务架构已经变得越来越受欢迎. 然而,随着这种架构的分布和复杂性增加,确保强大的安全措施变得至关重要. 微服务的安全性超越了传统的方法,需要采用全面的策略来保护免受不断演变的威胁和漏洞的影响. 通过理解核心原则并采取有效的安全措施,组织可以加强其微服务架构,并保护敏感数据和资源.

微服务框架Spring Cloud介绍 Part2: Spring Cloud与微服务

- - skaka的博客
之前介绍过 微服务的概念与Finagle框架, 这个系列介绍Spring Cloud.. Spring Cloud还是一个相对较新的框架, 今年(2016)才推出1.0的release版本. 虽然Spring Cloud时间最短, 但是相比我之前用过的Dubbo和Finagle, Spring Cloud提供的功能最齐全..