Contents

[架构]单体和微服务

多大的服务

“宜小不宜微”,不宜过大的单体,也不宜滥用微服务,应保持在合适的大小。
(ps. 这里只讨论服务的大小。不讨论服务的手段,拆分解耦、服务发现、mesh、告警、限流、全链路建设,都是好的实践,任何服务都可以做的同样好)
什么样的服务大小属于合理的服务?核心有两点,合理划分服务边界,匹配组织结构。

  • 团队视角:服务的规模应该尽量限制在最小团队,约3人左右的团队为宜
    • ❎ 过大!跨团队修改同一服务,风险大且不利于基础建设。没有人对整体的架构和质量负责。没有人有全局视角,写代码因为不了解改动范围容易出故障。
    • ❎ 过大!10人以上的团队不宜修改同一服务。很可能服务定位不清晰,10个人的信息交流会有很多gap,效率会大大降低
    • ❎ 过小!团队每个人管三四个服务,说明服务数量过多,无用工作会增加,效率也会降低
  • 业务视角:保证产品需求变更如果只在本团队内,修改的服务1-2个即可
    • ❎ 过小!改一个小小的功能,牵扯4-5个服务。服务太小了,效率降低
    • ❎ 过大!同时有四五个业务需求,对应数十个研发同时修改一个服务,而这些功能看起来并不密切。这说明服务包揽的功能太多了,已经膨胀的太大了

更微=更好?

我们以一个模块划分合理、大小合适的单体服务为例,看看如果拆分的更微小,对比起来会有哪些点值得关注:

关注点 合理的单体 更微服务
性能 无劣化 约数ms的劣化
复用性 可以仓库内直接引用 不可复用其他仓库代码;所以也不会复用到bug
可读性 容易找代码 需要跨的仓库多,层次深,理解困难
研发成本 编译可能较慢 写代码、编译、调试、发布、部署都需要多仓库并行,成本高
部署成本 单机器 高,需要多台机器
代码合入 公共部分容易冲突 不容易冲突

微服务教

我们看下某网站对单体的批评,一一回应下:

  • 开发效率低:所有的开发在一个项目改代码,递交代码相互等待,代码冲突不断
    • 确实,代码冲突会变多。但在单体内部模块划分合理的情况下,冲突的只会是公共模块;如果这些代码冲突了,使用微服务也会冲突。
  • 代码维护难:代码功能耦合在一起,新人不知道何从下手
    • 耦合是模块设计的问题,不是单体的问题。而且单体断层更少,更容易阅读
  • 部署不灵活:构建时间长,任何小修改必须重新构建整个项目,这个过程往往很长
    • 没发现编译时间有显著区别。部分单体仓库会编译多个产物,建议针对性编译,效果更好。
  • 稳定性不高:一个微不足道的小问题,可以导致整个应用挂掉
    • 绝对意义上,微服务存在同样的问题,而且更难定位。相对意义上,如果说单体的复用代码带来了问题风险的扩大,这属于因噎废食,不可取。
      微服务给我们带来了什么样的反思?拒绝盲目创新,提防吹牛皮但不切实际,小心滥用导致过犹不及。

再次回到起点:monorepo

有趣的是,越来越多人意识到了微服务的问题,最终又回归了单一的仓库,并发明了一新的词:monorepo。

Segment.com 提供活动收集和转发服务,每个客户都需要使用一种特殊格式的数据。因此,工程团队最初决定混合使用微服务和多代码库。这一策略效果很好——随着客户基数的增长,他们扩大了规模,没有出现问题。但是,当转发目的地的数量超过 100 个时,事情开始变得糟糕起来。维护、测试和部署超过 140 个代码库(每个代码库都有数百个日益分化的依赖关系)的管理负担太高了。最终,团队发现他们无法取得进展,三个全职工程师花费了大部分时间来维持系统的运行。
对于 Segment 来说,补救办法就是合并,将所有的服务和依赖迁移到一个单一代码库中。他们必须协调共享库并且测试所有内容,虽然花了很大的代价,但迁移非常成功,最终的结果是降低了复杂性,增加了可维护性。

每个团队的精力是有限的,当每个人管理的仓库>10个,团队管理的仓库>100个,会出现非常多的问题:

  • 团队无法集中注意力管理。有很多的仓库大部分人并不知晓。这部分代码不再能被复用,也不再被了解
  • 开发要打开很多IDE并发进行,容易出错。测试需要部署非常多的服务,也不能跨服务debug。发布时需要发布过多的仓库,发布容易遗漏;发布有很复杂的依赖,发布也会花费更久的时间。
  • 无法发起整体性重构。重构一个服务和同时重构10个服务的难度不是一个级别。