微服务到底要多微?

        我经常会被问到一个问题:我们的微服务边界要怎么划分?怎样的粒度才算合适?

       面对这样没头没脑的问题,标准答案只有一个:看情况(It depends)。这不是我故意耍小聪明,而是事实情况的确就是如此。因为微服务划分并不是单纯的技术问题,它更是业务问题,甚至是组织问题。因此,脱离业务上下文和组织边界讨论服务边界是没有意义的。

      说实在的,即使你把背景都和说清楚了,我也不一定就能给你一个“满意”的划分。因为分类这个事情从来就是一门艺术。但是,有了背景知识,我能给你一个相对“逻辑正确”的划分,即我会告诉你我为什么要怎么划分,以及其背后的逻辑是怎样的。

      本文,我会带你一起系统的了解微服务划分背后的逻辑和原则,从而可以从容不迫的进行微服务架构。

1. 微的内涵

       时至今日,我想已经很少有团队把“微服务”的“微”等同于“微小”的“微”了。但当这个技术术语才出来的时候,的确有一定的误导性。所以,我们看到很多团队做了过细的微服务拆分,导致不仅没有享受到微服务带来的便利,反而增加了运维和维护成本。

        Martin Folwer在他的文章《Microservices》中也提到了这一点,他说:“ Although “microservice” has become a popular name for this architectural style, its name does lead to an unfortunate focus on the size of service, and arguments about what constitutes “micro”. In our conversations with microservice practitioners, we see a range of sizes of services. The largest sizes reported follow Amazon's notion of the Two Pizza Team (i.e. the whole team can be fed by two pizzas), meaning no more than a dozen people. On the smaller size scale we've seen setups where a team of half-a-dozen would support half-a-dozen services.”

       大意是说,很多人把关注点放在微(micro)上这是不对的,在实践中不管是amazon的two-pizza-team(12个人)维护的一个服务,还是创新公司的一个人一个服务,都可以是微服务。

       所以,在继续探索服务粒度之前,我们先明确一下,微不是指微小,micro是和monolithic相对应的分布式架构风格。和粒度(size)并没有必然的关系。

2. 服务划分维度

       微服务划分也是分类(即把哪些功能分类到一个服务中)。分类是一门艺术,关键是要找到合适的分类维度。属性越多的事物,越难进行分类。我经常拿操场上的一群学生举分类的例子,就这样一个简单的群体,你都很难穷尽其分类。我们可以按照性别分成男生和女生,按照身高分成高的和矮的,按照成绩分成成绩好的和差的... ... 具体要怎么分,取决于分类目的,如果是要选拔奥数选手,那当然是要按照成绩分,按身高分类是没有意义的。

935b7d526bb789e27a8a25fa368c66d3.png

       微服务的划分也是一样,关键是要找到合适的分类维度。我们不妨从微服务的定义看看哪些维度是微服务的关键属性,从而找到合适的划分维度。软件系统最终都是要实现业务价值,一个理想的微服务,应该是能独立完成一个或一组业务能力(业务维度);一个微服务最好是由一个团队负责,这样不会踩脚(组织维度);此外,还要满足质量设计要求,比如吞吐量、可靠性、安全性等等(质量维度)。

        因此,微服务的划分维度,首当其冲的应该是业务功能,其次是组织边界和质量属性

2.1 业务维度

       在做边界划分的时候首当其冲要考虑的就是业务内聚性,因为服务作为一组功能单元,它肯定是提供了一定的业务能力的。不同于传统的单体架构,把所有的业务功能都放在一个应用中,微服务期望我们对业务进行拆分。那么这个拆分的边界理所当然的应该是和业务边界对齐。

1)业务能力(Business Capability)

       业务能力是指一些能够为公司(或组织)产生价值的商业活动。业务能力通常集中在特定的业务对象上。例如,商品对象是商品管理的重点。能力通常可以分解为子能力。例如,商品管理能力具有多个自能力,包括商品信息管理,产品信息管理,类目管理等等。

       按照业务能力拆分服务,是典型的业务视角拆分,和技术实现无关。如果你对一个领域非常熟悉,或者是领域专家,你完全可以站在山顶上高屋建瓴进行自上而下的领域划分。比如我对电商领域很熟悉,如果要让我做电商系统的架构,我很自然的会把整个电商系统划分成商品服务、会员服务、订单服务、店铺服务、交易服务、物流服务、库存服务、评论服务等等。

817b6826e064edd05e2c274e59dfbe89.png

        然而对于一个陌生的业务,识别业务能力并没有那么容易。因此作为一个架构师,理解问题域永远是第一位的。熟悉一个领域,从组织结构作为切入点(starting points),是一个不错的开始。

        这是因为在组织中,不同的部门是要负责不同的业务能力。(organization structure - different groups within an organization might correspond to business capabilities or business capability groups.)

        比如,在电商企业中,有商品运营是要负责对企业的商品进行管理,会员运营是要负责用户增长。这些不同的组织对应的不同业务能力,就需要对应的系统服务来支撑。

        这也是为什么,我在《程序员的底层思维》中关于新人落地指导中,特别提出来熟悉组织结构的重要性,因为通过组织结构你可以快速的熟悉一个企业的业务,以及运作模式。

