5

面试基操:微服务拆分需要考虑什么因素?

 2 years ago
source link: https://developer.51cto.com/article/703499.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
面试基操:微服务拆分需要考虑什么因素?-51CTO.COM
面试基操:微服务拆分需要考虑什么因素?
作者:Tlog4J 2022-03-09 08:22:43
在实际互联网项目开发中,分布式事务不宜设计得太重,通常来说异步的场景使用事务性MQ来解决,

f6eb22542c42adc528f921f55df8c4f9f35fd7.png

面试官:微服务如何拆分?需要考虑什么因素?

候选人:一般按照功能拆分

面试官:还有吗?

候选人:唔……

要拆分微服务,首先我们要了解微服务拆了会有什么问题?怎么合理拆服务?

拆分服务会带来什么问题?

举个电商系统下单扣库存的例子。

对于单体应用,通讯在进程内部进行,下单方法调用扣库存方法,有问题就回滚事务,利用数据库同一个Session会话的ACID特性干活,保证数据的强一致性,即使在调用下单方法成功后应用崩溃,数据也不会提交到数据库,不会产生脏数据。

而拆分成各个微服务后,代码、数据库进行了隔离,下单扣库存逻辑变成了订单服务通过RPC调用库存服务,由于不受同一个数据库Session会话控制,就必然会存在因业务处理失败、应用崩溃、网络通讯异常等一系列问题导致的数据不一致。

这是一个典型的复杂度转移的例子——单体应用的代码复杂度转移到了微服务之间的通讯复杂度,整体的复杂度并没有降低。

回到经典的分布式CAP定理:数据一致性、可用性、分区容错性,三者取其二。

36c8d6e577b39d4103e2077f90604ad660403c.png

CAP是分布式系统中三个维度的“客户承诺”:

  • 一致性:要么我给你返回一个错误,要么我给你返回绝对一致的最新数据,强调数据正确。
  • 可用性:我一定会给你返回数据,不会给你返回错误,但不保证数据最新,强调的是服务不出错。
  • 分区容错性:我会一直运行,不管我的内部出现何种数据同步问题,强调的是不挂掉。

为了解决数据一致性问题,业界又引入了各种一致性保障机制,比如BASE理论(基本可用、软状态、最终一致)、分布式事务DTP模型(XA协议、TCC协议)、JTA模型等等,根据对数据一致性的要求又划分为强一致性、弱一致性、最终一致性的方案,在分布式系统中通过一系列措施来保证ACID。

在实际互联网项目开发中,分布式事务不宜设计得太重,通常来说异步的场景使用事务性MQ来解决,比如RabbitMQ、Kafka、RocketMQ等;同步的场景使用业务状态机来规避它们,比如订单分正向销售单、逆向售后单,单据有不同维度的状态,比如支付状态、退款状态、物流状态、开票状态等等,对于出错的环节进行客户干预、系统告警或客服干预,暂时停留在异常节点,这里的“状态”可以理解为BASE理论中的软状态。

说到底还是用BASE理论指导生产。

6205d125556a513dc10803726e9052bdef6ace.png

说那么多,我们通过拆分微服务,提高了系统的分区容错性与可用性,却牺牲了单体应用的一致性优势,所以说,不要为了拆而拆,拆服务也需要合理“动机”,那什么样的“动机”是合理的呢?

如何合理拆分微服务?

OK,了解了服务拆分带来的问题后,我们拆服务就得更加严谨了,那怎么合理拆呢?

这里提供一些思路。

一、按单一职责拆

还是以我们的电商平台举例,一开始我们最核心的OMS订单系统做了特别多事情,包括:用户、下单、商品、库存、出入库、营销……

随着公司业务快速增长,OMS代码激增,新增/修改一个功能就要影响几乎整个链路,稳定性降低,也大大增加了风险,运维变得十分困难,这时不得不把各个模块剥离出来,独立成为UC用户服务、PMS商品服务、CIS中央库存服务、WMS出入库服务、MCS营销中心等等。

我们按照单一职责的划分原则,每一个独立的服务只提供该业务领域的核心功能,继而每个独立的服务演化出更为丰富的功能,数据库也进行垂直拆分提供应用独立访问,并且每个服务提供双节点保证高可用。

二、按团队组织架构拆

这里必须提一提软件架构设计中的第一定律——康威定律。

康威定律是马尔文·康威1967年提出的:“设计系统的架构受制于产生这些设计的组织的沟通结构。”通俗地来讲:产品必然是其(人员)组织沟通结构的缩影。

