故事的背景来源于,今天产品提了一个需求:对某个模块更新了一种文案,理论上来说,其实这是一个 k-v 结构,比方我有一个 getTexts 接口,回来如下:

[
    { title: '你好', desc: '国际' },
    { title: '作用不错', desc: '追加一条' } // 本次追加
]

那么直观感受是,咱们接入了这个接口,接下来定义完 render 的结构,不管服务端怎样变,是不是都能烘托出来。

这好像是理所当然的——产品也是这么认为的,这儿乃至不必提及体系架构中的分层,由于抽象就好像这么简略。

现在咱们的困难来了,假如有多个端需求做相同的事情呢——比方咱们就有 App、PC、H5、小程序,按照最简略的架构来看,好像会变成这样:

从接口设计看分层微服务架构

当然,作为一个工作的开发人员,咱们自然不至于做出课设等级的简略设计,至少你会知道,直连 DB 的应该只需一个服务,稍微改改这个设计:

从接口设计看分层微服务架构

当然,这一个微服务的底层或许还会有好几个微服务,问题就来了,我的体系到底是怎样拆分,才干终究做到独立、解耦,一起又能满意一次变更、多端收效呢。

咱们从图中的接口说起,也有人会把这一层称为 BFF,它的实质是面向视图服务的,也便是说让前端的逻辑尽或许的少,这样能够把前端做的愈加轻量,防止重逻辑的操作,这很好理解,从逻辑、解耦、提速和统一的视点,咱们都能找到这样拆分的理由。

可是他的下流是由一个个微服务组成的,而不是咱们图中所示的只需简略的一条线,实际体系中的链路往往杂乱许多,这又应该怎样拆分呢?

关于拆分,能够阅览下:微服务拆分之道,讲的挺明晰,简略总结一下,最下流的服务是根据范畴模型进行拆分的,比方「用户服务」、「信息服务」、「付出服务」、「订单服务」等等。一起,咱们也会根据服务重要性、QPS 等视点考虑去进行更细粒度的切开,并且在保护成本、运维成本中获得一个终究的平衡点。

但假如光按照范畴模型切开完服务,才是一个服务的开端,更重要的是,我这个服务应该去做哪些事情?

拿一个获取用户订单来说,那么首先我必定需求拿到用户,并且鉴权通往后,我才干履行后续的逻辑,吐给上游服务订单,既然如此,我是不是应该调用用户服务去进行鉴权呢?——从单一职责的视点上来看,其实不必,理论上,应该是上游鉴权并且告知你 userId,然后直接去拉指定 userId 的信息,不然一个「订单服务」的一切接口极有或许都是需求鉴权的,在一个上游服务调用多个微服务的时候,就会形成「用户服务」的严重读放大,一起无缘无故的增加了链路成本。

不管是代码仍是服务,咱们都应该奉行高内聚低耦合的原则进行。可是假如这样,或许会导致服务之间的关联性变弱,过于散装,所以咱们会在最底层的查询类服务上游再去进行一些聚合,行程上游服务,这也便是为什么微服务架构的链路存在必定杂乱性,而不是上图中的简略三层结构。

接下来回到原本的话题,现在产品能够实现他提一个需求改动一切端的主意了吗:好像是能够的,究竟只需微服务变更,接口侧只是对微服务进行的一些组装裁剪,上面那个 case 实质只是数据多了一条,没什么实质的改变。

可是新的问题来了,尽管这个特性终究或许是多端收效的,可是过程中产品或许要对某一段进行一些试验,比方 App 去做一些 AB 来验证主意。

这儿咱们的关键词有两个,一个是 App,一个是 AB;当咱们提到平台时,咱们会更倾向于在客户端或者接口层去进行试验桶的分配,然后在对不同的状况进行数据处理。而假如是平台无关,则能够考虑将试验逻辑进一步下沉到下流服务中,这样才更能保证多端一致。

结合需求来看,咱们常见的需求有两种:

  1. 新增 feature,需求前端调整 UI 的一起后端新增数据字段
  2. 战略调整,前端不变,可是后端数据会变得不一样的场景

关于场景 1,毫无疑问,应该新增个字段,来削减对现有服务的干扰,但也有一些状况是,原本 enum 是两个值,现在有了三种值该怎样办,这种状况上游服务从一开端就应该做好防御战略,防止数据变更导致的兼容性问题。

关于场景 2,假如产品预期多端一致,是完全能够进行多端一致处理的,做到在接口层不变更的状况下,微服务下发数据修正,App 试验期间,假如用户射中试验桶,能够将试验标传给下流服务,下流服务回来试验版别,但在完毕试验后,需求将代码的缺省版别更新,让它在一切端都收效。

可是关于服务端来说,或许有的顾忌是:假如各端由于数据变更出了异常,我是不是要背锅,所以始终不敢更新缺省版别,而让各端传入之前支撑的试验标——其实开发并不是一项自闭工程,仍是需求一些和谐沟通的,不必假定。

假如 App 端只需某些版别才支撑,其实应该在接口层根据版别进行兼容性处理,而不是一路无脑透传,接口层其实是一个脏活累活,也并不是无脑透传这么愉快的。

其实关于链路的每一层,都秉持 less is more 的理念,假如长时间把持着试验标,关于下流服务的可保护性也形成了必定应战,比方这次在接入一个接口的时候,我需求传十几个 options 才干保持和 App 一致,但有些并不是 App 正在进行的试验,而是现已完毕后保存的选项,尽管终究接口的提供方也没能给我解说每一个选项,可是简略看姓名,有的接口是决定了:是否出现某一个字段,这种裁剪才能应该由上游去做才对,也便是说,或许咱们的微服务拆分便是有问题的(乃至还见到了底层微服务下发十六进制色值、下发裁剪后图片而不是原图的状况)。

咱们再回去看看产品自身的诉求:多端一致。其实是不是只需把接口出入参简略化,逻辑清真化,多多沟通,就能处理的问题呢?

关于业务来说,自身没有银弹,只需结合业务后的合理的设计,可是根本依旧是,咱们不只要实现需求,还得想想怎样能更好的实现需求,能够走在产品前面,设计出一个可扩展、易使用的服务。

当然,本文原本觉得没啥好讲的,也很低端,没想到这两周接接口接的痛不欲生,一起也总算发现了为什么咱们的多端永远对不齐的其间一个问题点,所以有了这篇文章。