本节更多内容可以参见:https://microservices.io/patterns/decomposition/decompose-by-business-capability.html

2)子领域(Subdomain)

       随着微服务的兴趣,DDD也被提到了很高的高度,这是因为DDD的战略设计(子领域划分,限界上下文)可以说和微服务架构简直就是天造地设的一对,一个Bounded Context对应一个微服务,微服务之间的集成采用Context Mapping,完美。

       总体而言,以领域为核心的划分方式和我们上面提到的业务能力基本是一致的。比如,商品服务(提供商品业务能力)的领域核心实体就是商品。对于电商领域而言,不管你是通过User Story自上而下的建模,还是通过Event Storming自下而上的建模,商品都将是一个核心子领域,因为商品是贯穿整个电商业务的核心。

       所以通过业务内聚性识别子领域,和通过业务能力识别服务边界,在很多方面是共通的,共性的地方我就不赘述了。不同之处在于,DDD还提供了一个领域重要程度的视角,即其将子领域按重要程度分为核心域、支撑域和通用域。实际上,程度虽然也是一个维度,但并不像业务能力那么关键,大部分时候,即使你不知道子领域的概念,也不影响我们的微服务划分。但了解一下总没有坏处,有时候,不同的视角会给我们不同的启发。

  1. 核心域(Core Domain),顾名思义这是我领域的核心。有一点需要注意,Core念是随着你视角的变化而变化的。比如商品领域是核心域,但是对于订单领域而言,商品领域只是它的支撑。

  2. 支撑子域(Supporting Subdomian),虽然不是当前问题的核心领域,但也是必不可少的。比如订单服务离不开商品、会员、支付等其它领域的支撑。

  3. 通用子域(Generic Subdomain),如果一个子域被用于整个业务系统,那么这个子域便是通用子域。通常像账号、角色、权限都是常见的通用子域,每个子系统都需要。而且通用子域通常是领域无关(Domain Neatural)的,比如权限,所有的领域都需要(商品管理、会员管理等),它可以独立于领域而存在。反映在系统架构上就是其它子域可以依赖通用子域,但是反向依赖是不应该的。

本节更多内容可以参见:https://microservices.io/patterns/decomposition/decompose-by-subdomain.html

3)Business(业务)vs. Domain(领域)

       最近看到一个说法,说业务和领域不是一回事。大意是说业务(Business)聚焦在如何盈利,关注的是企业运营,随着企业运营模式的变化,其变化会比较大。而领域(Domain)关注的是问题域自身,相对比较稳定。比如支付是领域,支付宝、微信支付、银行转账、现金支付都是这个领域里不同的业务。社交是领域,微信、陌陌、微博是社交领域不同的业务。

       以社交领域为例,社交作为一个领域,其本质是人与人的连接,所以对于这个Domain而言,它要解决的就是人和人连接、沟通的问题。拿微信为例,微信里面除了加好友,和好友沟通是社交领域之外,其它的众多功能都属于业务部分,比如公众号、朋友圈、小程序等等。

acd0d4185aaadbe27659960918504029.png

       这也算是一种划分维度吧,即Domain反映的是本质,社交产品的基础和核心肯定是社交域。而上层的业务,比如公众号、广告都是业务功能,是因为公司运营盈利的需要,叠加在领域之上的。该维度和上文提到的程度维度一样,即使你不了解,很多时候也不影响我们的服务划分。因为在系统的表现形式上,每一个功能模块都可以是一个微服务。比如社交微服务、公众号微服务、朋友圈微服务等。

       同样,多一个维度,多一种视角。区分Domain(领域)和Business(业务)的意义在于,它可以帮助我们把领域核心和业务模式看清楚,从而可以更好地理解业务。以及理顺微服务之间的依赖关系,比如Domain是基础,Business的微服务可以依赖Domain微服务,反过来就不合理了。

       另外,因为每个微服务的目的不一样,它们的弹性诉求也不一样,比如现在发朋友圈的人越来越少了,原来朋友圈微服务需要1000台服务器,现在800台就够了。而使用微信的人并没有减少,所以社交服务器的数量不能减少。

2.2 组织维度

      业务维度是微服务划分的最主要考量维度,我们的组织结构和系统结构都是围绕着业务结构进行设计的。

      根据康威定律,组织边界决定系统边界。反过来也是一样,系统边界也可以影响组织边界。

    Any organization that designs a system (defined broadly) will produce a design whose structure is a copy of the organization's communication structure.

-- Melvin Conway, 1968

      上文说过,熟悉一个业务,最好的切入点就是从组织结构入手,看看一个组织有哪些岗位,每个岗位都是干什么的,把这些业务活动串起来就能得到一个完整的业务流程。

      所以我们在做服务划分的时候,也要兼顾到组织边界。比如我以前是带商品团队的,然而我团队只负责商品的写入,商品的读是从业务上来说,是属于买家侧的,所以是在另一个团队。因为组织边界的问题,我们将商品的读写分离成了两个微服务。

      就这个case而言,这种划分还无伤大雅,毕竟对于电商的商品而言,其读的数量要远大于写的数量,二者的弹性边界是不一样的,所以设计成CQRS也还合理。然而,如果发现因为组织边界造成了系统设计巨大阻碍的时候,我们也不总是要让系统边界去适配组织边界,必要时,也可以调整组织

      另外,为了减少沟通成本,我们提倡全功能团队(cross-functional team),即我们期望任何事情在服务边界内部都能形成闭环,从这个角度来说,按照业务能力划分组织会更加合理。

083f4e31d67875265874bf1542d9fb85.png

2.3 质量维度

      我们都知道软件系统除了要满足功能属性,还要满足非功能属性,也就是质量属性。这些质量属性包括可靠性、可用性、安全性、可扩展性、可维护性等等。在做微服务架构时也是一样,微服务的边界主要反映的是业务边界。此外,有时候也要考虑质量边界,比如不同的弹性诉求,不同的安全诉求可能会影响到微服务的边界划分。

      上文我们说商品系统的读写分离,主要是因为商品的读和写分别是有两个不同的团队在负责,所以要做拆分。然而即使是在一个团队内,这种分离也是有价值的,因为商品的写入主要是运营人员和商家,而商品的读是广大的消费者,二者的访问量和对可靠性的要求完全一样。因此这样的拆分就属于质量维度的拆分。

9c59886d690562d9e0a25b8d64e976f3.png

      再比如,登录一般都隶属于会员服务的一部分,但假如登录对安全性的要求很高,也可以把登录功能从会员服务中摘出来,设置专门的安全防护策略。这样的拆分也属于质量维度的拆分。

3. 指导原则

      道理总是相通的,比如高内聚低耦合,就属于软件设计中少有的、有普适性的大道理。关于内聚性,我们在面向对象设计中有两个原则,一个是SRP(Single Responsibility Principle,单一职责)原则,另一个是CCP(Common Closure Principle,共同闭包)原则。这两个原则同样适用于微服务的拆分指导。

      共同闭包原则是说,包中包含的所有类应该是同类的变化的一个集合,也就是说,如果对包做出修改,需要调整的类应该都在这个包之内

      在微服务架构下采用CCP原则,我们就能把同样原因进行变化的服务放在一个组件内。这样,当需求发生变化时,变更和部署也更加容易。理想情况下,一个变更只会影响一个团队和一个服务。破坏CCP的场景,很容易就能发现。比如我们发现两个微服务之间,互相频繁调用,就是一个典型的不满足CCP的征兆。我在给招行做咨询的时候,就发现有一个征信系统对下游的客户中心系统有70个API的依赖,究其原因,就是客户中心并没有把客户服务封装的很好,导致两个系统要互相同步数据,等于是要在两个地方维护客户数据,任何关于客户信息的变更,都要牵扯到两个系统,这就属于破坏了CCP。

      除此之外,CCP也是解决分布式单体这种可怕的反模式的法宝。

d3e399db19621d85e38eb27e9b8d0e55.png

        所谓的分布式单体,就是无脑的把原来的单体,拆分成很多个互相耦合的、微小的“微服务”。这种不考虑业务内聚性,组织边界,质量属性要求的胡乱拆分,可以说是一个灾难。很多团队在胡乱拆分之后,又不得不花大力气进行合并。

        其实,抛开具体的业务不看,通过一个指标:人员微服务数量比,我们也很容易发现这个团队是不是陷入了分布式单体的陷阱。比如在一个团队内,如果一个人要维护10个微服务,光看这一个数字,就能确定它已经是分布式单体无疑了。

        说到这里,我想起来,我曾经指导过团队实现了一个还算比较成功的“巨服务”。事情是这样的,疫情期间社区团购一下子火起来了,我们也看到了这个机会,于是在团队内孵化了阿里的第一个社区团购项目。当时我们能投入的资源只有一个运营、一个产品经理和4个开发人员,是一个典型的“试错性”项目。因为后端开发都在我团队,所以我决定把社区团购所有的领域(会员、商品、团购、店铺、交易、微信小程序等)都放在一个服务里面。只是,在分包策略上,我要求顶层按照领域分开,这样如果业务发展的好,我们可以按照领域做服务拆分。不幸的是,业务最后是没有发展起来。幸运的是,因为是“巨服务”,我们整体投资也不算太大。

6802704195c74fbbe31e798742d9c085.png

4. 总结

在微服务架构中,微服务划分至关重要,是决定一个项目成败的关键。虽然没有一种完美的划分方式,因为分类天然就带有主观性在里面。但是这并妨碍我们从一些优秀实践中提炼出好的经验,以及从一些糟糕实践学会教训。

这个好的经验就是在做微服务划分的时候,就是要找准切分的维度。有三个维度需要我们去考量,最重要的维度就是业务维度,然后综合考虑组织边界和质量属性的述求。以及考虑业务发展阶段,综合权衡之后,选择一个合适的粒度,去满足业务诉求

衡量服务划分是否合理的关键是CCP原则,通过CCP检查我们的划分是否满足业务内聚性、组织内聚性、服务内聚性的要求,从而避免我们陷入分布式单体陷进

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值