Skip to main content

第12章 微服务的痛:用实际经历告诉你它有多少陷阱

第3部分主要讲解了基于常见组件的微服务场景,因为目前已经有了一些比较流行的开源组件,所以只需要清楚组件的原理即可。从这一章开始,将进入第4部分——微服务进阶场景实战。

在介绍业务场景之前,先来谈谈微服务的概念和优缺点。

单体式架构VS微服务架构

12.1 单体式架构 VS 微服务架构

为了快速理解单体式架构与微服务架构之间的区别,先来看一个新零售系统的例子。

某门店(门店分为自营店和加盟店)计划研发一款新零售系统进行商品售卖,它需要包含订单、营销、商品、门店、会员、加盟商等功能模块。

单体式架构

在搭建新零售系统架构时,如果使用单体式架构进行设计:

  • 所有模块的代码存放在一个应用
  • 所有模块的数据存放在一个数据库

在这种架构模式下,当业务功能增加到一定程度时,只要稍微有点小改动,就有可能影响整个应用的其他功能。虽然每次系统崩溃后都会进行复盘,后期需要 Code Review、合理设计、仔细评估风险、共同评审方案,但是问题还是会发生。

因此,随着风险控制流程的复杂化,代码发布的频率越来越低,最终导致系统无法迭代,而其他公司交付新功能的效率却是它的 10 倍以上。

微服务架构

面对这种情况,必须把各个模块的代码进行拆分,以免相互影响。于是把单体式架构拆分为微服务架构:

  • 一个应用被拆分成了 6 个应用
  • 分别负责订单、营销、商品、门店、会员、加盟商等相关的业务逻辑
  • 每个模块的数据分别存放在不同数据库
  • 各个应用之间如果彼此存在依赖关系,可以通过接口、消息、共享缓存、数据库同步等方式来解决

12.2 微服务的好处

将单体式架构迁移到微服务架构后,确实带来了诸多便利:

优势说明
易于扩展某个模块的服务器处理能力不足时,在该模块所处应用的服务器中增加节点即可
发布简单只需要保证对外契约不变即可,发布过程变得非常简单
技术异构各个服务之间相互独立、互不影响,内部可以使用各自不同的语言或框架
便于重构把模块间的影响进行了隔离,大大增加了重构的灵活性

12.3 微服务的痛点

在产品研发过程中,引入一种技术来解决一个业务问题并不难,难的是能否合理评估技术风险,这个观点对微服务同样适用。

微服务痛点

12.3.1 痛点:微服务职责划分

微服务的难点在于无法对一些特定职责进行清晰划分,比如某个特定职责应该归属于服务 A 还是服务 B?

划分原则

  1. 根据存放主要数据的服务所在进行划分

    • 根据商品 ID 找出商品信息的接口 → 放在商品服务中
    • 获取单个用户的所有订单 → 放在订单服务中
  2. 业务逻辑服务归属与业务人员的划分可能存在关系

    • 各个门店的商品库存由该门店的运营人员管理 → 放在门店系统中
  3. 业务逻辑服务归属与产品人员的划分可能存在关系

    • 由商品系统的产品经理负责 → 放在商品服务中
    • 由门店的产品经理负责 → 放在门店服务中
  4. 业务逻辑服务归属与工期可能存在关系

    • 再优雅的设计也抵不过业务部门要求的上线时间压力
  5. 业务逻辑服务归属还可能与组织架构存在关系(康威定律)

    设计系统的组织在设计系统时,会设计出基于这些组织的沟通结构的系统。

现实情况

在现实场景中,微服务职责的划分会受太多人为因素的影响,这也是为什么现在关于服务职责划分原则的相关资料不太多的原因。

12.3.2 痛点:微服务粒度拆分

微服务还有一个痛点,就是服务太多

实际案例

以加盟商系统为例:

  • 最初只有登录和信息管理功能 → 一个服务即可
  • 随着业务开展,需要增加财务功能、员工管理、返点、子门店管理等

问题:微服务的粒度到底拆分到多细比较合适?

影响粒度的因素

  1. 团队规模原则:根据新的微服务的大小,安排 3~4 人设计即可
  2. 绩效因素:开发人员在阐述个人工作量时偶尔会提微服务数,潜意识里喜欢做微服务
  3. 结果:微服务就会越来越多,甚至出现人均 5 个微服务数的情况
结论

微服务的粒度大小控制在什么范围比较合适?这就是一个痛点,因为没有确切的答案

12.3.3 痛点:没人知道系统整体架构的全貌

每隔几个月或半年,领导就会让汇报一下每个部门的微服务数量、公司微服务总数量、每个微服务都用来做什么等情况。

"几百个微服务?系统这么复杂了吗?谁知道所有系统的全貌?如果出现问题,你们如何快速定位问题?"

在使用微服务的公司后,很难找到了解微服务系统架构全貌的人员,只要熟悉自己负责的部分即可,如果出现问题就临时学习一下相关系统。

12.3.4 痛点:重复代码多

没有使用微服务的公司会把所有的代码放在同一个工程中,如果发现某些代码可以重复使用,把这些代码抽取出来存放在 Common 包中即可。

但是这种代码设计在微服务中经常会出现问题:

步骤问题
团队 A 做了一个日志自动埋点功能其他团队想拿来用
团队 B 使用后出现 JAR 版本冲突埋点团队需要重新设计兼容版本
团队 C 又汇报 JAR 版本冲突埋点团队放弃维护,直接告知其他团队自己复制修改
统一 JAR 版本项目立项因紧急业务需求搁置

结论:维护这些不多的重复代码总比统一排期做重构、统一评审 JAR 版本的成本低得多。

12.3.5 痛点:耗费更多服务器资源

某公司原来使用单体式架构,一共部署了 5 台服务器,后来拆分成了 6 个微服务:

架构服务器数量说明
单体式5 台原始架构
微服务15 台每个服务 2 节点 + 网关层 2 台

业务没有变,流量没有变,代码逻辑改动也不大,却多出了 9 台服务器。

服务器部署

12.3.6 痛点:分布式事务

分布式事务这个痛点对于微服务来说,简直就是地狱

实际案例:下单流程

原本的下单流程:

插入订单 → 修改库存 → 插入交易单 → 插入财务应收款单 → 返回结果

单体式架构:只需要把上面的下单流程包含在一个事务里就可以了。

微服务架构:因为这几个流程分别存放在不同的服务中,需要考虑:

  1. 某个流程出错是否需要将数据全部回滚?
  2. 是否选择统一不回滚,失败就重试?
  3. 如果做成异步,会不会出现时间超时?
现实做法

针对这种情况,在大部分场景下不考虑回滚和重试,只考虑写"Happy Path",如果报错就记录异常日志,再线下手工处理。

结果是:机房网络抖动时,数据更新总是出现异常,比如上游数据更新了,下游数据没有更新,出现了错误数据。

关于此问题的解决方案将在第13章第14章中进行说明。

12.3.7 痛点:服务之间的依赖

在设计类时,往往需要遵循类与类之间不可循环依赖的原则,因此最终设计出来的类关系是层次分明的结构。

但是微服务的现实情况

  • 商品系统依赖门店系统(门店类型设置价格)
  • 门店系统依赖商品系统(门店库存需要商品信息)
  • 财务系统需要依赖订单信息、会员信息和门店信息

最终,服务之间的依赖关系变成千丝万缕、难以理清的架构——"你中有我,我中有你"。

两次架构经历

  1. 重构评估影响面让各个团队鸡飞狗跳

    • 需要根据全链路日志系统找到所有上游服务
    • 评估后发现大半的微服务都会受到影响
    • 很多团队不得不一起通宵达旦地做回归测试
  2. 为了不影响其他团队,出现了很多版本

    • 新的代码直接调用 V2 版本,旧的代码继续调用 V1 版本
    • 服务数量出现暴涨,新旧版本并存
    • 维护起来更痛苦

这个问题的解决方案将在第15章进行讲解。

12.3.8 痛点:联调的痛苦

联调问题

以往的需求排期:

需求评审时间 → 开发完成时间 → 测试完成时间 → 上线时间

迁移到微服务后:

需求评审时间 → 接口设计时间 → 开发完成时间 → 联调完成时间 → 测试完成时间 → 上线时间

联调中的常见对话

调用方:"addXXX的接口怎么样了?"
被调用方:"好了,你可以调调看。"
调用方:"不行啊,返回了404。"
被调用方:"哎呀,环境部署错了,稍等一下。"
...
调用方:"addXXX的接口需要增加一个修改时间字段,你帮我加一下。"
被调用方:"可以,不过我正忙着另外一个项目,要不明天给你?"
调用方:"别啊,今天必须联调完。"
被调用方:"那我晚上赶一赶,9点给你行吗?"

在做项目时最麻烦的事情之一就是协调时间,因为它不可控。

关于这个痛点,将在第16章中给出解决方案。

12.3.9 痛点:部署上的难题

使用单体式架构时,每个开发人员都想在本地把整个系统部署完后再调试。

迁移到微服务后,项目经常涉及 10 个以上的微服务:

  • 内存很可能不够
  • 几乎没有开发人员会熟悉所有微服务的部署

解决方案:专门建立一套测试环境供开发人员进行联调。

测试环境的问题

问题说明
联调环境的数据缺漏非常多数据是开发数据,单个服务中的数据不具备完整性
服务调用错误经常有人调用了错误的服务节点
联调环境极度不稳定开发人员常常需要对联调中的服务进行部署

这就是第17章将要分享的内容。

12.4 小结

微服务痛点总结

微服务的9个痛点

痛点核心问题
职责划分受太多人为因素影响,没有确切标准
粒度拆分服务太多,粒度难以控制
架构全貌没人知道系统整体架构
重复代码JAR版本冲突,维护成本高
服务器资源微服务比单体式消耗更多服务器
分布式事务数据一致性问题是地狱级难度
服务依赖"你中有我,我中有你"
联调痛苦协调时间不可控
部署难题测试环境不稳定

为什么还要使用微服务?

微服务的优势讲了 5 点,而痛点讲了 9 点,为什么还要使用微服务?

如果使用单体式架构的话,随着业务的复杂化,将会出现无论怎么加人都无法迭代的情况。

而如果使用微服务,虽然它存在很多问题,但是至少可以通过增加人力的方式来保持迭代

原因就这么简单,跟那些痛点无关。

新技术的态度

程序员喜欢用新技术,但新技术层出不穷。对于新技术,要有敬畏心,除了知道它的优点,也要了解它的缺点。

微服务架构的痛点介绍完了,接下来开始讲一些进阶的微服务实战场景,看看如何解决本章提到的这些痛点。