康威定律可总结为以下四个定律:

第一定律:组织沟通方式会通过系统设计表达出来。

这条定律重点是讲组织架构和沟通对系统设计的影响。

组织的沟通和系统的设计之间紧密相连,特别是复杂系统,解决好人与人的沟通才能有一个更好的系统设计。

沟通的问题会带来系统设计的问题,进而影响整个系统的开发效率和最终产品结果,这也是为什么互联网公司都追求小团队的原因之一。

第二定律:时间再多一件事情也不可能做得完美,但总有时间做完一件事情。

人手永远是不够的,事情永远是做不完的,但可以一件一件来。

这不就是软件行业中“敏捷开发”模式所解决的问题吗,面对这样的状况,敏捷开发可以做到不断迭代、持续交付、快速验证和反馈,并持续改进。

再牛的开发也会写出BUG,再全面的测试覆盖率也无法测出所有的问题,解决方案不是消灭这些问题,是容忍一些问题的存在,然后通过适当的设计(冗余、监控、高可用设计),当问题发生时能够快速解决。

几个开发人员的小公司,去追求微服务、中台架构、这是追求完美吗?

不是,这是找死。

好的架构不是买来的,也不是设计出来的,而是根据业务落地生根长期演化来的。

第三定律:线型系统和线型组织架构间有潜在的异质同态特性。

这一定律是第一定律的具体应用。

想象一下如果公司的架构是这样的:

团队是分布式,每个团队都包含产品、研发、测试、运维等角色,而此时系统是单体应用,那项目沟通和协调的成本是巨大的,弄不好还会打起来。

728293350d524bfb8840590eabede721efd75f.png

如果将单块的系统拆分成微服务,每个团队负责自己的部分,对外提供对应的接口即可,互不干扰,系统效率将得到提升,这与软件设计中的高内聚、低耦合是相通的。

9629ea351237191a2cb552d3c487470816d0bb.png

直白地说就是想要什么样的系统就搭建什么样的团队,有什么样的团队就搭建什么样的系统,需要前后端分离的系统就搭建前后端分离的团队;反之,拥有前后端分离的团队就可以设计前后端分离的系统。

第四定律:大的系统组织总是比小系统更倾向于分解。

“话说天下大势,分久必合,合久必分。”系统越复杂,越需要增加人手,人手越多,沟通成本也呈指数增长,分而治之便是大多数公司选择的解决方案,分不同的层级,分不同的小团队,让团队内部完成自治理,然后统一对外沟通。

我们试着从康威定律来推导系统的架构演进方向,自然知道微服务的拆解粒度了。

SOA 也好、微服务也好,解决的根本问题是团队分工问题,这是大型软件发展的必然,不因为人的喜好而改变,当你读懂康威定律,就会发现“服务拆分粒度难以准确把握”根本不是本质问题,你有几个 2 pizza 团队,最好就拆成几个微服务。

只有一个开发人员时,尽量就做单体应用,不要没事找刺激拆成 10 个微服务,最终这个开发人员还会把他合成一个。

微服务要求纵向的 2 pizza 团队(无数个小团队,包含开发、测试、运维),如果团队还是处在横向结构的场景下(开发、运维、测试各是一个团队),比如说一些传统大型企业,去实施微服务会让他们很痛苦,尤其是运维团队。

1995b83145c80f6084b3474d3f8fd7ba6719c9.jpg

具体实践建议:

我们要用一切手段提升沟通效率,比如slack,github,wiki。能2个人讲清楚的事情,就不要拉更多人,每个人每个系统都有明确的分工,出了问题知道马上找谁,避免踢皮球。

通过MVP的方式来设计系统,通过不断的迭代来验证优化,系统应该是弹性设计的。

你想要什么样的系统设计,就架构什么样的团队,能扁平化就扁平化。最好按业务来划分团队,这样能让团队自然的自治内聚,明确的业务边界会减少和外部的沟通成本,每个小团队都对自己的模块的整个生命周期负责,没有边界不清,没有无效的扯皮,inter-operate, not integrate。

做小而美的团队,人多会带来沟通的成本,让效率下降。亚马逊的Bezos有个逗趣的比喻,如果2个披萨不够一个团队吃的,那么这个团队就太大了。事实上一般一个互联网公司小产品的团队差不多就是7,8人左右。

总之,只要说得清楚,运维能力又能跟上,服务拆分一般就是合理的!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK