故事背景

从前,有这么一个团队,他们按照不同的业务类型把人员划分了 3 个小队,一个是专注 To C 零售相关业务的,一个专注与 To B 对公业务的,还有一个是专门开发管理一些内部使用的系统的。

恰好,他们 3 个团队使用的架构和技术栈非常类似,比如 Spring Boot 全家桶中的常客Eureka、Spring Cloud Gateway 等,每边的业务又都需要一系列的用户鉴权验证操作。有一天,老板来一看就拍桌子了,“你看这 Eureka、这 gateway(网关)、这鉴权服务!这么类似的东西你们怎么搞了三套!明显浪费资源啊!!微服务不就是要方便重用资源嘛,那谁(架构师)快来收拾收拾看怎么合并一下吧”。

于是,苦 B 的架构师开始埋头梳理架构......

几天后我碰见这位架构师朋友,他立马就开始向我吐糟:“你说前端吧,业务不同,大家分开做没毛病,顶多看看有什么共用模块可以抽取一下做个控件库啥的。说后端吧,反正也在准备建中台了,之后按着业务流程,用领域分析的方式走一下总还是能把这些梳理出来的。老板这么忽然而来去关注服务注册啊、服务网关啊这些基础的设施,你说合起来嘛好像也可以,但是我怎么心里总觉得有点不太确定。”

业务价值导向架构决策

前不久,老马(Martin Fowler)正好写了这么一篇文章(中文翻译供参考),里面提到一种从业务价值出发的决策方式,我在这里且把它概括为“业务导向一中心,得失衡量两基本”,简称【一个中心,两个基本点】。

在做架构决策的时候,可用性 / 扩展性 / 延时等特性总是互相制衡的。我们需要有【一个中心】,也就是要选择出最最重要的点,或者说有个优先级排序。而选出这个中心的出发点,是聚焦业务价值(而非技术价值)。正如 Martin 文中提到的例子,我们会期望一个交易系统有 5 个 9 的高可用,但如果我们要求一个公司内部的 OA 系统做到 5 个 9,就有点过分了。这个区别就在于不同系统提供的业务价值是大不同的。

在决定了一个中心之后,可以进一步问自己两个问题,也就是【两个基本点】。

  • 得: 如果这个决策 / 组件顺利工作,那它能贡献多大的业务价值?
  • 失: 万一这个决策 / 组件出了问题,它对业务的影响有多大呢?

在项目立项或者申报的时候,大家往往都喜欢考虑“得”,这事要成了就怎么怎么的。但若单纯是这个思路,那很多的技术改进或者优化就排不上了。像是定期的灾备演练,你说不重要那不可能,尤其是银行之类的系统,但你说算不算优先级很高呢?它总是很容易会被一些看似更重要的业务功能的优先级所超越,而导致一拖再拖。直到某天台风真的来了,主机房被淹了,这才发现停服几天损失居然如此之大。可见,只有正反都想透了才能保证思虑更周全。

那我们就尝试用这套方法,聚焦到这次的问题上来分析一下。为了更好地发散,我们可以先从两个基本点开始,然后再来收敛一个中心。究竟,这 3 个团队可以 / 应该共用一个 API 网关吗?

两个基本点

先来看看“得”(初心 / 好处)

  • 增加业务重用:如果共用一个 API 网关,3 个团队共用的业务功能 API 是不是可以更容易地得到复用?如果服务能更好地复用,那是不是意味着我们可以更快地提供业务所需的功能? 如果是更快的话,那这里还可以尝试进一步展开,比如说我们现在已有 / 预计有多少这样共用 API ?
  • 减少代码冗余:如果共用一个 API 网关,那至少能减少类似的功能重复开发和冗余。那再展开的话,如果共用了不需要再开发网关了,这里能省多少时间?
  • 减少硬件资源投入:资源部署还是需要硬件支撑的,这里的网关通常用的是集群(cluster),例如 3 个组件同时启动。如果共用一组网关,也少部署了另外两组网关(6个)服务,那硬件上能省多少?
  • 降低运维成本:除了让组件运行起来,还得有人对应的去监控管理运维。每少一个组件都应该减轻了一定的运维成本,也让架构简单一些。

上面都是一些拍脑袋出来的点,实际分析的时候如果能有业务数据支撑就更好了。

再来看看“失”(挑战 / 风险)

  • 网关出问题的业务影响:因为通常是集群,如果只是其中一个网关有问题,那应该只要及时解决一下应该没什么影响。万一全部都挂了,那本是影响对应的业务线无法访问,合并后就有可能导致 3 个业务线都无法访问。这里还可以再展开一下,
    • 这里的风险影响级别?(明显业务影响是高的)
    • 对应的出问题机率又是多少呢?(可以类比洪水机率描述,比如一年一遇 / 三年一遇 / 多少年来暂时未发生过?)
    • 万一它真出现问题了,我们有没有办法及时预警发现然后马上修复?(比如能马上重启解决?有充分的灾备演练和文档说明?还是说只能听天由命到时研究?)
    • 执行解决方案后,估计服务暂停时间(downtime)大概会是多少?(如 3 - 5 分钟内?30 - 60 分钟?半天?)这段服务暂停时间对业务的影响是什么?
  • 网关出问题的责任归属问题:即出问题之后由哪个团队负责修复。这个就和康威定律相关了。以前就自己组管自己的组件分得很清晰,那如果之后三个组都用同一个网关,出事之后,
    • 谁主力去负责修复呢?怎么分工?
    • 这个人是否有足够的知识去了解和分析事故的影响范围及有能力去修复?至少有能力找到对应的专家修复?
  • 开发和发布等进度的协作问题:大家知道在网关里面最简单还是需要配置一下后台服务的对应关系(mapping),有时候还会新增和修改一下的。那合并之后也就是 3 个团队都需要对这个代码库有控制权,而且会分别按自己的进度修改和发布。这时候,要求:
    • 3 个团队统一代码库
    • 然后还得大家协商好协作方式(如分支策略、发布策略等)
    • 再展开一下的话,就得再看看 3 个团队对于网关的改动 / 部署的频率分别是怎样的?冲突的机率多不多?
  • 各团队对网关的安全性 / 可用性 / 延时等要求不同:理想中的网关是单纯的转发,但实际的网关很多团队会慢慢混入更多的功能,比如:
    • 加上 traceId 做全链路追踪?
    • 在网关中截获 HTTP header 做校验?
    • 甚至在网关中就需要连接 Redis 进行认证鉴权?

当一个组件目的不那么单纯的时候,出现问题的机率自然也会上升。例如可能那个 ToC 团队因为被撸羊毛撸怕了,所以需要很高的安全性,但对于内部系统的团队来说,这部分的安全就有点过了,增加的复杂度反而让运维压力更大。

如果这种不一致性比较大,那我们在抽取公共服务共用的时候,有没有办法把共用部分变得更单纯简单?(有可能某些团队就需要作架构调整,如把额外的功能移到另一个非共用组件上。)

8MFhQTO1LpACiaVr

一个中心

分析到这里,可能你又会有一种感觉——似乎每一点能列出来的都有道理,但是我依然做不了决定,这就是因为还欠缺了【一个中心】帮助我们做收敛和取舍。

我们可以先假设一个背景:这是在一个超级大公司里面

在这里钱和人都不是大问题,但服务的安全可靠是最重要的。

这时候再去回顾就会发现有些点会忽然变得无关紧要。比如对于硬件资源投入的节省,那简直就是九牛一毛无足轻重,即使是代码冗余和运维成本上,影响也不那么大。反过来说,大公司可能对安全性和可用性都更加关注,即使是偶发的短时间的服务不可用也足以让公司股价波动。大公司的条条框框也让多个团队共用一个代码库去协同更加困难。那如果这么思考,看起来如果合并的话风险就太高了,而且收益也并不显著。

另外一个可能的策略是不原样共用,而是先尽量把一些纯粹的功能抽取出来作为共用服务,而把一些团队特有的特性考虑迁移到另外一些服务里面。但这个就涉及到搬哪些内容、搬到哪里和怎么搬的问题。如果抛开具体情况,这个也说不清,暂且先不细说。

回过头来再假设另外一个背景:这是在一个互联网初创小团队

融资的钱烧得太快了,活下去的关键就是快速迭代出新功能验证市场需求。

那这时候,架构的简洁和部署资源的各种节省都是很有必要的。服务的尽量重用和灵活也会对进度有明显帮助。相反,因为初期用户还不多,公司影响力也不算那么大,偶然如果只是 3 - 5 分钟的服务受影响,其实造成的影响还是可控的。在这种情况下,可能我们从一开始就会选择共用一个网关,准备好救火的文档,准备好救火队员的轮值表,尽量把风险控制在一个非常短的时间内。

总结

架构设计最好玩也是最让人纠结的地方就在于各种抉择。

虽说现在有很多技术手段让我们的架构演进更加轻量和灵活,让大家不用再承受那么孤注一掷的压力,但一个深思熟虑的抉择还是可以让团队少走弯路的。

一个中心,两个基本点】,看似一个网关的故事,其实可以用于架构调整和重构决策的方方面面,希望可以给各位在抉择路上提供多一套思路,远离选择困难的苦海,阿弥陀佛 ^_^